~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to system/lib/libcxxabi/src/cxa_vector.cpp

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//===-------------------------- cxa_vector.cpp ---------------------------===//
 
2
//
 
3
//                     The LLVM Compiler Infrastructure
 
4
//
 
5
// This file is dual licensed under the MIT and the University of Illinois Open
 
6
// Source Licenses. See LICENSE.TXT for details.
 
7
//
 
8
//  
 
9
//  This file implements the "Array Construction and Destruction APIs"
 
10
//  http://www.codesourcery.com/public/cxx-abi/abi.html#array-ctor
 
11
//  
 
12
//===----------------------------------------------------------------------===//
 
13
 
 
14
#include "cxxabi.h"
 
15
 
 
16
#include <exception>        // for std::terminate
 
17
 
 
18
namespace __cxxabiv1 {
 
19
 
 
20
#pragma mark --Helper routines and classes --
 
21
 
 
22
namespace {
 
23
    inline static size_t __get_element_count ( void *p ) {
 
24
        return static_cast <size_t *> (p)[-1];
 
25
        }
 
26
 
 
27
    inline static void __set_element_count ( void *p, size_t element_count ) {
 
28
        static_cast <size_t *> (p)[-1] = element_count;
 
29
        }
 
30
 
 
31
 
 
32
//  A pair of classes to simplify exception handling and control flow.
 
33
//  They get passed a block of memory in the constructor, and unless the
 
34
//  'release' method is called, they deallocate the memory in the destructor.
 
35
//  Preferred usage is to allocate some memory, attach it to one of these objects,
 
36
//  and then, when all the operations to set up the memory block have succeeded,
 
37
//  call 'release'. If any of the setup operations fail, or an exception is
 
38
//  thrown, then the block is automatically deallocated.
 
39
//
 
40
//  The only difference between these two classes is the signature for the
 
41
//  deallocation function (to match new2/new3 and delete2/delete3.
 
42
    class st_heap_block2 {
 
43
    public:
 
44
        typedef void (*dealloc_f)(void *);
 
45
        
 
46
        st_heap_block2 ( dealloc_f dealloc, void *ptr ) 
 
47
            : dealloc_ ( dealloc ), ptr_ ( ptr ), enabled_ ( true ) {}
 
48
        ~st_heap_block2 () { if ( enabled_ ) dealloc_ ( ptr_ ) ; }
 
49
        void release () { enabled_ = false; }
 
50
    
 
51
    private:
 
52
        dealloc_f dealloc_;
 
53
        void *ptr_;
 
54
        bool enabled_;
 
55
    };
 
56
    
 
57
    class st_heap_block3 {
 
58
    public:
 
59
        typedef void (*dealloc_f)(void *, size_t);
 
60
        
 
61
        st_heap_block3 ( dealloc_f dealloc, void *ptr, size_t size ) 
 
62
            : dealloc_ ( dealloc ), ptr_ ( ptr ), size_ ( size ), enabled_ ( true ) {}
 
63
        ~st_heap_block3 () { if ( enabled_ ) dealloc_ ( ptr_, size_ ) ; }
 
64
        void release () { enabled_ = false; }
 
65
    
 
66
    private:
 
67
        dealloc_f dealloc_;
 
68
        void *ptr_;
 
69
        size_t size_;
 
70
        bool enabled_;
 
71
    };
 
72
 
 
73
    class st_cxa_cleanup {
 
74
    public:
 
75
        typedef void (*destruct_f)(void *);
 
76
        
 
77
        st_cxa_cleanup ( void *ptr, size_t &idx, size_t element_size, destruct_f destructor )
 
78
            : ptr_ ( ptr ), idx_ ( idx ), element_size_ ( element_size ), 
 
79
                destructor_ ( destructor ), enabled_ ( true ) {}
 
80
        ~st_cxa_cleanup () {
 
81
            if ( enabled_ ) 
 
82
                __cxa_vec_cleanup ( ptr_, idx_, element_size_, destructor_ );
 
83
            }
 
84
        
 
85
        void release () { enabled_ = false; }
 
86
    
 
87
    private:
 
88
        void *ptr_;
 
89
        size_t &idx_;
 
90
        size_t element_size_;
 
91
        destruct_f destructor_;
 
92
        bool enabled_;
 
93
    };
 
94
    
 
95
    class st_terminate {
 
96
    public:
 
97
        st_terminate ( bool enabled = true ) : enabled_ ( enabled ) {}
 
98
        ~st_terminate () { if ( enabled_ ) std::terminate (); }
 
99
        void release () { enabled_ = false; }
 
100
    private:
 
101
        bool enabled_ ;
 
102
    };
 
103
}
 
104
 
 
105
#pragma mark --Externally visible routines--
 
106
 
 
107
extern "C" {
 
108
 
 
109
// Equivalent to
 
110
// 
 
111
//   __cxa_vec_new2(element_count, element_size, padding_size, constructor,
 
112
//                  destructor, &::operator new[], &::operator delete[])
 
113
void* __cxa_vec_new(
 
114
    size_t element_count, size_t element_size, size_t padding_size, 
 
115
        void (*constructor)(void*), void (*destructor)(void*) ) {
 
116
 
 
117
    return __cxa_vec_new2 ( element_count, element_size, padding_size, 
 
118
        constructor, destructor, &::operator new [], &::operator delete [] );
 
119
}
 
120
 
 
121
 
 
122
 
 
123
// Given the number and size of elements for an array and the non-negative
 
124
// size of prefix padding for a cookie, allocate space (using alloc) for
 
125
// the array preceded by the specified padding, initialize the cookie if
 
126
// the padding is non-zero, and call the given constructor on each element.
 
127
// Return the address of the array proper, after the padding.
 
128
// 
 
129
// If alloc throws an exception, rethrow the exception. If alloc returns
 
130
// NULL, return NULL. If the constructor throws an exception, call
 
131
// destructor for any already constructed elements, and rethrow the
 
132
// exception. If the destructor throws an exception, call std::terminate.
 
133
// 
 
134
// The constructor may be NULL, in which case it must not be called. If the
 
135
// padding_size is zero, the destructor may be NULL; in that case it must
 
136
// not be called.
 
137
// 
 
138
// Neither alloc nor dealloc may be NULL.
 
139
void* __cxa_vec_new2(
 
140
    size_t element_count, size_t element_size, size_t padding_size,
 
141
        void  (*constructor)(void*), void  (*destructor)(void*),
 
142
        void* (*alloc)(size_t), void  (*dealloc)(void*) ) {
 
143
 
 
144
    const size_t heap_size = element_count * element_size + padding_size;
 
145
    char * const heap_block = static_cast<char *> ( alloc ( heap_size ));
 
146
    char *vec_base = heap_block;
 
147
    
 
148
    if ( NULL != vec_base ) {
 
149
        st_heap_block2 heap ( dealloc, heap_block );
 
150
 
 
151
    //  put the padding before the array elements
 
152
        if ( 0 != padding_size ) {
 
153
            vec_base += padding_size;
 
154
            __set_element_count ( vec_base, element_count );
 
155
        }
 
156
            
 
157
    //  Construct the elements
 
158
        __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
 
159
        heap.release ();    // We're good!
 
160
    }
 
161
    
 
162
    return vec_base;
 
163
}
 
164
 
 
165
 
 
166
// Same as __cxa_vec_new2 except that the deallocation function takes both
 
167
// the object address and its size.
 
168
void* __cxa_vec_new3(
 
169
    size_t element_count, size_t element_size, size_t padding_size,
 
170
        void  (*constructor)(void*), void  (*destructor)(void*),
 
171
        void* (*alloc)(size_t), void  (*dealloc)(void*, size_t) ) {
 
172
 
 
173
    const size_t heap_size = element_count * element_size + padding_size;
 
174
    char * const heap_block = static_cast<char *> ( alloc ( heap_size ));
 
175
    char *vec_base = heap_block;
 
176
    
 
177
    if ( NULL != vec_base ) {
 
178
        st_heap_block3 heap ( dealloc, heap_block, heap_size );
 
179
 
 
180
    //  put the padding before the array elements
 
181
        if ( 0 != padding_size ) {
 
182
            vec_base += padding_size;
 
183
            __set_element_count ( vec_base, element_count );
 
184
        }
 
185
            
 
186
    //  Construct the elements
 
187
        __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
 
188
        heap.release ();    // We're good!
 
189
    }
 
190
    
 
191
    return vec_base;
 
192
}
 
193
 
 
194
 
 
195
// Given the (data) addresses of a destination and a source array, an
 
196
// element count and an element size, call the given copy constructor to
 
197
// copy each element from the source array to the destination array. The
 
198
// copy constructor's arguments are the destination address and source
 
199
// address, respectively. If an exception occurs, call the given destructor
 
200
// (if non-NULL) on each copied element and rethrow. If the destructor
 
201
// throws an exception, call terminate(). The constructor and or destructor
 
202
// pointers may be NULL. If either is NULL, no action is taken when it
 
203
// would have been called.
 
204
 
 
205
void __cxa_vec_cctor( void*  dest_array, void*  src_array, 
 
206
    size_t element_count, size_t element_size, 
 
207
        void  (*constructor) (void*, void*), void  (*destructor)(void*) ) {
 
208
 
 
209
    if ( NULL != constructor ) {
 
210
        size_t idx = 0;
 
211
        char *src_ptr  = static_cast<char *>(src_array);
 
212
        char *dest_ptr = static_cast<char *>(dest_array);
 
213
        st_cxa_cleanup cleanup ( dest_array, idx, element_size, destructor );        
 
214
 
 
215
        for ( idx = 0; idx < element_count; 
 
216
                    ++idx, src_ptr += element_size, dest_ptr += element_size )
 
217
            constructor ( dest_ptr, src_ptr );
 
218
        cleanup.release ();     // We're good!
 
219
    }
 
220
}
 
221
 
 
222
 
 
223
// Given the (data) address of an array, not including any cookie padding,
 
224
// and the number and size of its elements, call the given constructor on
 
225
// each element. If the constructor throws an exception, call the given
 
226
// destructor for any already-constructed elements, and rethrow the
 
227
// exception. If the destructor throws an exception, call terminate(). The
 
228
// constructor and/or destructor pointers may be NULL. If either is NULL,
 
229
// no action is taken when it would have been called.
 
230
void __cxa_vec_ctor(
 
231
    void*  array_address, size_t element_count, size_t element_size, 
 
232
       void (*constructor)(void*), void (*destructor)(void*) ) {
 
233
 
 
234
    if ( NULL != constructor ) {
 
235
        size_t idx;
 
236
        char *ptr = static_cast <char *> ( array_address );
 
237
        st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );        
 
238
        
 
239
    //  Construct the elements
 
240
        for ( idx = 0; idx < element_count; ++idx, ptr += element_size )
 
241
            constructor ( ptr );
 
242
        cleanup.release ();     // We're good!
 
243
    }
 
244
}
 
245
 
 
246
// Given the (data) address of an array, the number of elements, and the
 
247
// size of its elements, call the given destructor on each element. If the
 
248
// destructor throws an exception, rethrow after destroying the remaining
 
249
// elements if possible. If the destructor throws a second exception, call
 
250
// terminate(). The destructor pointer may be NULL, in which case this
 
251
// routine does nothing.
 
252
void __cxa_vec_dtor(
 
253
    void*  array_address, size_t element_count, size_t element_size, 
 
254
       void (*destructor)(void*) ) {
 
255
    
 
256
    if ( NULL != destructor ) {
 
257
        char *ptr = static_cast <char *> (array_address);
 
258
        size_t idx = element_count;
 
259
        st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );        
 
260
        {
 
261
            st_terminate exception_guard (__cxa_uncaught_exception ());
 
262
            ptr +=  element_count * element_size;   // one past the last element
 
263
 
 
264
            while ( idx-- > 0 ) {
 
265
                ptr -= element_size;
 
266
                destructor ( ptr );
 
267
            }
 
268
            exception_guard.release (); //  We're good !
 
269
        }
 
270
        cleanup.release ();     // We're still good!
 
271
    }
 
272
}
 
