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