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