273
 
 
274
// Given the (data) address of an array, the number of elements, and the
 
275
// size of its elements, call the given destructor on each element. If the
 
276
// destructor throws an exception, call terminate(). The destructor pointer
 
277
// may be NULL, in which case this routine does nothing.
 
278
void __cxa_vec_cleanup( void* array_address, size_t element_count,
 
279
        size_t element_size, void  (*destructor)(void*) ) {
 
280
 
 
281
    if ( NULL != destructor ) {
 
282
        char *ptr = static_cast <char *> (array_address);
 
283
        size_t idx = element_count;
 
284
        st_terminate exception_guard;
 
285
        
 
286
        ptr += element_count * element_size;    // one past the last element
 
287
        while ( idx-- > 0 ) {
 
288
            ptr -= element_size;
 
289
            destructor ( ptr );
 
290
            }
 
291
        exception_guard.release ();     // We're done!
 
292
    }
 
293
}
 
294
 
 
295
 
 
296
// If the array_address is NULL, return immediately. Otherwise, given the
 
297
// (data) address of an array, the non-negative size of prefix padding for
 
298
// the cookie, and the size of its elements, call the given destructor on
 
299
// each element, using the cookie to determine the number of elements, and
 
300
// then delete the space by calling ::operator delete[](void *). If the
 
