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