xref: /openbsd-src/gnu/llvm/libcxxabi/src/cxa_vector.cpp (revision 8f1d572453a8bab44a2fe956e25efc4124e87e82)
1*8f1d5724Srobert //===----------------------------------------------------------------------===//
279c2e3e6Spatrick //
379c2e3e6Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
479c2e3e6Spatrick // See https://llvm.org/LICENSE.txt for license information.
579c2e3e6Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
679c2e3e6Spatrick //
779c2e3e6Spatrick //
879c2e3e6Spatrick //  This file implements the "Array Construction and Destruction APIs"
979c2e3e6Spatrick //  https://itanium-cxx-abi.github.io/cxx-abi/abi.html#array-ctor
1079c2e3e6Spatrick //
1179c2e3e6Spatrick //===----------------------------------------------------------------------===//
1279c2e3e6Spatrick 
1379c2e3e6Spatrick #include "cxxabi.h"
1479c2e3e6Spatrick #include "__cxxabi_config.h"
1579c2e3e6Spatrick 
1679c2e3e6Spatrick #include <exception>        // for std::terminate
1779c2e3e6Spatrick #include <new>              // for std::bad_array_new_length
1879c2e3e6Spatrick 
1979c2e3e6Spatrick #include "abort_message.h"
2079c2e3e6Spatrick 
2179c2e3e6Spatrick #ifndef __has_builtin
2279c2e3e6Spatrick #define __has_builtin(x) 0
2379c2e3e6Spatrick #endif
2479c2e3e6Spatrick 
2579c2e3e6Spatrick namespace __cxxabiv1 {
2679c2e3e6Spatrick 
27fb9c2e6cSpatrick //
28fb9c2e6cSpatrick // Helper routines and classes
29fb9c2e6cSpatrick //
3079c2e3e6Spatrick 
3179c2e3e6Spatrick namespace {
__get_element_count(void * p)3279c2e3e6Spatrick     inline static size_t __get_element_count ( void *p ) {
3379c2e3e6Spatrick         return static_cast <size_t *> (p)[-1];
3479c2e3e6Spatrick         }
3579c2e3e6Spatrick 
__set_element_count(void * p,size_t element_count)3679c2e3e6Spatrick     inline static void __set_element_count ( void *p, size_t element_count ) {
3779c2e3e6Spatrick         static_cast <size_t *> (p)[-1] = element_count;
3879c2e3e6Spatrick         }
3979c2e3e6Spatrick 
4079c2e3e6Spatrick 
4179c2e3e6Spatrick //  A pair of classes to simplify exception handling and control flow.
4279c2e3e6Spatrick //  They get passed a block of memory in the constructor, and unless the
4379c2e3e6Spatrick //  'release' method is called, they deallocate the memory in the destructor.
4479c2e3e6Spatrick //  Preferred usage is to allocate some memory, attach it to one of these objects,
4579c2e3e6Spatrick //  and then, when all the operations to set up the memory block have succeeded,
4679c2e3e6Spatrick //  call 'release'. If any of the setup operations fail, or an exception is
4779c2e3e6Spatrick //  thrown, then the block is automatically deallocated.
4879c2e3e6Spatrick //
4979c2e3e6Spatrick //  The only difference between these two classes is the signature for the
5079c2e3e6Spatrick //  deallocation function (to match new2/new3 and delete2/delete3.
5179c2e3e6Spatrick     class st_heap_block2 {
5279c2e3e6Spatrick     public:
5379c2e3e6Spatrick         typedef void (*dealloc_f)(void *);
5479c2e3e6Spatrick 
st_heap_block2(dealloc_f dealloc,void * ptr)5579c2e3e6Spatrick         st_heap_block2 ( dealloc_f dealloc, void *ptr )
5679c2e3e6Spatrick             : dealloc_ ( dealloc ), ptr_ ( ptr ), enabled_ ( true ) {}
~st_heap_block2()5779c2e3e6Spatrick         ~st_heap_block2 () { if ( enabled_ ) dealloc_ ( ptr_ ) ; }
release()5879c2e3e6Spatrick         void release () { enabled_ = false; }
5979c2e3e6Spatrick 
6079c2e3e6Spatrick     private:
6179c2e3e6Spatrick         dealloc_f dealloc_;
6279c2e3e6Spatrick         void *ptr_;
6379c2e3e6Spatrick         bool enabled_;
6479c2e3e6Spatrick     };
6579c2e3e6Spatrick 
6679c2e3e6Spatrick     class st_heap_block3 {
6779c2e3e6Spatrick     public:
6879c2e3e6Spatrick         typedef void (*dealloc_f)(void *, size_t);
6979c2e3e6Spatrick 
st_heap_block3(dealloc_f dealloc,void * ptr,size_t size)7079c2e3e6Spatrick         st_heap_block3 ( dealloc_f dealloc, void *ptr, size_t size )
7179c2e3e6Spatrick             : dealloc_ ( dealloc ), ptr_ ( ptr ), size_ ( size ), enabled_ ( true ) {}
~st_heap_block3()7279c2e3e6Spatrick         ~st_heap_block3 () { if ( enabled_ ) dealloc_ ( ptr_, size_ ) ; }
release()7379c2e3e6Spatrick         void release () { enabled_ = false; }
7479c2e3e6Spatrick 
7579c2e3e6Spatrick     private:
7679c2e3e6Spatrick         dealloc_f dealloc_;
7779c2e3e6Spatrick         void *ptr_;
7879c2e3e6Spatrick         size_t size_;
7979c2e3e6Spatrick         bool enabled_;
8079c2e3e6Spatrick     };
8179c2e3e6Spatrick 
8279c2e3e6Spatrick     class st_cxa_cleanup {
8379c2e3e6Spatrick     public:
8479c2e3e6Spatrick         typedef void (*destruct_f)(void *);
8579c2e3e6Spatrick 
st_cxa_cleanup(void * ptr,size_t & idx,size_t element_size,destruct_f destructor)8679c2e3e6Spatrick         st_cxa_cleanup ( void *ptr, size_t &idx, size_t element_size, destruct_f destructor )
8779c2e3e6Spatrick             : ptr_ ( ptr ), idx_ ( idx ), element_size_ ( element_size ),
8879c2e3e6Spatrick                 destructor_ ( destructor ), enabled_ ( true ) {}
~st_cxa_cleanup()8979c2e3e6Spatrick         ~st_cxa_cleanup () {
9079c2e3e6Spatrick             if ( enabled_ )
9179c2e3e6Spatrick                 __cxa_vec_cleanup ( ptr_, idx_, element_size_, destructor_ );
9279c2e3e6Spatrick             }
9379c2e3e6Spatrick 
release()9479c2e3e6Spatrick         void release () { enabled_ = false; }
9579c2e3e6Spatrick 
9679c2e3e6Spatrick     private:
9779c2e3e6Spatrick         void *ptr_;
9879c2e3e6Spatrick         size_t &idx_;
9979c2e3e6Spatrick         size_t element_size_;
10079c2e3e6Spatrick         destruct_f destructor_;
10179c2e3e6Spatrick         bool enabled_;
10279c2e3e6Spatrick     };
10379c2e3e6Spatrick 
10479c2e3e6Spatrick     class st_terminate {
10579c2e3e6Spatrick     public:
st_terminate(bool enabled=true)10679c2e3e6Spatrick         st_terminate ( bool enabled = true ) : enabled_ ( enabled ) {}
~st_terminate()10779c2e3e6Spatrick         ~st_terminate () { if ( enabled_ ) std::terminate (); }
release()10879c2e3e6Spatrick         void release () { enabled_ = false; }
10979c2e3e6Spatrick     private:
11079c2e3e6Spatrick         bool enabled_ ;
11179c2e3e6Spatrick     };
11279c2e3e6Spatrick }
11379c2e3e6Spatrick 
114fb9c2e6cSpatrick //
115fb9c2e6cSpatrick // Externally visible routines
116fb9c2e6cSpatrick //
11779c2e3e6Spatrick 
11879c2e3e6Spatrick namespace {
11979c2e3e6Spatrick _LIBCXXABI_NORETURN
throw_bad_array_new_length()12079c2e3e6Spatrick void throw_bad_array_new_length() {
12179c2e3e6Spatrick #ifndef _LIBCXXABI_NO_EXCEPTIONS
12279c2e3e6Spatrick   throw std::bad_array_new_length();
12379c2e3e6Spatrick #else
12479c2e3e6Spatrick   abort_message("__cxa_vec_new failed to allocate memory");
12579c2e3e6Spatrick #endif
12679c2e3e6Spatrick }
12779c2e3e6Spatrick 
mul_overflow(size_t x,size_t y,size_t * res)12879c2e3e6Spatrick bool mul_overflow(size_t x, size_t y, size_t *res) {
12979c2e3e6Spatrick #if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_mul_overflow)) \
13079c2e3e6Spatrick     || defined(_LIBCXXABI_COMPILER_GCC)
13179c2e3e6Spatrick     return __builtin_mul_overflow(x, y, res);
13279c2e3e6Spatrick #else
13379c2e3e6Spatrick     *res = x * y;
13479c2e3e6Spatrick     return x && ((*res / x) != y);
13579c2e3e6Spatrick #endif
13679c2e3e6Spatrick }
13779c2e3e6Spatrick 
add_overflow(size_t x,size_t y,size_t * res)13879c2e3e6Spatrick bool add_overflow(size_t x, size_t y, size_t *res) {
13979c2e3e6Spatrick #if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_add_overflow)) \
14079c2e3e6Spatrick     || defined(_LIBCXXABI_COMPILER_GCC)
14179c2e3e6Spatrick   return __builtin_add_overflow(x, y, res);
14279c2e3e6Spatrick #else
14379c2e3e6Spatrick   *res = x + y;
14479c2e3e6Spatrick   return *res < y;
14579c2e3e6Spatrick #endif
14679c2e3e6Spatrick }
14779c2e3e6Spatrick 
calculate_allocation_size_or_throw(size_t element_count,size_t element_size,size_t padding_size)14879c2e3e6Spatrick size_t calculate_allocation_size_or_throw(size_t element_count,
14979c2e3e6Spatrick                                           size_t element_size,
15079c2e3e6Spatrick                                           size_t padding_size) {
15179c2e3e6Spatrick   size_t element_heap_size;
15279c2e3e6Spatrick   if (mul_overflow(element_count, element_size, &element_heap_size))
15379c2e3e6Spatrick     throw_bad_array_new_length();
15479c2e3e6Spatrick 
15579c2e3e6Spatrick   size_t allocation_size;
15679c2e3e6Spatrick   if (add_overflow(element_heap_size, padding_size, &allocation_size))
15779c2e3e6Spatrick     throw_bad_array_new_length();
15879c2e3e6Spatrick 
15979c2e3e6Spatrick   return allocation_size;
16079c2e3e6Spatrick }
16179c2e3e6Spatrick 
16279c2e3e6Spatrick } // namespace
16379c2e3e6Spatrick 
16479c2e3e6Spatrick extern "C" {
16579c2e3e6Spatrick 
16679c2e3e6Spatrick // Equivalent to
16779c2e3e6Spatrick //
16879c2e3e6Spatrick //   __cxa_vec_new2(element_count, element_size, padding_size, constructor,
16979c2e3e6Spatrick //                  destructor, &::operator new[], &::operator delete[])
17079c2e3e6Spatrick _LIBCXXABI_FUNC_VIS void *
__cxa_vec_new(size_t element_count,size_t element_size,size_t padding_size,void (* constructor)(void *),void (* destructor)(void *))17179c2e3e6Spatrick __cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size,
17279c2e3e6Spatrick               void (*constructor)(void *), void (*destructor)(void *)) {
17379c2e3e6Spatrick     return __cxa_vec_new2 ( element_count, element_size, padding_size,
17479c2e3e6Spatrick         constructor, destructor, &::operator new [], &::operator delete [] );
17579c2e3e6Spatrick }
17679c2e3e6Spatrick 
17779c2e3e6Spatrick 
17879c2e3e6Spatrick // Given the number and size of elements for an array and the non-negative
17979c2e3e6Spatrick // size of prefix padding for a cookie, allocate space (using alloc) for
18079c2e3e6Spatrick // the array preceded by the specified padding, initialize the cookie if
18179c2e3e6Spatrick // the padding is non-zero, and call the given constructor on each element.
18279c2e3e6Spatrick // Return the address of the array proper, after the padding.
18379c2e3e6Spatrick //
18479c2e3e6Spatrick // If alloc throws an exception, rethrow the exception. If alloc returns
18579c2e3e6Spatrick // NULL, return NULL. If the constructor throws an exception, call
18679c2e3e6Spatrick // destructor for any already constructed elements, and rethrow the
18779c2e3e6Spatrick // exception. If the destructor throws an exception, call std::terminate.
18879c2e3e6Spatrick //
18979c2e3e6Spatrick // The constructor may be NULL, in which case it must not be called. If the
19079c2e3e6Spatrick // padding_size is zero, the destructor may be NULL; in that case it must
19179c2e3e6Spatrick // not be called.
19279c2e3e6Spatrick //
19379c2e3e6Spatrick // Neither alloc nor dealloc may be NULL.
19479c2e3e6Spatrick _LIBCXXABI_FUNC_VIS void *
__cxa_vec_new2(size_t element_count,size_t element_size,size_t padding_size,void (* constructor)(void *),void (* destructor)(void *),void * (* alloc)(size_t),void (* dealloc)(void *))19579c2e3e6Spatrick __cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size,
19679c2e3e6Spatrick                void (*constructor)(void *), void (*destructor)(void *),
19779c2e3e6Spatrick                void *(*alloc)(size_t), void (*dealloc)(void *)) {
19879c2e3e6Spatrick   const size_t heap_size = calculate_allocation_size_or_throw(
19979c2e3e6Spatrick       element_count, element_size, padding_size);
20079c2e3e6Spatrick   char* const heap_block = static_cast<char*>(alloc(heap_size));
20179c2e3e6Spatrick   char* vec_base = heap_block;
20279c2e3e6Spatrick 
20379c2e3e6Spatrick   if (NULL != vec_base) {
20479c2e3e6Spatrick     st_heap_block2 heap(dealloc, heap_block);
20579c2e3e6Spatrick 
20679c2e3e6Spatrick     //  put the padding before the array elements
20779c2e3e6Spatrick         if ( 0 != padding_size ) {
20879c2e3e6Spatrick             vec_base += padding_size;
20979c2e3e6Spatrick             __set_element_count ( vec_base, element_count );
21079c2e3e6Spatrick         }
21179c2e3e6Spatrick 
21279c2e3e6Spatrick     //  Construct the elements
21379c2e3e6Spatrick         __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
21479c2e3e6Spatrick         heap.release ();    // We're good!
21579c2e3e6Spatrick     }
21679c2e3e6Spatrick 
21779c2e3e6Spatrick     return vec_base;
21879c2e3e6Spatrick }
21979c2e3e6Spatrick 
22079c2e3e6Spatrick 
22179c2e3e6Spatrick // Same as __cxa_vec_new2 except that the deallocation function takes both
22279c2e3e6Spatrick // the object address and its size.
22379c2e3e6Spatrick _LIBCXXABI_FUNC_VIS void *
__cxa_vec_new3(size_t element_count,size_t element_size,size_t padding_size,void (* constructor)(void *),void (* destructor)(void *),void * (* alloc)(size_t),void (* dealloc)(void *,size_t))22479c2e3e6Spatrick __cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size,
22579c2e3e6Spatrick                void (*constructor)(void *), void (*destructor)(void *),
22679c2e3e6Spatrick                void *(*alloc)(size_t), void (*dealloc)(void *, size_t)) {
22779c2e3e6Spatrick   const size_t heap_size = calculate_allocation_size_or_throw(
22879c2e3e6Spatrick       element_count, element_size, padding_size);
22979c2e3e6Spatrick   char* const heap_block = static_cast<char*>(alloc(heap_size));
23079c2e3e6Spatrick   char* vec_base = heap_block;
23179c2e3e6Spatrick 
23279c2e3e6Spatrick   if (NULL != vec_base) {
23379c2e3e6Spatrick     st_heap_block3 heap(dealloc, heap_block, heap_size);
23479c2e3e6Spatrick 
23579c2e3e6Spatrick     //  put the padding before the array elements
23679c2e3e6Spatrick         if ( 0 != padding_size ) {
23779c2e3e6Spatrick             vec_base += padding_size;
23879c2e3e6Spatrick             __set_element_count ( vec_base, element_count );
23979c2e3e6Spatrick         }
24079c2e3e6Spatrick 
24179c2e3e6Spatrick     //  Construct the elements
24279c2e3e6Spatrick         __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
24379c2e3e6Spatrick         heap.release ();    // We're good!
24479c2e3e6Spatrick     }
24579c2e3e6Spatrick 
24679c2e3e6Spatrick     return vec_base;
24779c2e3e6Spatrick }
24879c2e3e6Spatrick 
24979c2e3e6Spatrick 
25079c2e3e6Spatrick // Given the (data) addresses of a destination and a source array, an
25179c2e3e6Spatrick // element count and an element size, call the given copy constructor to
25279c2e3e6Spatrick // copy each element from the source array to the destination array. The
25379c2e3e6Spatrick // copy constructor's arguments are the destination address and source
25479c2e3e6Spatrick // address, respectively. If an exception occurs, call the given destructor
25579c2e3e6Spatrick // (if non-NULL) on each copied element and rethrow. If the destructor
25679c2e3e6Spatrick // throws an exception, call terminate(). The constructor and or destructor
25779c2e3e6Spatrick // pointers may be NULL. If either is NULL, no action is taken when it
25879c2e3e6Spatrick // would have been called.
25979c2e3e6Spatrick 
__cxa_vec_cctor(void * dest_array,void * src_array,size_t element_count,size_t element_size,void (* constructor)(void *,void *),void (* destructor)(void *))26079c2e3e6Spatrick _LIBCXXABI_FUNC_VIS void __cxa_vec_cctor(void *dest_array, void *src_array,
26179c2e3e6Spatrick                                          size_t element_count,
26279c2e3e6Spatrick                                          size_t element_size,
26379c2e3e6Spatrick                                          void (*constructor)(void *, void *),
26479c2e3e6Spatrick                                          void (*destructor)(void *)) {
26579c2e3e6Spatrick     if ( NULL != constructor ) {
26679c2e3e6Spatrick         size_t idx = 0;
26779c2e3e6Spatrick         char *src_ptr  = static_cast<char *>(src_array);
26879c2e3e6Spatrick         char *dest_ptr = static_cast<char *>(dest_array);
26979c2e3e6Spatrick         st_cxa_cleanup cleanup ( dest_array, idx, element_size, destructor );
27079c2e3e6Spatrick 
27179c2e3e6Spatrick         for ( idx = 0; idx < element_count;
27279c2e3e6Spatrick                     ++idx, src_ptr += element_size, dest_ptr += element_size )
27379c2e3e6Spatrick             constructor ( dest_ptr, src_ptr );
27479c2e3e6Spatrick         cleanup.release ();     // We're good!
27579c2e3e6Spatrick     }
27679c2e3e6Spatrick }
27779c2e3e6Spatrick 
27879c2e3e6Spatrick 
27979c2e3e6Spatrick // Given the (data) address of an array, not including any cookie padding,
28079c2e3e6Spatrick // and the number and size of its elements, call the given constructor on
28179c2e3e6Spatrick // each element. If the constructor throws an exception, call the given
28279c2e3e6Spatrick // destructor for any already-constructed elements, and rethrow the
28379c2e3e6Spatrick // exception. If the destructor throws an exception, call terminate(). The
28479c2e3e6Spatrick // constructor and/or destructor pointers may be NULL. If either is NULL,
28579c2e3e6Spatrick // no action is taken when it would have been called.
28679c2e3e6Spatrick _LIBCXXABI_FUNC_VIS void
__cxa_vec_ctor(void * array_address,size_t element_count,size_t element_size,void (* constructor)(void *),void (* destructor)(void *))28779c2e3e6Spatrick __cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size,
28879c2e3e6Spatrick                void (*constructor)(void *), void (*destructor)(void *)) {
28979c2e3e6Spatrick     if ( NULL != constructor ) {
29079c2e3e6Spatrick         size_t idx;
29179c2e3e6Spatrick         char *ptr = static_cast <char *> ( array_address );
29279c2e3e6Spatrick         st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
29379c2e3e6Spatrick 
29479c2e3e6Spatrick     //  Construct the elements
29579c2e3e6Spatrick         for ( idx = 0; idx < element_count; ++idx, ptr += element_size )
29679c2e3e6Spatrick             constructor ( ptr );
29779c2e3e6Spatrick         cleanup.release ();     // We're good!
29879c2e3e6Spatrick     }
29979c2e3e6Spatrick }
30079c2e3e6Spatrick 
30179c2e3e6Spatrick // Given the (data) address of an array, the number of elements, and the
30279c2e3e6Spatrick // size of its elements, call the given destructor on each element. If the
30379c2e3e6Spatrick // destructor throws an exception, rethrow after destroying the remaining
30479c2e3e6Spatrick // elements if possible. If the destructor throws a second exception, call
30579c2e3e6Spatrick // terminate(). The destructor pointer may be NULL, in which case this
30679c2e3e6Spatrick // routine does nothing.
__cxa_vec_dtor(void * array_address,size_t element_count,size_t element_size,void (* destructor)(void *))30779c2e3e6Spatrick _LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address,
30879c2e3e6Spatrick                                         size_t element_count,
30979c2e3e6Spatrick                                         size_t element_size,
31079c2e3e6Spatrick                                         void (*destructor)(void *)) {
31179c2e3e6Spatrick     if ( NULL != destructor ) {
31279c2e3e6Spatrick         char *ptr = static_cast <char *> (array_address);
31379c2e3e6Spatrick         size_t idx = element_count;
31479c2e3e6Spatrick         st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
31579c2e3e6Spatrick         {
31679c2e3e6Spatrick             st_terminate exception_guard (__cxa_uncaught_exception ());
31779c2e3e6Spatrick             ptr +=  element_count * element_size;   // one past the last element
31879c2e3e6Spatrick 
31979c2e3e6Spatrick             while ( idx-- > 0 ) {
32079c2e3e6Spatrick                 ptr -= element_size;
32179c2e3e6Spatrick                 destructor ( ptr );
32279c2e3e6Spatrick             }
32379c2e3e6Spatrick             exception_guard.release (); //  We're good !
32479c2e3e6Spatrick         }
32579c2e3e6Spatrick         cleanup.release ();     // We're still good!
32679c2e3e6Spatrick     }
32779c2e3e6Spatrick }
32879c2e3e6Spatrick 
32979c2e3e6Spatrick // Given the (data) address of an array, the number of elements, and the
33079c2e3e6Spatrick // size of its elements, call the given destructor on each element. If the
33179c2e3e6Spatrick // destructor throws an exception, call terminate(). The destructor pointer
33279c2e3e6Spatrick // may be NULL, in which case this routine does nothing.
__cxa_vec_cleanup(void * array_address,size_t element_count,size_t element_size,void (* destructor)(void *))33379c2e3e6Spatrick _LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address,
33479c2e3e6Spatrick                                            size_t element_count,
33579c2e3e6Spatrick                                            size_t element_size,
33679c2e3e6Spatrick                                            void (*destructor)(void *)) {
33779c2e3e6Spatrick     if ( NULL != destructor ) {
33879c2e3e6Spatrick         char *ptr = static_cast <char *> (array_address);
33979c2e3e6Spatrick         size_t idx = element_count;
34079c2e3e6Spatrick         st_terminate exception_guard;
34179c2e3e6Spatrick 
34279c2e3e6Spatrick         ptr += element_count * element_size;    // one past the last element
34379c2e3e6Spatrick         while ( idx-- > 0 ) {
34479c2e3e6Spatrick             ptr -= element_size;
34579c2e3e6Spatrick             destructor ( ptr );
34679c2e3e6Spatrick             }
34779c2e3e6Spatrick         exception_guard.release ();     // We're done!
34879c2e3e6Spatrick     }
34979c2e3e6Spatrick }
35079c2e3e6Spatrick 
35179c2e3e6Spatrick 
35279c2e3e6Spatrick // If the array_address is NULL, return immediately. Otherwise, given the
35379c2e3e6Spatrick // (data) address of an array, the non-negative size of prefix padding for
35479c2e3e6Spatrick // the cookie, and the size of its elements, call the given destructor on
35579c2e3e6Spatrick // each element, using the cookie to determine the number of elements, and
35679c2e3e6Spatrick // then delete the space by calling ::operator delete[](void *). If the
35779c2e3e6Spatrick // destructor throws an exception, rethrow after (a) destroying the
35879c2e3e6Spatrick // remaining elements, and (b) deallocating the storage. If the destructor
35979c2e3e6Spatrick // throws a second exception, call terminate(). If padding_size is 0, the
36079c2e3e6Spatrick // destructor pointer must be NULL. If the destructor pointer is NULL, no
36179c2e3e6Spatrick // destructor call is to be made.
36279c2e3e6Spatrick //
36379c2e3e6Spatrick // The intent of this function is to permit an implementation to call this
36479c2e3e6Spatrick // function when confronted with an expression of the form delete[] p in
36579c2e3e6Spatrick // the source code, provided that the default deallocation function can be
36679c2e3e6Spatrick // used. Therefore, the semantics of this function are consistent with
36779c2e3e6Spatrick // those required by the standard. The requirement that the deallocation
36879c2e3e6Spatrick // function be called even if the destructor throws an exception derives
36979c2e3e6Spatrick // from the resolution to DR 353 to the C++ standard, which was adopted in
37079c2e3e6Spatrick // April, 2003.
__cxa_vec_delete(void * array_address,size_t element_size,size_t padding_size,void (* destructor)(void *))37179c2e3e6Spatrick _LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address,
37279c2e3e6Spatrick                                           size_t element_size,
37379c2e3e6Spatrick                                           size_t padding_size,
37479c2e3e6Spatrick                                           void (*destructor)(void *)) {
37579c2e3e6Spatrick     __cxa_vec_delete2 ( array_address, element_size, padding_size,
37679c2e3e6Spatrick                destructor, &::operator delete [] );
37779c2e3e6Spatrick }
37879c2e3e6Spatrick 
37979c2e3e6Spatrick // Same as __cxa_vec_delete, except that the given function is used for
38079c2e3e6Spatrick // deallocation instead of the default delete function. If dealloc throws
38179c2e3e6Spatrick // an exception, the result is undefined. The dealloc pointer may not be
38279c2e3e6Spatrick // NULL.
38379c2e3e6Spatrick _LIBCXXABI_FUNC_VIS void
__cxa_vec_delete2(void * array_address,size_t element_size,size_t padding_size,void (* destructor)(void *),void (* dealloc)(void *))38479c2e3e6Spatrick __cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size,
38579c2e3e6Spatrick                   void (*destructor)(void *), void (*dealloc)(void *)) {
38679c2e3e6Spatrick     if ( NULL != array_address ) {
38779c2e3e6Spatrick         char *vec_base   = static_cast <char *> (array_address);
38879c2e3e6Spatrick         char *heap_block = vec_base - padding_size;
38979c2e3e6Spatrick         st_heap_block2 heap ( dealloc, heap_block );
39079c2e3e6Spatrick 
39179c2e3e6Spatrick         if ( 0 != padding_size && NULL != destructor ) // call the destructors
39279c2e3e6Spatrick             __cxa_vec_dtor ( array_address, __get_element_count ( vec_base ),
39379c2e3e6Spatrick                                     element_size, destructor );
39479c2e3e6Spatrick     }
39579c2e3e6Spatrick }
39679c2e3e6Spatrick 
39779c2e3e6Spatrick 
39879c2e3e6Spatrick // Same as __cxa_vec_delete, except that the given function is used for
39979c2e3e6Spatrick // deallocation instead of the default delete function. The deallocation
40079c2e3e6Spatrick // function takes both the object address and its size. If dealloc throws
40179c2e3e6Spatrick // an exception, the result is undefined. The dealloc pointer may not be
40279c2e3e6Spatrick // NULL.
40379c2e3e6Spatrick _LIBCXXABI_FUNC_VIS void
__cxa_vec_delete3(void * array_address,size_t element_size,size_t padding_size,void (* destructor)(void *),void (* dealloc)(void *,size_t))40479c2e3e6Spatrick __cxa_vec_delete3(void *array_address, size_t element_size, size_t padding_size,
40579c2e3e6Spatrick                   void (*destructor)(void *), void (*dealloc)(void *, size_t)) {
40679c2e3e6Spatrick     if ( NULL != array_address ) {
40779c2e3e6Spatrick         char *vec_base   = static_cast <char *> (array_address);
40879c2e3e6Spatrick         char *heap_block = vec_base - padding_size;
40979c2e3e6Spatrick         const size_t element_count = padding_size ? __get_element_count ( vec_base ) : 0;
41079c2e3e6Spatrick         const size_t heap_block_size = element_size * element_count + padding_size;
41179c2e3e6Spatrick         st_heap_block3 heap ( dealloc, heap_block, heap_block_size );
41279c2e3e6Spatrick 
41379c2e3e6Spatrick         if ( 0 != padding_size && NULL != destructor ) // call the destructors
41479c2e3e6Spatrick             __cxa_vec_dtor ( array_address, element_count, element_size, destructor );
41579c2e3e6Spatrick     }
41679c2e3e6Spatrick }
41779c2e3e6Spatrick 
41879c2e3e6Spatrick 
41979c2e3e6Spatrick }  // extern "C"
42079c2e3e6Spatrick 
42179c2e3e6Spatrick }  // abi
422