301
// destructor throws an exception, rethrow after (a) destroying the
 
302
// remaining elements, and (b) deallocating the storage. If the destructor
 
303
// throws a second exception, call terminate(). If padding_size is 0, the
 
304
// destructor pointer must be NULL. If the destructor pointer is NULL, no
 
305
// destructor call is to be made.
 
306
// 
 
307
// The intent of this function is to permit an implementation to call this
 
308
// function when confronted with an expression of the form delete[] p in
 
309
// the source code, provided that the default deallocation function can be
 
310
// used. Therefore, the semantics of this function are consistent with
 
311
// those required by the standard. The requirement that the deallocation
 
312
// function be called even if the destructor throws an exception derives
 
313
// from the resolution to DR 353 to the C++ standard, which was adopted in
 
314
// April, 2003.
 
315
void __cxa_vec_delete( void* array_address,
 
316
        size_t element_size, size_t padding_size, void  (*destructor)(void*) ) {
 
317
 
 
318
    __cxa_vec_delete2 ( array_address, element_size, padding_size,
 
319
               destructor, &::operator delete [] );
 
320
}
 
321
 
 
322
 
 
323
// Same as __cxa_vec_delete, except that the given function is used for
 
324
// deallocation instead of the default delete function. If dealloc throws
 
325
// an exception, the result is undefined. The dealloc pointer may not be
 
