eh_alloc.cc revision 132720
197403Sobrien// -*- C++ -*- Allocate exception objects.
2132720Skan// Copyright (C) 2001, 2004 Free Software Foundation, Inc.
397403Sobrien//
4132720Skan// This file is part of GCC.
597403Sobrien//
6132720Skan// GCC is free software; you can redistribute it and/or modify
797403Sobrien// it under the terms of the GNU General Public License as published by
897403Sobrien// the Free Software Foundation; either version 2, or (at your option)
997403Sobrien// any later version.
1097403Sobrien//
11132720Skan// GCC is distributed in the hope that it will be useful,
1297403Sobrien// but WITHOUT ANY WARRANTY; without even the implied warranty of
1397403Sobrien// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1497403Sobrien// GNU General Public License for more details.
1597403Sobrien//
1697403Sobrien// You should have received a copy of the GNU General Public License
17132720Skan// along with GCC; see the file COPYING.  If not, write to
1897403Sobrien// the Free Software Foundation, 59 Temple Place - Suite 330,
1997403Sobrien// Boston, MA 02111-1307, USA.
2097403Sobrien
2197403Sobrien// As a special exception, you may use this file as part of a free software
2297403Sobrien// library without restriction.  Specifically, if other files instantiate
2397403Sobrien// templates or use macros or inline functions from this file, or you compile
2497403Sobrien// this file and link it with other files to produce an executable, this
2597403Sobrien// file does not by itself cause the resulting executable to be covered by
2697403Sobrien// the GNU General Public License.  This exception does not however
2797403Sobrien// invalidate any other reasons why the executable file might be covered by
2897403Sobrien// the GNU General Public License.
2997403Sobrien
3097403Sobrien// This is derived from the C++ ABI for IA-64.  Where we diverge
3197403Sobrien// for cross-architecture compatibility are noted with "@@@".
3297403Sobrien
3397403Sobrien#include <cstdlib>
3497403Sobrien#include <cstring>
3597403Sobrien#include <climits>
36102782Skan#include <exception>
3797403Sobrien#include "unwind-cxx.h"
3897403Sobrien#include "bits/c++config.h"
3997403Sobrien#include "bits/gthr.h"
4097403Sobrien
4197403Sobrienusing namespace __cxxabiv1;
4297403Sobrien
4397403Sobrien
4497403Sobrien// ??? How to control these parameters.
4597403Sobrien
4697403Sobrien// Guess from the size of basic types how large a buffer is reasonable.
4797403Sobrien// Note that the basic c++ exception header has 13 pointers and 2 ints,
4897403Sobrien// so on a system with PSImode pointers we're talking about 56 bytes
4997403Sobrien// just for overhead.
5097403Sobrien
5197403Sobrien#if INT_MAX == 32767
5297403Sobrien# define EMERGENCY_OBJ_SIZE	128
5397403Sobrien# define EMERGENCY_OBJ_COUNT	16
5497403Sobrien#elif LONG_MAX == 2147483647
5597403Sobrien# define EMERGENCY_OBJ_SIZE	512
5697403Sobrien# define EMERGENCY_OBJ_COUNT	32
5797403Sobrien#else
5897403Sobrien# define EMERGENCY_OBJ_SIZE	1024
5997403Sobrien# define EMERGENCY_OBJ_COUNT	64
6097403Sobrien#endif
6197403Sobrien
6297403Sobrien#ifndef __GTHREADS
6397403Sobrien# undef EMERGENCY_OBJ_COUNT
6497403Sobrien# define EMERGENCY_OBJ_COUNT	4
6597403Sobrien#endif
6697403Sobrien
6797403Sobrien#if INT_MAX == 32767 || EMERGENCY_OBJ_COUNT <= 32
6897403Sobrientypedef unsigned int bitmask_type;
6997403Sobrien#else
7097403Sobrientypedef unsigned long bitmask_type;
7197403Sobrien#endif
7297403Sobrien
7397403Sobrien
7497403Sobrientypedef char one_buffer[EMERGENCY_OBJ_SIZE] __attribute__((aligned));
7597403Sobrienstatic one_buffer emergency_buffer[EMERGENCY_OBJ_COUNT];
7697403Sobrienstatic bitmask_type emergency_used;
7797403Sobrien
7897403Sobrien
7997403Sobrien#ifdef __GTHREADS
8097403Sobrien#ifdef __GTHREAD_MUTEX_INIT
8197403Sobrienstatic __gthread_mutex_t emergency_mutex =__GTHREAD_MUTEX_INIT;
8297403Sobrien#else
8397403Sobrienstatic __gthread_mutex_t emergency_mutex;
8497403Sobrien#endif
8597403Sobrien
8697403Sobrien#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
8797403Sobrienstatic void
8897403Sobrienemergency_mutex_init ()
8997403Sobrien{
9097403Sobrien  __GTHREAD_MUTEX_INIT_FUNCTION (&emergency_mutex);
9197403Sobrien}
9297403Sobrien#endif
9397403Sobrien#endif
9497403Sobrien
9597403Sobrien
9697403Sobrienextern "C" void *
97132720Skan__cxa_allocate_exception(std::size_t thrown_size) throw()
9897403Sobrien{
9997403Sobrien  void *ret;
10097403Sobrien
10197403Sobrien  thrown_size += sizeof (__cxa_exception);
10297403Sobrien  ret = std::malloc (thrown_size);
10397403Sobrien
10497403Sobrien  if (! ret)
10597403Sobrien    {
10697403Sobrien#ifdef __GTHREADS
10797403Sobrien#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
10897403Sobrien      static __gthread_once_t once = __GTHREAD_ONCE_INIT;
10997403Sobrien      __gthread_once (&once, emergency_mutex_init);
11097403Sobrien#endif
11197403Sobrien      __gthread_mutex_lock (&emergency_mutex);
11297403Sobrien#endif
11397403Sobrien
11497403Sobrien      bitmask_type used = emergency_used;
11597403Sobrien      unsigned int which = 0;
11697403Sobrien
11797403Sobrien      if (thrown_size > EMERGENCY_OBJ_SIZE)
11897403Sobrien	goto failed;
11997403Sobrien      while (used & 1)
12097403Sobrien	{
12197403Sobrien	  used >>= 1;
12297403Sobrien	  if (++which >= EMERGENCY_OBJ_COUNT)
12397403Sobrien	    goto failed;
12497403Sobrien	}
12597403Sobrien
12697403Sobrien      emergency_used |= (bitmask_type)1 << which;
12797403Sobrien      ret = &emergency_buffer[which][0];
12897403Sobrien
12997403Sobrien    failed:;
13097403Sobrien#ifdef __GTHREADS
13197403Sobrien      __gthread_mutex_unlock (&emergency_mutex);
13297403Sobrien#endif
13397403Sobrien      if (!ret)
13497403Sobrien	std::terminate ();
13597403Sobrien    }
13697403Sobrien
13797403Sobrien  std::memset (ret, 0, sizeof (__cxa_exception));
13897403Sobrien
13997403Sobrien  return (void *)((char *)ret + sizeof (__cxa_exception));
14097403Sobrien}
14197403Sobrien
14297403Sobrien
14397403Sobrienextern "C" void
144132720Skan__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    {
15097403Sobrien      unsigned int which
15197403Sobrien	= (unsigned)(ptr - &emergency_buffer[0][0]) / EMERGENCY_OBJ_SIZE;
15297403Sobrien
15397403Sobrien#ifdef __GTHREADS
15497403Sobrien      __gthread_mutex_lock (&emergency_mutex);
15597403Sobrien      emergency_used &= ~((bitmask_type)1 << which);
15697403Sobrien      __gthread_mutex_unlock (&emergency_mutex);
15797403Sobrien#else
15897403Sobrien      emergency_used &= ~((bitmask_type)1 << which);
15997403Sobrien#endif
16097403Sobrien    }
16197403Sobrien  else
16297403Sobrien    std::free (ptr - sizeof (__cxa_exception));
16397403Sobrien}
164