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