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 <cstdlib>
35#if _GLIBCXX_HOSTED
36#include <cstring>
37#endif
38#include <climits>
39#include <exception>
40#include "unwind-cxx.h"
41#include "bits/c++config.h"
42#include "bits/gthr.h"
43
44#if _GLIBCXX_HOSTED
45using std::free;
46using std::malloc;
47using std::memcpy;
48#else
49// In a freestanding environment, these functions may not be
50// available -- 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#if INT_MAX == 32767 || EMERGENCY_OBJ_COUNT <= 32
82typedef unsigned int bitmask_type;
83#else
84typedef unsigned long bitmask_type;
85#endif
86
87
88typedef char one_buffer[EMERGENCY_OBJ_SIZE] __attribute__((aligned));
89static one_buffer emergency_buffer[EMERGENCY_OBJ_COUNT];
90static bitmask_type emergency_used;
91
92
93#ifdef __GTHREADS
94#ifdef __GTHREAD_MUTEX_INIT
95static __gthread_mutex_t emergency_mutex =__GTHREAD_MUTEX_INIT;
96#else
97static __gthread_mutex_t emergency_mutex;
98#endif
99
100#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
101static void
102emergency_mutex_init ()
103{
104  __GTHREAD_MUTEX_INIT_FUNCTION (&emergency_mutex);
105}
106#endif
107#endif
108
109
110extern "C" void *
111__cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw()
112{
113  void *ret;
114
115  thrown_size += sizeof (__cxa_exception);
116  ret = malloc (thrown_size);
117
118  if (! ret)
119    {
120#ifdef __GTHREADS
121#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
122      static __gthread_once_t once = __GTHREAD_ONCE_INIT;
123      __gthread_once (&once, emergency_mutex_init);
124#endif
125      __gthread_mutex_lock (&emergency_mutex);
126#endif
127
128      bitmask_type used = emergency_used;
129      unsigned int which = 0;
130
131      if (thrown_size > EMERGENCY_OBJ_SIZE)
132	goto failed;
133      while (used & 1)
134	{
135	  used >>= 1;
136	  if (++which >= EMERGENCY_OBJ_COUNT)
137	    goto failed;
138	}
139
140      emergency_used |= (bitmask_type)1 << which;
141      ret = &emergency_buffer[which][0];
142
143    failed:;
144#ifdef __GTHREADS
145      __gthread_mutex_unlock (&emergency_mutex);
146#endif
147      if (!ret)
148	std::terminate ();
149    }
150
151  // We have an uncaught exception as soon as we allocate memory.  This
152  // yields uncaught_exception() true during the copy-constructor that
153  // initializes the exception object.  See Issue 475.
154  __cxa_eh_globals *globals = __cxa_get_globals ();
155  globals->uncaughtExceptions += 1;
156
157  memset (ret, 0, sizeof (__cxa_exception));
158
159  return (void *)((char *)ret + sizeof (__cxa_exception));
160}
161
162
163extern "C" void
164__cxxabiv1::__cxa_free_exception(void *vptr) throw()
165{
166  char *ptr = (char *) vptr;
167  if (ptr >= &emergency_buffer[0][0]
168      && ptr < &emergency_buffer[0][0] + sizeof (emergency_buffer))
169    {
170      unsigned int which
171	= (unsigned)(ptr - &emergency_buffer[0][0]) / EMERGENCY_OBJ_SIZE;
172
173#ifdef __GTHREADS
174      __gthread_mutex_lock (&emergency_mutex);
175      emergency_used &= ~((bitmask_type)1 << which);
176      __gthread_mutex_unlock (&emergency_mutex);
177#else
178      emergency_used &= ~((bitmask_type)1 << which);
179#endif
180    }
181  else
182    free (ptr - sizeof (__cxa_exception));
183}
184