1 // New abi Support -*- C++ -*-
2 
3 // Copyright (C) 2000, 2001, 2003, 2004 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, 59 Temple Place - Suite 330,
20 // Boston, MA 02111-1307, 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 // Written by Nathan Sidwell, Codesourcery LLC, <[email protected]>
32 
33 #include <cxxabi.h>
34 #include <new>
35 #include <exception>
36 #include <exception_defines.h>
37 #include "unwind-cxx.h"
38 
39 namespace __cxxabiv1
40 {
41   namespace
42   {
43     struct uncatch_exception
44     {
45       uncatch_exception();
46       ~uncatch_exception () { __cxa_begin_catch (&p->unwindHeader); }
47 
48       __cxa_exception* p;
49 
50     private:
51       uncatch_exception&
52       operator=(const uncatch_exception&);
53 
54       uncatch_exception(const uncatch_exception&);
55     };
56 
57     uncatch_exception::uncatch_exception() : p(0)
58     {
59       __cxa_eh_globals *globals = __cxa_get_globals_fast ();
60 
61       p = globals->caughtExceptions;
62       p->handlerCount -= 1;
63       globals->caughtExceptions = p->nextException;
64       globals->uncaughtExceptions += 1;
65     }
66   }
67 
68   // Allocate and construct array.
69   extern "C" void *
70   __cxa_vec_new(std::size_t element_count,
71 		std::size_t element_size,
72 		std::size_t padding_size,
73 		void (*constructor) (void *),
74 		void (*destructor) (void *))
75   {
76     return __cxa_vec_new2(element_count, element_size, padding_size,
77 			   constructor, destructor,
78 			   &operator new[], &operator delete []);
79   }
80 
81   extern "C" void *
82   __cxa_vec_new2(std::size_t element_count,
83 		 std::size_t element_size,
84 		 std::size_t padding_size,
85 		 void (*constructor) (void *),
86 		 void (*destructor) (void *),
87 		 void *(*alloc) (std::size_t),
88 		 void (*dealloc) (void *))
89   {
90     std::size_t size = element_count * element_size + padding_size;
91     char *base = static_cast <char *> (alloc (size));
92     if (!base)
93       return base;
94 
95     if (padding_size)
96       {
97 	base += padding_size;
98 	reinterpret_cast <std::size_t *> (base)[-1] = element_count;
99       }
100     try
101       {
102 	__cxa_vec_ctor(base, element_count, element_size,
103 		       constructor, destructor);
104       }
105     catch (...)
106       {
107 	{
108 	  uncatch_exception ue;
109 	  dealloc(base - padding_size);
110 	}
111 	__throw_exception_again;
112       }
113     return base;
114   }
115 
116   extern "C" void *
117   __cxa_vec_new3(std::size_t element_count,
118 		 std::size_t element_size,
119 		 std::size_t padding_size,
120 		 void (*constructor) (void *),
121 		 void (*destructor) (void *),
122 		 void *(*alloc) (std::size_t),
123 		 void (*dealloc) (void *, std::size_t))
124   {
125     std::size_t size = element_count * element_size + padding_size;
126     char *base = static_cast<char *>(alloc (size));
127     if (!base)
128       return base;
129 
130     if (padding_size)
131       {
132 	base += padding_size;
133 	reinterpret_cast<std::size_t *>(base)[-1] = element_count;
134       }
135     try
136       {
137 	__cxa_vec_ctor(base, element_count, element_size,
138 		       constructor, destructor);
139       }
140     catch (...)
141       {
142 	{
143 	  uncatch_exception ue;
144 	  dealloc(base - padding_size, size);
145 	}
146 	__throw_exception_again;
147       }
148     return base;
149   }
150 
151   // Construct array.
152   extern "C" void
153   __cxa_vec_ctor(void *array_address,
154 		 std::size_t element_count,
155 		 std::size_t element_size,
156 		 void (*constructor) (void *),
157 		 void (*destructor) (void *))
158   {
159     std::size_t ix = 0;
160     char *ptr = static_cast<char *>(array_address);
161 
162     try
163       {
164 	if (constructor)
165 	  for (; ix != element_count; ix++, ptr += element_size)
166 	    constructor(ptr);
167       }
168     catch (...)
169       {
170 	{
171 	  uncatch_exception ue;
172 	  __cxa_vec_cleanup(array_address, ix, element_size, destructor);
173 	}
174 	__throw_exception_again;
175       }
176   }
177 
178   // Construct an array by copying.
179   extern "C" void
180   __cxa_vec_cctor(void *dest_array,
181 		  void *src_array,
182 		  std::size_t element_count,
183 		  std::size_t element_size,
184 		  void (*constructor) (void *, void *),
185 		  void (*destructor) (void *))
186   {
187     std::size_t ix = 0;
188     char *dest_ptr = static_cast<char *>(dest_array);
189     char *src_ptr = static_cast<char *>(src_array);
190 
191     try
192       {
193 	if (constructor)
194 	  for (; ix != element_count;
195 	       ix++, src_ptr += element_size, dest_ptr += element_size)
196 	    constructor(dest_ptr, src_ptr);
197       }
198     catch (...)
199       {
200 	{
201 	  uncatch_exception ue;
202 	  __cxa_vec_cleanup(dest_array, ix, element_size, destructor);
203 	}
204 	__throw_exception_again;
205       }
206   }
207 
208   // Destruct array.
209   extern "C" void
210   __cxa_vec_dtor(void *array_address,
211 		 std::size_t element_count,
212 		 std::size_t element_size,
213 		 void (*destructor) (void *))
214   {
215     if (destructor)
216       {
217 	char *ptr = static_cast<char *>(array_address);
218 	std::size_t ix = element_count;
219 
220 	ptr += element_count * element_size;
221 
222 	try
223 	  {
224 	    while (ix--)
225 	      {
226 		ptr -= element_size;
227 		destructor(ptr);
228 	      }
229 	  }
230 	catch (...)
231 	  {
232 	    {
233 	      uncatch_exception ue;
234 	      __cxa_vec_cleanup(array_address, ix, element_size, destructor);
235 	    }
236 	    __throw_exception_again;
237 	  }
238       }
239   }
240 
241   // Destruct array as a result of throwing an exception.
242   // [except.ctor]/3 If a destructor called during stack unwinding
243   // exits with an exception, terminate is called.
244   extern "C" void
245   __cxa_vec_cleanup(void *array_address,
246 		    std::size_t element_count,
247 		    std::size_t element_size,
248 		    void (*destructor) (void *))
249   {
250     if (destructor)
251       {
252 	char *ptr = static_cast <char *> (array_address);
253 	std::size_t ix = element_count;
254 
255 	ptr += element_count * element_size;
256 
257 	try
258 	  {
259 	    while (ix--)
260 	      {
261 		ptr -= element_size;
262 		destructor(ptr);
263 	      }
264 	  }
265 	catch (...)
266 	  {
267 	    std::terminate();
268 	  }
269       }
270   }
271 
272   // Destruct and release array.
273   extern "C" void
274   __cxa_vec_delete(void *array_address,
275 		   std::size_t element_size,
276 		   std::size_t padding_size,
277 		   void (*destructor) (void *))
278   {
279     __cxa_vec_delete2(array_address, element_size, padding_size,
280 		       destructor,
281 		       &operator delete []);
282   }
283 
284   extern "C" void
285   __cxa_vec_delete2(void *array_address,
286 		    std::size_t element_size,
287 		    std::size_t padding_size,
288 		    void (*destructor) (void *),
289 		    void (*dealloc) (void *))
290   {
291     if (!array_address)
292       return;
293 
294     char* base = static_cast<char *>(array_address);
295 
296     if (padding_size)
297       {
298 	std::size_t element_count = reinterpret_cast<std::size_t *>(base)[-1];
299 	base -= padding_size;
300 	try
301 	  {
302 	    __cxa_vec_dtor(array_address, element_count, element_size,
303 			   destructor);
304 	  }
305 	catch (...)
306 	  {
307 	    {
308 	      uncatch_exception ue;
309 	      dealloc(base);
310 	    }
311 	    __throw_exception_again;
312 	  }
313       }
314     dealloc(base);
315   }
316 
317   extern "C" void
318   __cxa_vec_delete3(void *array_address,
319 		    std::size_t element_size,
320 		    std::size_t padding_size,
321 		     void (*destructor) (void *),
322 		    void (*dealloc) (void *, std::size_t))
323   {
324     if (!array_address)
325       return;
326 
327     char* base = static_cast <char *> (array_address);
328     std::size_t size = 0;
329 
330     if (padding_size)
331       {
332 	std::size_t element_count = reinterpret_cast<std::size_t *> (base)[-1];
333 	base -= padding_size;
334 	size = element_count * element_size + padding_size;
335 	try
336 	  {
337 	    __cxa_vec_dtor(array_address, element_count, element_size,
338 			   destructor);
339 	  }
340 	catch (...)
341 	  {
342 	    {
343 	      uncatch_exception ue;
344 	      dealloc(base, size);
345 	    }
346 	    __throw_exception_again;
347 	  }
348       }
349     dealloc(base, size);
350   }
351 } // namespace __cxxabiv1
352 
353