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, 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// Written by Nathan Sidwell, Codesourcery LLC, <nathan@codesourcery.com>
32
33#include <cxxabi.h>
34#include <new>
35#include <exception>
36#include <exception_defines.h>
37#include "unwind-cxx.h"
38
39namespace __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		__cxa_cdtor_type constructor,
74		__cxa_cdtor_type destructor)
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		 __cxa_cdtor_type constructor,
86		 __cxa_cdtor_type destructor,
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#ifdef _GLIBCXX_ELTSIZE_IN_COOKIE
100	reinterpret_cast <std::size_t *> (base)[-2] = element_size;
101#endif
102      }
103    try
104      {
105	__cxa_vec_ctor(base, element_count, element_size,
106		       constructor, destructor);
107      }
108    catch (...)
109      {
110	{
111	  uncatch_exception ue;
112	  dealloc(base - padding_size);
113	}
114	__throw_exception_again;
115      }
116    return base;
117  }
118
119  extern "C" void *
120  __cxa_vec_new3(std::size_t element_count,
121		 std::size_t element_size,
122		 std::size_t padding_size,
123		 __cxa_cdtor_type constructor,
124		 __cxa_cdtor_type destructor,
125		 void *(*alloc) (std::size_t),
126		 void (*dealloc) (void *, std::size_t))
127  {
128    std::size_t size = element_count * element_size + padding_size;
129    char *base = static_cast<char *>(alloc (size));
130    if (!base)
131      return base;
132
133    if (padding_size)
134      {
135	base += padding_size;
136	reinterpret_cast<std::size_t *>(base)[-1] = element_count;
137#ifdef _GLIBCXX_ELTSIZE_IN_COOKIE
138	reinterpret_cast <std::size_t *> (base)[-2] = element_size;
139#endif
140      }
141    try
142      {
143	__cxa_vec_ctor(base, element_count, element_size,
144		       constructor, destructor);
145      }
146    catch (...)
147      {
148	{
149	  uncatch_exception ue;
150	  dealloc(base - padding_size, size);
151	}
152	__throw_exception_again;
153      }
154    return base;
155  }
156
157  // Construct array.
158  extern "C" __cxa_vec_ctor_return_type
159  __cxa_vec_ctor(void *array_address,
160		 std::size_t element_count,
161		 std::size_t element_size,
162		 __cxa_cdtor_type constructor,
163		 __cxa_cdtor_type destructor)
164  {
165    std::size_t ix = 0;
166    char *ptr = static_cast<char *>(array_address);
167
168    try
169      {
170	if (constructor)
171	  for (; ix != element_count; ix++, ptr += element_size)
172	    constructor(ptr);
173      }
174    catch (...)
175      {
176	{
177	  uncatch_exception ue;
178	  __cxa_vec_cleanup(array_address, ix, element_size, destructor);
179	}
180	__throw_exception_again;
181      }
182    _GLIBCXX_CXA_VEC_CTOR_RETURN (array_address);
183  }
184
185  // Construct an array by copying.
186  extern "C" __cxa_vec_ctor_return_type
187  __cxa_vec_cctor(void *dest_array,
188		  void *src_array,
189		  std::size_t element_count,
190		  std::size_t element_size,
191		  __cxa_cdtor_return_type (*constructor) (void *, void *),
192		  __cxa_cdtor_type destructor)
193  {
194    std::size_t ix = 0;
195    char *dest_ptr = static_cast<char *>(dest_array);
196    char *src_ptr = static_cast<char *>(src_array);
197
198    try
199      {
200	if (constructor)
201	  for (; ix != element_count;
202	       ix++, src_ptr += element_size, dest_ptr += element_size)
203	    constructor(dest_ptr, src_ptr);
204      }
205    catch (...)
206      {
207	{
208	  uncatch_exception ue;
209	  __cxa_vec_cleanup(dest_array, ix, element_size, destructor);
210	}
211	__throw_exception_again;
212      }
213    _GLIBCXX_CXA_VEC_CTOR_RETURN (dest_array);
214  }
215
216  // Destruct array.
217  extern "C" void
218  __cxa_vec_dtor(void *array_address,
219		 std::size_t element_count,
220		 std::size_t element_size,
221		 __cxa_cdtor_type destructor)
222  {
223    if (destructor)
224      {
225	char *ptr = static_cast<char *>(array_address);
226	std::size_t ix = element_count;
227
228	ptr += element_count * element_size;
229
230	try
231	  {
232	    while (ix--)
233	      {
234		ptr -= element_size;
235		destructor(ptr);
236	      }
237	  }
238	catch (...)
239	  {
240	    {
241	      uncatch_exception ue;
242	      __cxa_vec_cleanup(array_address, ix, element_size, destructor);
243	    }
244	    __throw_exception_again;
245	  }
246      }
247  }
248
249  // Destruct array as a result of throwing an exception.
250  // [except.ctor]/3 If a destructor called during stack unwinding
251  // exits with an exception, terminate is called.
252  extern "C" void
253  __cxa_vec_cleanup(void *array_address,
254		    std::size_t element_count,
255		    std::size_t element_size,
256		    __cxa_cdtor_type destructor)
257  {
258    if (destructor)
259      {
260	char *ptr = static_cast <char *> (array_address);
261	std::size_t ix = element_count;
262
263	ptr += element_count * element_size;
264
265	try
266	  {
267	    while (ix--)
268	      {
269		ptr -= element_size;
270		destructor(ptr);
271	      }
272	  }
273	catch (...)
274	  {
275	    std::terminate();
276	  }
277      }
278  }
279
280  // Destruct and release array.
281  extern "C" void
282  __cxa_vec_delete(void *array_address,
283		   std::size_t element_size,
284		   std::size_t padding_size,
285		   __cxa_cdtor_type destructor)
286  {
287    __cxa_vec_delete2(array_address, element_size, padding_size,
288		       destructor,
289		       &operator delete []);
290  }
291
292  extern "C" void
293  __cxa_vec_delete2(void *array_address,
294		    std::size_t element_size,
295		    std::size_t padding_size,
296		    __cxa_cdtor_type destructor,
297		    void (*dealloc) (void *))
298  {
299    if (!array_address)
300      return;
301
302    char* base = static_cast<char *>(array_address);
303
304    if (padding_size)
305      {
306	std::size_t element_count = reinterpret_cast<std::size_t *>(base)[-1];
307	base -= padding_size;
308	try
309	  {
310	    __cxa_vec_dtor(array_address, element_count, element_size,
311			   destructor);
312	  }
313	catch (...)
314	  {
315	    {
316	      uncatch_exception ue;
317	      dealloc(base);
318	    }
319	    __throw_exception_again;
320	  }
321      }
322    dealloc(base);
323  }
324
325  extern "C" void
326  __cxa_vec_delete3(void *array_address,
327		    std::size_t element_size,
328		    std::size_t padding_size,
329		     __cxa_cdtor_type destructor,
330		    void (*dealloc) (void *, std::size_t))
331  {
332    if (!array_address)
333      return;
334
335    char* base = static_cast <char *> (array_address);
336    std::size_t size = 0;
337
338    if (padding_size)
339      {
340	std::size_t element_count = reinterpret_cast<std::size_t *> (base)[-1];
341	base -= padding_size;
342	size = element_count * element_size + padding_size;
343	try
344	  {
345	    __cxa_vec_dtor(array_address, element_count, element_size,
346			   destructor);
347	  }
348	catch (...)
349	  {
350	    {
351	      uncatch_exception ue;
352	      dealloc(base, size);
353	    }
354	    __throw_exception_again;
355	  }
356      }
357    dealloc(base, size);
358  }
359} // namespace __cxxabiv1
360
361#if defined(__arm__) && defined(__ARM_EABI__)
362
363// The ARM C++ ABI requires that the library provide these additional
364// helper functions.  There are placed in this file, despite being
365// architecture-specifier, so that the compiler can inline the __cxa
366// functions into these functions as appropriate.
367
368namespace __aeabiv1
369{
370  extern "C" void *
371  __aeabi_vec_ctor_nocookie_nodtor (void *array_address,
372				    abi::__cxa_cdtor_type constructor,
373				    std::size_t element_size,
374				    std::size_t element_count)
375  {
376    return abi::__cxa_vec_ctor (array_address, element_count, element_size,
377				constructor, /*destructor=*/NULL);
378  }
379
380  extern "C" void *
381  __aeabi_vec_ctor_cookie_nodtor (void *array_address,
382				  abi::__cxa_cdtor_type constructor,
383				  std::size_t element_size,
384				  std::size_t element_count)
385  {
386    if (array_address == NULL)
387      return NULL;
388
389    array_address = reinterpret_cast<std::size_t *>(array_address) + 2;
390    reinterpret_cast<std::size_t *>(array_address)[-2] = element_size;
391    reinterpret_cast<std::size_t *>(array_address)[-1] = element_count;
392    return abi::__cxa_vec_ctor (array_address,
393				element_count, element_size,
394				constructor, /*destructor=*/NULL);
395  }
396
397  extern "C" void *
398  __aeabi_vec_cctor_nocookie_nodtor (void *dest_array,
399				     void *src_array,
400				     std::size_t element_size,
401				     std::size_t element_count,
402				     void *(*constructor) (void *, void *))
403  {
404    return abi::__cxa_vec_cctor (dest_array, src_array,
405				 element_count, element_size,
406				 constructor, NULL);
407  }
408
409  extern "C" void *
410  __aeabi_vec_new_cookie_noctor (std::size_t element_size,
411				 std::size_t element_count)
412  {
413    return abi::__cxa_vec_new(element_count, element_size,
414			      2 * sizeof (std::size_t),
415			      /*constructor=*/NULL, /*destructor=*/NULL);
416  }
417
418  extern "C" void *
419  __aeabi_vec_new_nocookie (std::size_t element_size,
420			    std::size_t element_count,
421			    abi::__cxa_cdtor_type constructor)
422  {
423    return abi::__cxa_vec_new (element_count, element_size, 0, constructor,
424			       NULL);
425  }
426
427  extern "C" void *
428  __aeabi_vec_new_cookie_nodtor (std::size_t element_size,
429				 std::size_t element_count,
430				 abi::__cxa_cdtor_type constructor)
431  {
432    return abi::__cxa_vec_new(element_count, element_size,
433			      2 * sizeof (std::size_t),
434			      constructor, NULL);
435  }
436
437  extern "C" void *
438  __aeabi_vec_new_cookie(std::size_t element_size,
439			 std::size_t element_count,
440			 abi::__cxa_cdtor_type constructor,
441			 abi::__cxa_cdtor_type destructor)
442  {
443    return abi::__cxa_vec_new (element_count, element_size,
444			       2 * sizeof (std::size_t),
445			       constructor, destructor);
446  }
447
448
449  extern "C" void *
450  __aeabi_vec_dtor (void *array_address,
451		    abi::__cxa_cdtor_type destructor,
452		    std::size_t element_size,
453		    std::size_t element_count)
454  {
455    abi::__cxa_vec_dtor (array_address, element_count, element_size,
456			 destructor);
457    return reinterpret_cast<std::size_t*> (array_address) - 2;
458  }
459
460  extern "C" void *
461  __aeabi_vec_dtor_cookie (void *array_address,
462			   abi::__cxa_cdtor_type destructor)
463  {
464    abi::__cxa_vec_dtor (array_address,
465			 reinterpret_cast<std::size_t *>(array_address)[-1],
466			 reinterpret_cast<std::size_t *>(array_address)[-2],
467			 destructor);
468    return reinterpret_cast<std::size_t*> (array_address) - 2;
469  }
470
471
472  extern "C" void
473  __aeabi_vec_delete (void *array_address,
474		      abi::__cxa_cdtor_type destructor)
475  {
476    abi::__cxa_vec_delete (array_address,
477			   reinterpret_cast<std::size_t *>(array_address)[-2],
478			   2 * sizeof (std::size_t),
479			   destructor);
480  }
481
482  extern "C" void
483  __aeabi_vec_delete3 (void *array_address,
484		       abi::__cxa_cdtor_type destructor,
485		       void (*dealloc) (void *, std::size_t))
486  {
487    abi::__cxa_vec_delete3 (array_address,
488			    reinterpret_cast<std::size_t *>(array_address)[-2],
489			    2 * sizeof (std::size_t),
490			    destructor, dealloc);
491  }
492
493  extern "C" void
494  __aeabi_vec_delete3_nodtor (void *array_address,
495			      void (*dealloc) (void *, std::size_t))
496  {
497    abi::__cxa_vec_delete3 (array_address,
498			    reinterpret_cast<std::size_t *>(array_address)[-2],
499			    2 * sizeof (std::size_t),
500			    /*destructor=*/NULL, dealloc);
501  }
502
503  extern "C" int
504  __aeabi_atexit (void *object,
505		  void (*destructor) (void *),
506		  void *dso_handle)
507  {
508    return abi::__cxa_atexit(destructor, object, dso_handle);
509  }
510} // namespace __aeabiv1
511
512#endif // defined(__arm__) && defined(__ARM_EABI__)
513