326
// NULL.
 
327
void __cxa_vec_delete2( void* array_address,
 
328
        size_t element_size, size_t padding_size, 
 
329
        void  (*destructor)(void*), void  (*dealloc)(void*) ) {
 
330
 
 
331
    if ( NULL != array_address ) {
 
332
        char *vec_base   = static_cast <char *> (array_address);
 
333
        char *heap_block = vec_base - padding_size;
 
334
        st_heap_block2 heap ( dealloc, heap_block );
 
335
        
 
336
        if ( 0 != padding_size && NULL != destructor ) // call the destructors
 
337
            __cxa_vec_dtor ( array_address, __get_element_count ( vec_base ), 
 
338
                                    element_size, destructor );
 
339
    }
 
340
}
 
341
 
 
342
 
 
343
// Same as __cxa_vec_delete, except that the given function is used for
 
344
// deallocation instead of the default delete function. The deallocation
 
345
// function takes both the object address and its size. If dealloc throws
 
346
// an exception, the result is undefined. The dealloc pointer may not be
 
347
// NULL.
 
348
void __cxa_vec_delete3( void* array_address, 
 
349
        size_t element_size, size_t padding_size, 
 
350
        void  (*destructor)(void*), void  (*dealloc) (void*, size_t)) {
 
351
 
 
352
    if ( NULL != array_address ) {
 
353
        char *vec_base   = static_cast <char *> (array_address);
 
354
        char *heap_block = vec_base - padding_size;
 
355
        const size_t element_count = padding_size ? __get_element_count ( vec_base ) : 0;
 
356
        const size_t heap_block_size = element_size * element_count + padding_size;
 
357
        st_heap_block3 heap ( dealloc, heap_block, heap_block_size );
 
358
 
 
359
        if ( 0 != padding_size && NULL != destructor ) // call the destructors
 
360
            __cxa_vec_dtor ( array_address, element_count, element_size, destructor );
 
361
    }
 
362
}
 
363
 
 
364
 
 
365
}  // extern "C"
 
366
 
 
367
}  // abi