197403Sobrien// New abi Support -*- C++ -*-
297403Sobrien
3132720Skan// Copyright (C) 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
497403Sobrien//
5132720Skan// This file is part of GCC.
697403Sobrien//
7132720Skan// GCC is free software; you can redistribute it and/or modify
897403Sobrien// it under the terms of the GNU General Public License as published by
997403Sobrien// the Free Software Foundation; either version 2, or (at your option)
1097403Sobrien// any later version.
1197403Sobrien
12132720Skan// GCC is distributed in the hope that it will be useful,
1397403Sobrien// but WITHOUT ANY WARRANTY; without even the implied warranty of
1497403Sobrien// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1597403Sobrien// GNU General Public License for more details.
1697403Sobrien
1797403Sobrien// You should have received a copy of the GNU General Public License
18132720Skan// along with GCC; see the file COPYING.  If not, write to
19169691Skan// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
20169691Skan// Boston, MA 02110-1301, USA.
2197403Sobrien
2297403Sobrien// As a special exception, you may use this file as part of a free software
2397403Sobrien// library without restriction.  Specifically, if other files instantiate
2497403Sobrien// templates or use macros or inline functions from this file, or you compile
2597403Sobrien// this file and link it with other files to produce an executable, this
2697403Sobrien// file does not by itself cause the resulting executable to be covered by
2797403Sobrien// the GNU General Public License.  This exception does not however
2897403Sobrien// invalidate any other reasons why the executable file might be covered by
2997403Sobrien// the GNU General Public License.
3097403Sobrien
3197403Sobrien// Written by Nathan Sidwell, Codesourcery LLC, <nathan@codesourcery.com>
3297403Sobrien
3397403Sobrien#include <cxxabi.h>
3497403Sobrien#include <new>
3597403Sobrien#include <exception>
3697403Sobrien#include <exception_defines.h>
3797403Sobrien#include "unwind-cxx.h"
3897403Sobrien
3997403Sobriennamespace __cxxabiv1
4097403Sobrien{
4197403Sobrien  namespace
4297403Sobrien  {
4397403Sobrien    struct uncatch_exception
4497403Sobrien    {
45132720Skan      uncatch_exception();
4697403Sobrien      ~uncatch_exception () { __cxa_begin_catch (&p->unwindHeader); }
4797403Sobrien
48132720Skan      __cxa_exception* p;
49132720Skan
50132720Skan    private:
51132720Skan      uncatch_exception&
52132720Skan      operator=(const uncatch_exception&);
53132720Skan
54132720Skan      uncatch_exception(const uncatch_exception&);
5597403Sobrien    };
5697403Sobrien
57132720Skan    uncatch_exception::uncatch_exception() : p(0)
5897403Sobrien    {
5997403Sobrien      __cxa_eh_globals *globals = __cxa_get_globals_fast ();
6097403Sobrien
6197403Sobrien      p = globals->caughtExceptions;
6297403Sobrien      p->handlerCount -= 1;
6397403Sobrien      globals->caughtExceptions = p->nextException;
6497403Sobrien      globals->uncaughtExceptions += 1;
6597403Sobrien    }
6697403Sobrien  }
6797403Sobrien
6897403Sobrien  // Allocate and construct array.
6997403Sobrien  extern "C" void *
7097403Sobrien  __cxa_vec_new(std::size_t element_count,
7197403Sobrien		std::size_t element_size,
7297403Sobrien		std::size_t padding_size,
73169691Skan		__cxa_cdtor_type constructor,
74169691Skan		__cxa_cdtor_type destructor)
7597403Sobrien  {
7697403Sobrien    return __cxa_vec_new2(element_count, element_size, padding_size,
7797403Sobrien			   constructor, destructor,
7897403Sobrien			   &operator new[], &operator delete []);
7997403Sobrien  }
8097403Sobrien
8197403Sobrien  extern "C" void *
8297403Sobrien  __cxa_vec_new2(std::size_t element_count,
8397403Sobrien		 std::size_t element_size,
8497403Sobrien		 std::size_t padding_size,
85169691Skan		 __cxa_cdtor_type constructor,
86169691Skan		 __cxa_cdtor_type destructor,
8797403Sobrien		 void *(*alloc) (std::size_t),
8897403Sobrien		 void (*dealloc) (void *))
8997403Sobrien  {
9097403Sobrien    std::size_t size = element_count * element_size + padding_size;
9197403Sobrien    char *base = static_cast <char *> (alloc (size));
92132720Skan    if (!base)
93132720Skan      return base;
94132720Skan
9597403Sobrien    if (padding_size)
9697403Sobrien      {
9797403Sobrien	base += padding_size;
9897403Sobrien	reinterpret_cast <std::size_t *> (base)[-1] = element_count;
99169691Skan#ifdef _GLIBCXX_ELTSIZE_IN_COOKIE
100169691Skan	reinterpret_cast <std::size_t *> (base)[-2] = element_size;
101169691Skan#endif
10297403Sobrien      }
10397403Sobrien    try
10497403Sobrien      {
10597403Sobrien	__cxa_vec_ctor(base, element_count, element_size,
10697403Sobrien		       constructor, destructor);
10797403Sobrien      }
10897403Sobrien    catch (...)
10997403Sobrien      {
11097403Sobrien	{
11197403Sobrien	  uncatch_exception ue;
11297403Sobrien	  dealloc(base - padding_size);
11397403Sobrien	}
11497403Sobrien	__throw_exception_again;
11597403Sobrien      }
11697403Sobrien    return base;
11797403Sobrien  }
11897403Sobrien
11997403Sobrien  extern "C" void *
12097403Sobrien  __cxa_vec_new3(std::size_t element_count,
12197403Sobrien		 std::size_t element_size,
12297403Sobrien		 std::size_t padding_size,
123169691Skan		 __cxa_cdtor_type constructor,
124169691Skan		 __cxa_cdtor_type destructor,
12597403Sobrien		 void *(*alloc) (std::size_t),
12697403Sobrien		 void (*dealloc) (void *, std::size_t))
12797403Sobrien  {
12897403Sobrien    std::size_t size = element_count * element_size + padding_size;
12997403Sobrien    char *base = static_cast<char *>(alloc (size));
130132720Skan    if (!base)
131132720Skan      return base;
13297403Sobrien
13397403Sobrien    if (padding_size)
13497403Sobrien      {
13597403Sobrien	base += padding_size;
13697403Sobrien	reinterpret_cast<std::size_t *>(base)[-1] = element_count;
137169691Skan#ifdef _GLIBCXX_ELTSIZE_IN_COOKIE
138169691Skan	reinterpret_cast <std::size_t *> (base)[-2] = element_size;
139169691Skan#endif
14097403Sobrien      }
14197403Sobrien    try
14297403Sobrien      {
14397403Sobrien	__cxa_vec_ctor(base, element_count, element_size,
14497403Sobrien		       constructor, destructor);
14597403Sobrien      }
14697403Sobrien    catch (...)
14797403Sobrien      {
14897403Sobrien	{
14997403Sobrien	  uncatch_exception ue;
15097403Sobrien	  dealloc(base - padding_size, size);
15197403Sobrien	}
15297403Sobrien	__throw_exception_again;
15397403Sobrien      }
15497403Sobrien    return base;
15597403Sobrien  }
15697403Sobrien
15797403Sobrien  // Construct array.
158169691Skan  extern "C" __cxa_vec_ctor_return_type
15997403Sobrien  __cxa_vec_ctor(void *array_address,
16097403Sobrien		 std::size_t element_count,
16197403Sobrien		 std::size_t element_size,
162169691Skan		 __cxa_cdtor_type constructor,
163169691Skan		 __cxa_cdtor_type destructor)
16497403Sobrien  {
16597403Sobrien    std::size_t ix = 0;
16697403Sobrien    char *ptr = static_cast<char *>(array_address);
16797403Sobrien
16897403Sobrien    try
16997403Sobrien      {
17097403Sobrien	if (constructor)
17197403Sobrien	  for (; ix != element_count; ix++, ptr += element_size)
17297403Sobrien	    constructor(ptr);
17397403Sobrien      }
17497403Sobrien    catch (...)
17597403Sobrien      {
17697403Sobrien	{
17797403Sobrien	  uncatch_exception ue;
17897403Sobrien	  __cxa_vec_cleanup(array_address, ix, element_size, destructor);
17997403Sobrien	}
18097403Sobrien	__throw_exception_again;
18197403Sobrien      }
182169691Skan    _GLIBCXX_CXA_VEC_CTOR_RETURN (array_address);
18397403Sobrien  }
18497403Sobrien
18597403Sobrien  // Construct an array by copying.
186169691Skan  extern "C" __cxa_vec_ctor_return_type
18797403Sobrien  __cxa_vec_cctor(void *dest_array,
18897403Sobrien		  void *src_array,
18997403Sobrien		  std::size_t element_count,
19097403Sobrien		  std::size_t element_size,
191169691Skan		  __cxa_cdtor_return_type (*constructor) (void *, void *),
192169691Skan		  __cxa_cdtor_type destructor)
19397403Sobrien  {
19497403Sobrien    std::size_t ix = 0;
19597403Sobrien    char *dest_ptr = static_cast<char *>(dest_array);
19697403Sobrien    char *src_ptr = static_cast<char *>(src_array);
19797403Sobrien
19897403Sobrien    try
19997403Sobrien      {
20097403Sobrien	if (constructor)
20197403Sobrien	  for (; ix != element_count;
20297403Sobrien	       ix++, src_ptr += element_size, dest_ptr += element_size)
20397403Sobrien	    constructor(dest_ptr, src_ptr);
20497403Sobrien      }
20597403Sobrien    catch (...)
20697403Sobrien      {
20797403Sobrien	{
20897403Sobrien	  uncatch_exception ue;
20997403Sobrien	  __cxa_vec_cleanup(dest_array, ix, element_size, destructor);
21097403Sobrien	}
21197403Sobrien	__throw_exception_again;
21297403Sobrien      }
213169691Skan    _GLIBCXX_CXA_VEC_CTOR_RETURN (dest_array);
21497403Sobrien  }
21597403Sobrien
21697403Sobrien  // Destruct array.
21797403Sobrien  extern "C" void
21897403Sobrien  __cxa_vec_dtor(void *array_address,
21997403Sobrien		 std::size_t element_count,
22097403Sobrien		 std::size_t element_size,
221169691Skan		 __cxa_cdtor_type destructor)
22297403Sobrien  {
22397403Sobrien    if (destructor)
22497403Sobrien      {
22597403Sobrien	char *ptr = static_cast<char *>(array_address);
22697403Sobrien	std::size_t ix = element_count;
22797403Sobrien
22897403Sobrien	ptr += element_count * element_size;
22997403Sobrien
23097403Sobrien	try
23197403Sobrien	  {
23297403Sobrien	    while (ix--)
23397403Sobrien	      {
23497403Sobrien		ptr -= element_size;
23597403Sobrien		destructor(ptr);
23697403Sobrien	      }
23797403Sobrien	  }
23897403Sobrien	catch (...)
23997403Sobrien	  {
24097403Sobrien	    {
24197403Sobrien	      uncatch_exception ue;
24297403Sobrien	      __cxa_vec_cleanup(array_address, ix, element_size, destructor);
24397403Sobrien	    }
24497403Sobrien	    __throw_exception_again;
24597403Sobrien	  }
24697403Sobrien      }
24797403Sobrien  }
24897403Sobrien
24997403Sobrien  // Destruct array as a result of throwing an exception.
25097403Sobrien  // [except.ctor]/3 If a destructor called during stack unwinding
25197403Sobrien  // exits with an exception, terminate is called.
25297403Sobrien  extern "C" void
25397403Sobrien  __cxa_vec_cleanup(void *array_address,
25497403Sobrien		    std::size_t element_count,
25597403Sobrien		    std::size_t element_size,
256169691Skan		    __cxa_cdtor_type destructor)
25797403Sobrien  {
25897403Sobrien    if (destructor)
25997403Sobrien      {
26097403Sobrien	char *ptr = static_cast <char *> (array_address);
26197403Sobrien	std::size_t ix = element_count;
26297403Sobrien
26397403Sobrien	ptr += element_count * element_size;
26497403Sobrien
26597403Sobrien	try
26697403Sobrien	  {
26797403Sobrien	    while (ix--)
26897403Sobrien	      {
26997403Sobrien		ptr -= element_size;
27097403Sobrien		destructor(ptr);
27197403Sobrien	      }
27297403Sobrien	  }
27397403Sobrien	catch (...)
27497403Sobrien	  {
27597403Sobrien	    std::terminate();
27697403Sobrien	  }
27797403Sobrien      }
27897403Sobrien  }
27997403Sobrien
28097403Sobrien  // Destruct and release array.
28197403Sobrien  extern "C" void
28297403Sobrien  __cxa_vec_delete(void *array_address,
28397403Sobrien		   std::size_t element_size,
28497403Sobrien		   std::size_t padding_size,
285169691Skan		   __cxa_cdtor_type destructor)
28697403Sobrien  {
28797403Sobrien    __cxa_vec_delete2(array_address, element_size, padding_size,
28897403Sobrien		       destructor,
28997403Sobrien		       &operator delete []);
29097403Sobrien  }
29197403Sobrien
29297403Sobrien  extern "C" void
29397403Sobrien  __cxa_vec_delete2(void *array_address,
29497403Sobrien		    std::size_t element_size,
29597403Sobrien		    std::size_t padding_size,
296169691Skan		    __cxa_cdtor_type destructor,
29797403Sobrien		    void (*dealloc) (void *))
29897403Sobrien  {
299132720Skan    if (!array_address)
300132720Skan      return;
301132720Skan
302132720Skan    char* base = static_cast<char *>(array_address);
30397403Sobrien
30497403Sobrien    if (padding_size)
30597403Sobrien      {
30697403Sobrien	std::size_t element_count = reinterpret_cast<std::size_t *>(base)[-1];
30797403Sobrien	base -= padding_size;
30897403Sobrien	try
30997403Sobrien	  {
31097403Sobrien	    __cxa_vec_dtor(array_address, element_count, element_size,
31197403Sobrien			   destructor);
31297403Sobrien	  }
31397403Sobrien	catch (...)
31497403Sobrien	  {
31597403Sobrien	    {
31697403Sobrien	      uncatch_exception ue;
31797403Sobrien	      dealloc(base);
31897403Sobrien	    }
31997403Sobrien	    __throw_exception_again;
32097403Sobrien	  }
32197403Sobrien      }
32297403Sobrien    dealloc(base);
32397403Sobrien  }
32497403Sobrien
32597403Sobrien  extern "C" void
32697403Sobrien  __cxa_vec_delete3(void *array_address,
32797403Sobrien		    std::size_t element_size,
32897403Sobrien		    std::size_t padding_size,
329169691Skan		     __cxa_cdtor_type destructor,
33097403Sobrien		    void (*dealloc) (void *, std::size_t))
33197403Sobrien  {
332132720Skan    if (!array_address)
333132720Skan      return;
334132720Skan
335132720Skan    char* base = static_cast <char *> (array_address);
33697403Sobrien    std::size_t size = 0;
337132720Skan
33897403Sobrien    if (padding_size)
33997403Sobrien      {
34097403Sobrien	std::size_t element_count = reinterpret_cast<std::size_t *> (base)[-1];
34197403Sobrien	base -= padding_size;
34297403Sobrien	size = element_count * element_size + padding_size;
34397403Sobrien	try
34497403Sobrien	  {
34597403Sobrien	    __cxa_vec_dtor(array_address, element_count, element_size,
34697403Sobrien			   destructor);
34797403Sobrien	  }
34897403Sobrien	catch (...)
34997403Sobrien	  {
35097403Sobrien	    {
35197403Sobrien	      uncatch_exception ue;
35297403Sobrien	      dealloc(base, size);
35397403Sobrien	    }
35497403Sobrien	    __throw_exception_again;
35597403Sobrien	  }
35697403Sobrien      }
35797403Sobrien    dealloc(base, size);
35897403Sobrien  }
35997403Sobrien} // namespace __cxxabiv1
36097403Sobrien
361169691Skan#if defined(__arm__) && defined(__ARM_EABI__)
362169691Skan
363169691Skan// The ARM C++ ABI requires that the library provide these additional
364169691Skan// helper functions.  There are placed in this file, despite being
365169691Skan// architecture-specifier, so that the compiler can inline the __cxa
366169691Skan// functions into these functions as appropriate.
367169691Skan
368169691Skannamespace __aeabiv1
369169691Skan{
370169691Skan  extern "C" void *
371169691Skan  __aeabi_vec_ctor_nocookie_nodtor (void *array_address,
372169691Skan				    abi::__cxa_cdtor_type constructor,
373169691Skan				    std::size_t element_size,
374169691Skan				    std::size_t element_count)
375169691Skan  {
376169691Skan    return abi::__cxa_vec_ctor (array_address, element_count, element_size,
377169691Skan				constructor, /*destructor=*/NULL);
378169691Skan  }
379169691Skan
380169691Skan  extern "C" void *
381169691Skan  __aeabi_vec_ctor_cookie_nodtor (void *array_address,
382169691Skan				  abi::__cxa_cdtor_type constructor,
383169691Skan				  std::size_t element_size,
384169691Skan				  std::size_t element_count)
385169691Skan  {
386169691Skan    if (array_address == NULL)
387169691Skan      return NULL;
388169691Skan
389169691Skan    array_address = reinterpret_cast<std::size_t *>(array_address) + 2;
390169691Skan    reinterpret_cast<std::size_t *>(array_address)[-2] = element_size;
391169691Skan    reinterpret_cast<std::size_t *>(array_address)[-1] = element_count;
392169691Skan    return abi::__cxa_vec_ctor (array_address,
393169691Skan				element_count, element_size,
394169691Skan				constructor, /*destructor=*/NULL);
395169691Skan  }
396169691Skan
397169691Skan  extern "C" void *
398169691Skan  __aeabi_vec_cctor_nocookie_nodtor (void *dest_array,
399169691Skan				     void *src_array,
400169691Skan				     std::size_t element_size,
401169691Skan				     std::size_t element_count,
402169691Skan				     void *(*constructor) (void *, void *))
403169691Skan  {
404169691Skan    return abi::__cxa_vec_cctor (dest_array, src_array,
405169691Skan				 element_count, element_size,
406169691Skan				 constructor, NULL);
407169691Skan  }
408169691Skan
409169691Skan  extern "C" void *
410169691Skan  __aeabi_vec_new_cookie_noctor (std::size_t element_size,
411169691Skan				 std::size_t element_count)
412169691Skan  {
413169691Skan    return abi::__cxa_vec_new(element_count, element_size,
414169691Skan			      2 * sizeof (std::size_t),
415169691Skan			      /*constructor=*/NULL, /*destructor=*/NULL);
416169691Skan  }
417169691Skan
418169691Skan  extern "C" void *
419169691Skan  __aeabi_vec_new_nocookie (std::size_t element_size,
420169691Skan			    std::size_t element_count,
421169691Skan			    abi::__cxa_cdtor_type constructor)
422169691Skan  {
423169691Skan    return abi::__cxa_vec_new (element_count, element_size, 0, constructor,
424169691Skan			       NULL);
425169691Skan  }
426169691Skan
427169691Skan  extern "C" void *
428169691Skan  __aeabi_vec_new_cookie_nodtor (std::size_t element_size,
429169691Skan				 std::size_t element_count,
430169691Skan				 abi::__cxa_cdtor_type constructor)
431169691Skan  {
432169691Skan    return abi::__cxa_vec_new(element_count, element_size,
433169691Skan			      2 * sizeof (std::size_t),
434169691Skan			      constructor, NULL);
435169691Skan  }
436169691Skan
437169691Skan  extern "C" void *
438169691Skan  __aeabi_vec_new_cookie(std::size_t element_size,
439169691Skan			 std::size_t element_count,
440169691Skan			 abi::__cxa_cdtor_type constructor,
441169691Skan			 abi::__cxa_cdtor_type destructor)
442169691Skan  {
443169691Skan    return abi::__cxa_vec_new (element_count, element_size,
444169691Skan			       2 * sizeof (std::size_t),
445169691Skan			       constructor, destructor);
446169691Skan  }
447169691Skan
448169691Skan
449169691Skan  extern "C" void *
450169691Skan  __aeabi_vec_dtor (void *array_address,
451169691Skan		    abi::__cxa_cdtor_type destructor,
452169691Skan		    std::size_t element_size,
453169691Skan		    std::size_t element_count)
454169691Skan  {
455169691Skan    abi::__cxa_vec_dtor (array_address, element_count, element_size,
456169691Skan			 destructor);
457169691Skan    return reinterpret_cast<std::size_t*> (array_address) - 2;
458169691Skan  }
459169691Skan
460169691Skan  extern "C" void *
461169691Skan  __aeabi_vec_dtor_cookie (void *array_address,
462169691Skan			   abi::__cxa_cdtor_type destructor)
463169691Skan  {
464169691Skan    abi::__cxa_vec_dtor (array_address,
465169691Skan			 reinterpret_cast<std::size_t *>(array_address)[-1],
466169691Skan			 reinterpret_cast<std::size_t *>(array_address)[-2],
467169691Skan			 destructor);
468169691Skan    return reinterpret_cast<std::size_t*> (array_address) - 2;
469169691Skan  }
470169691Skan
471169691Skan
472169691Skan  extern "C" void
473169691Skan  __aeabi_vec_delete (void *array_address,
474169691Skan		      abi::__cxa_cdtor_type destructor)
475169691Skan  {
476169691Skan    abi::__cxa_vec_delete (array_address,
477169691Skan			   reinterpret_cast<std::size_t *>(array_address)[-2],
478169691Skan			   2 * sizeof (std::size_t),
479169691Skan			   destructor);
480169691Skan  }
481169691Skan
482169691Skan  extern "C" void
483169691Skan  __aeabi_vec_delete3 (void *array_address,
484169691Skan		       abi::__cxa_cdtor_type destructor,
485169691Skan		       void (*dealloc) (void *, std::size_t))
486169691Skan  {
487169691Skan    abi::__cxa_vec_delete3 (array_address,
488169691Skan			    reinterpret_cast<std::size_t *>(array_address)[-2],
489169691Skan			    2 * sizeof (std::size_t),
490169691Skan			    destructor, dealloc);
491169691Skan  }
492169691Skan
493169691Skan  extern "C" void
494169691Skan  __aeabi_vec_delete3_nodtor (void *array_address,
495169691Skan			      void (*dealloc) (void *, std::size_t))
496169691Skan  {
497169691Skan    abi::__cxa_vec_delete3 (array_address,
498169691Skan			    reinterpret_cast<std::size_t *>(array_address)[-2],
499169691Skan			    2 * sizeof (std::size_t),
500169691Skan			    /*destructor=*/NULL, dealloc);
501169691Skan  }
502169691Skan
503169691Skan  extern "C" int
504169691Skan  __aeabi_atexit (void *object,
505169691Skan		  void (*destructor) (void *),
506169691Skan		  void *dso_handle)
507169691Skan  {
508169691Skan    return abi::__cxa_atexit(destructor, object, dso_handle);
509169691Skan  }
510169691Skan} // namespace __aeabiv1
511169691Skan
512169691Skan#endif // defined(__arm__) && defined(__ARM_EABI__)
513