eh_alloc.cc revision 259694
1// -*- C++ -*- Allocate exception objects.
2// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
3// Free Software Foundation, Inc.
4//
5// This file is part of GCC.
6//
7// GCC is free software; you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 2, or (at your option)
10// any later version.
11//
12// GCC is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with GCC; see the file COPYING.  If not, write to
19// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
20// Boston, MA 02110-1301, USA.
21
22// As a special exception, you may use this file as part of a free software
23// library without restriction.  Specifically, if other files instantiate
24// templates or use macros or inline functions from this file, or you compile
25// this file and link it with other files to produce an executable, this
26// file does not by itself cause the resulting executable to be covered by
27// the GNU General Public License.  This exception does not however
28// invalidate any other reasons why the executable file might be covered by
29// the GNU General Public License.
30
31// This is derived from the C++ ABI for IA-64.  Where we diverge
32// for cross-architecture compatibility are noted with "@@@".
33
34#include <bits/c++config.h>
35#include <cstdlib>
36#if _GLIBCXX_HOSTED
37#include <cstring>
38#endif
39#include <climits>
40#include <exception>
41#include "unwind-cxx.h"
42#include <ext/concurrence.h>
43
44#if _GLIBCXX_HOSTED
45using std::free;
46using std::malloc;
47using std::memset;
48#else
49// In a freestanding environment, these functions may not be available
50// -- but for now, we assume that they are.
51extern "C" void *malloc (std::size_t);
52extern "C" void free(void *);
53extern "C" void *memset (void *, int, std::size_t);
54#endif
55
56using namespace __cxxabiv1;
57
58// ??? How to control these parameters.
59
60// Guess from the size of basic types how large a buffer is reasonable.
61// Note that the basic c++ exception header has 13 pointers and 2 ints,
62// so on a system with PSImode pointers we're talking about 56 bytes
63// just for overhead.
64
65#if INT_MAX == 32767
66# define EMERGENCY_OBJ_SIZE	128
67# define EMERGENCY_OBJ_COUNT	16
68#elif LONG_MAX == 2147483647
69# define EMERGENCY_OBJ_SIZE	512
70# define EMERGENCY_OBJ_COUNT	32
71#else
72# define EMERGENCY_OBJ_SIZE	1024
73# define EMERGENCY_OBJ_COUNT	64
74#endif
75
76#ifndef __GTHREADS
77# undef EMERGENCY_OBJ_COUNT
78# define EMERGENCY_OBJ_COUNT	4
79#endif
80
81/* APPLE LOCAL begin reduce emergency buffer size */
82/* 256 bytes is more than large enough for an std::bad_alloc object */
83#undef EMERGENCY_OBJ_SIZE
84#undef EMERGENCY_OBJ_COUNT
85#define EMERGENCY_OBJ_SIZE 256
86#define EMERGENCY_OBJ_COUNT 2
87/* APPLE LOCAL end reduce emergency buffer size */
88
89#if INT_MAX == 32767 || EMERGENCY_OBJ_COUNT <= 32
90typedef unsigned int bitmask_type;
91#else
92typedef unsigned long bitmask_type;
93#endif
94
95
96typedef char one_buffer[EMERGENCY_OBJ_SIZE] __attribute__((aligned));
97static one_buffer emergency_buffer[EMERGENCY_OBJ_COUNT];
98static bitmask_type emergency_used;
99
100namespace
101{
102  // A single mutex controlling emergency allocations.
103  __gnu_cxx::__mutex emergency_mutex;
104}
105
106extern "C" void *
107__cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw()
108{
109  void *ret;
110
111  thrown_size += sizeof (__cxa_exception);
112  ret = malloc (thrown_size);
113
114  if (! ret)
115    {
116      __gnu_cxx::__scoped_lock sentry(emergency_mutex);
117
118      bitmask_type used = emergency_used;
119      unsigned int which = 0;
120
121      if (thrown_size > EMERGENCY_OBJ_SIZE)
122	goto failed;
123      while (used & 1)
124	{
125	  used >>= 1;
126	  if (++which >= EMERGENCY_OBJ_COUNT)
127	    goto failed;
128	}
129
130      emergency_used |= (bitmask_type)1 << which;
131      ret = &emergency_buffer[which][0];
132
133    failed:;
134
135      if (!ret)
136	std::terminate ();
137    }
138
139  // We have an uncaught exception as soon as we allocate memory.  This
140  // yields uncaught_exception() true during the copy-constructor that
141  // initializes the exception object.  See Issue 475.
142  __cxa_eh_globals *globals = __cxa_get_globals ();
143  globals->uncaughtExceptions += 1;
144
145  memset (ret, 0, sizeof (__cxa_exception));
146
147  return (void *)((char *)ret + sizeof (__cxa_exception));
148}
149
150
151extern "C" void
152__cxxabiv1::__cxa_free_exception(void *vptr) throw()
153{
154  char *ptr = (char *) vptr;
155  if (ptr >= &emergency_buffer[0][0]
156      && ptr < &emergency_buffer[0][0] + sizeof (emergency_buffer))
157    {
158      const unsigned int which
159	= (unsigned)(ptr - &emergency_buffer[0][0]) / EMERGENCY_OBJ_SIZE;
160
161      __gnu_cxx::__scoped_lock sentry(emergency_mutex);
162      emergency_used &= ~((bitmask_type)1 << which);
163    }
164  else
165    free (ptr - sizeof (__cxa_exception));
166}
167