481 lines
14 KiB
Diff
481 lines
14 KiB
Diff
r220201 | rguenth | 2015-01-28 10:53:39 +0100 (Wed, 28 Jan 2015) | 9 lines
|
|
|
|
2015-01-28 Richard Biener <rguenther@suse.de>
|
|
|
|
PR libstdc++/64798
|
|
* libsupc++/eh_alloc.cc (struct allocated_entry): Align
|
|
data member.
|
|
(pool::allocate): Adjust allocation size and alignment to
|
|
that change.
|
|
(pool::free): Adjust pointer offsetting.
|
|
|
|
r219988 | rguenth | 2015-01-22 10:21:48 +0100 (Thu, 22 Jan 2015) | 20 lines
|
|
|
|
2015-01-22 Richard Biener <rguenther@suse.de>
|
|
|
|
PR libstdc++/64535
|
|
* libsupc++/eh_alloc.cc: Include new.
|
|
(bitmask_type): Remove.
|
|
(one_buffer): Likewise.
|
|
(emergency_buffer): Likewise.
|
|
(emergency_used): Likewise.
|
|
(dependents_buffer): Likewise.
|
|
(dependents_used): Likewise.
|
|
(class pool): New custom fixed-size arena, variable size object
|
|
allocator.
|
|
(emergency_pool): New global.
|
|
(__cxxabiv1::__cxa_allocate_exception): Use new emergency_pool.
|
|
(__cxxabiv1::__cxa_free_exception): Likewise.
|
|
(__cxxabiv1::__cxa_allocate_dependent_exception): Likewise.
|
|
(__cxxabiv1::__cxa_free_dependent_exception): Likewise.
|
|
|
|
* g++.old-deja/g++.eh/badalloc1.C: Adjust.
|
|
|
|
|
|
*** gcc-4_8-branch/libstdc++-v3/libsupc++/eh_alloc.cc Mon Feb 3 10:38:52 2014
|
|
--- trunk/libstdc++-v3/libsupc++/eh_alloc.cc Wed Jan 28 12:37:44 2015
|
|
***************
|
|
*** 1,5 ****
|
|
// -*- C++ -*- Allocate exception objects.
|
|
! // Copyright (C) 2001-2013 Free Software Foundation, Inc.
|
|
//
|
|
// This file is part of GCC.
|
|
//
|
|
--- 1,5 ----
|
|
// -*- C++ -*- Allocate exception objects.
|
|
! // Copyright (C) 2001-2015 Free Software Foundation, Inc.
|
|
//
|
|
// This file is part of GCC.
|
|
//
|
|
***************
|
|
*** 34,39 ****
|
|
--- 34,40 ----
|
|
#include <exception>
|
|
#include "unwind-cxx.h"
|
|
#include <ext/concurrence.h>
|
|
+ #include <new>
|
|
|
|
#if _GLIBCXX_HOSTED
|
|
using std::free;
|
|
***************
|
|
*** 72,133 ****
|
|
# define EMERGENCY_OBJ_COUNT 4
|
|
#endif
|
|
|
|
- #if INT_MAX == 32767 || EMERGENCY_OBJ_COUNT <= 32
|
|
- typedef unsigned int bitmask_type;
|
|
- #else
|
|
- #if defined (_GLIBCXX_LLP64)
|
|
- typedef unsigned long long bitmask_type;
|
|
- #else
|
|
- typedef unsigned long bitmask_type;
|
|
- #endif
|
|
- #endif
|
|
|
|
|
|
! typedef char one_buffer[EMERGENCY_OBJ_SIZE] __attribute__((aligned));
|
|
! static one_buffer emergency_buffer[EMERGENCY_OBJ_COUNT];
|
|
! static bitmask_type emergency_used;
|
|
|
|
! static __cxa_dependent_exception dependents_buffer[EMERGENCY_OBJ_COUNT];
|
|
! static bitmask_type dependents_used;
|
|
|
|
! namespace
|
|
! {
|
|
! // A single mutex controlling emergency allocations.
|
|
! __gnu_cxx::__mutex emergency_mutex;
|
|
! }
|
|
|
|
! extern "C" void *
|
|
! __cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) _GLIBCXX_NOTHROW
|
|
! {
|
|
! void *ret;
|
|
|
|
! thrown_size += sizeof (__cxa_refcounted_exception);
|
|
! ret = malloc (thrown_size);
|
|
|
|
! if (! ret)
|
|
{
|
|
__gnu_cxx::__scoped_lock sentry(emergency_mutex);
|
|
|
|
! bitmask_type used = emergency_used;
|
|
! unsigned int which = 0;
|
|
!
|
|
! if (thrown_size > EMERGENCY_OBJ_SIZE)
|
|
! goto failed;
|
|
! while (used & 1)
|
|
{
|
|
! used >>= 1;
|
|
! if (++which >= EMERGENCY_OBJ_COUNT)
|
|
! goto failed;
|
|
}
|
|
|
|
! emergency_used |= (bitmask_type)1 << which;
|
|
! ret = &emergency_buffer[which][0];
|
|
|
|
! failed:;
|
|
|
|
! if (!ret)
|
|
! std::terminate ();
|
|
! }
|
|
|
|
memset (ret, 0, sizeof (__cxa_refcounted_exception));
|
|
|
|
--- 73,262 ----
|
|
# define EMERGENCY_OBJ_COUNT 4
|
|
#endif
|
|
|
|
|
|
+ namespace
|
|
+ {
|
|
+ // A fixed-size heap, variable size object allocator
|
|
+ class pool
|
|
+ {
|
|
+ public:
|
|
+ pool();
|
|
|
|
! void *allocate (std::size_t);
|
|
! void free (void *);
|
|
|
|
! bool in_pool (void *);
|
|
|
|
! private:
|
|
! struct free_entry {
|
|
! std::size_t size;
|
|
! free_entry *next;
|
|
! };
|
|
! struct allocated_entry {
|
|
! std::size_t size;
|
|
! char data[] __attribute__((aligned));
|
|
! };
|
|
!
|
|
! // A single mutex controlling emergency allocations.
|
|
! __gnu_cxx::__mutex emergency_mutex;
|
|
!
|
|
! // The free-list
|
|
! free_entry *first_free_entry;
|
|
! // The arena itself - we need to keep track of these only
|
|
! // to implement in_pool.
|
|
! char *arena;
|
|
! std::size_t arena_size;
|
|
! };
|
|
|
|
! pool::pool()
|
|
! {
|
|
! // Allocate the arena - we could add a GLIBCXX_EH_ARENA_SIZE environment
|
|
! // to make this tunable.
|
|
! arena_size = (EMERGENCY_OBJ_SIZE * EMERGENCY_OBJ_COUNT
|
|
! + EMERGENCY_OBJ_COUNT * sizeof (__cxa_dependent_exception));
|
|
! arena = (char *)malloc (arena_size);
|
|
! if (!arena)
|
|
! {
|
|
! // If the allocation failed go without an emergency pool.
|
|
! arena_size = 0;
|
|
! first_free_entry = NULL;
|
|
! return;
|
|
! }
|
|
|
|
! // Populate the free-list with a single entry covering the whole arena
|
|
! first_free_entry = reinterpret_cast <free_entry *> (arena);
|
|
! new (first_free_entry) free_entry;
|
|
! first_free_entry->size = arena_size;
|
|
! first_free_entry->next = NULL;
|
|
! }
|
|
|
|
! void *pool::allocate (std::size_t size)
|
|
{
|
|
__gnu_cxx::__scoped_lock sentry(emergency_mutex);
|
|
+ // We need an additional size_t member plus the padding to
|
|
+ // ensure proper alignment of data.
|
|
+ size += offsetof (allocated_entry, data);
|
|
+ // And we need to at least hand out objects of the size of
|
|
+ // a freelist entry.
|
|
+ if (size < sizeof (free_entry))
|
|
+ size = sizeof (free_entry);
|
|
+ // And we need to align objects we hand out to the maximum
|
|
+ // alignment required on the target (this really aligns the
|
|
+ // tail which will become a new freelist entry).
|
|
+ size = ((size + __alignof__ (allocated_entry::data) - 1)
|
|
+ & ~(__alignof__ (allocated_entry::data) - 1));
|
|
+ // Search for an entry of proper size on the freelist.
|
|
+ free_entry **e;
|
|
+ for (e = &first_free_entry;
|
|
+ *e && (*e)->size < size;
|
|
+ e = &(*e)->next)
|
|
+ ;
|
|
+ if (!*e)
|
|
+ return NULL;
|
|
+ allocated_entry *x;
|
|
+ if ((*e)->size - size >= sizeof (free_entry))
|
|
+ {
|
|
+ // Slit block if it is too large.
|
|
+ free_entry *f = reinterpret_cast <free_entry *>
|
|
+ (reinterpret_cast <char *> (*e) + size);
|
|
+ std::size_t sz = (*e)->size;
|
|
+ free_entry *next = (*e)->next;
|
|
+ new (f) free_entry;
|
|
+ f->next = next;
|
|
+ f->size = sz - size;
|
|
+ x = reinterpret_cast <allocated_entry *> (*e);
|
|
+ new (x) allocated_entry;
|
|
+ x->size = size;
|
|
+ *e = f;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ // Exact size match or too small overhead for a free entry.
|
|
+ std::size_t sz = (*e)->size;
|
|
+ free_entry *next = (*e)->next;
|
|
+ x = reinterpret_cast <allocated_entry *> (*e);
|
|
+ new (x) allocated_entry;
|
|
+ x->size = sz;
|
|
+ *e = next;
|
|
+ }
|
|
+ return &x->data;
|
|
+ }
|
|
|
|
! void pool::free (void *data)
|
|
! {
|
|
! __gnu_cxx::__scoped_lock sentry(emergency_mutex);
|
|
! allocated_entry *e = reinterpret_cast <allocated_entry *>
|
|
! (reinterpret_cast <char *> (data) - offsetof (allocated_entry, data));
|
|
! std::size_t sz = e->size;
|
|
! if (!first_free_entry)
|
|
! {
|
|
! // If the free list is empty just put the entry there.
|
|
! free_entry *f = reinterpret_cast <free_entry *> (e);
|
|
! new (f) free_entry;
|
|
! f->size = sz;
|
|
! f->next = NULL;
|
|
! first_free_entry = f;
|
|
! }
|
|
! else if (reinterpret_cast <char *> (e) + sz
|
|
! == reinterpret_cast <char *> (first_free_entry))
|
|
! {
|
|
! // Check if we can merge with the first free entry being right
|
|
! // after us.
|
|
! free_entry *f = reinterpret_cast <free_entry *> (e);
|
|
! new (f) free_entry;
|
|
! f->size = sz + first_free_entry->size;
|
|
! f->next = first_free_entry->next;
|
|
! first_free_entry = f;
|
|
! }
|
|
! else
|
|
{
|
|
! // Else search for a free item we can merge with at its end.
|
|
! free_entry **fe;
|
|
! for (fe = &first_free_entry;
|
|
! (*fe)->next
|
|
! && (reinterpret_cast <char *> ((*fe)->next)
|
|
! > reinterpret_cast <char *> (e) + sz);
|
|
! fe = &(*fe)->next)
|
|
! ;
|
|
! if (reinterpret_cast <char *> (*fe) + (*fe)->size
|
|
! == reinterpret_cast <char *> (e))
|
|
! /* Merge with the freelist entry. */
|
|
! (*fe)->size += sz;
|
|
! else
|
|
! {
|
|
! // Else put it after it which keeps the freelist sorted.
|
|
! free_entry *f = reinterpret_cast <free_entry *> (e);
|
|
! new (f) free_entry;
|
|
! f->size = sz;
|
|
! f->next = (*fe)->next;
|
|
! (*fe)->next = f;
|
|
! }
|
|
}
|
|
+ }
|
|
|
|
! bool pool::in_pool (void *ptr)
|
|
! {
|
|
! char *p = reinterpret_cast <char *> (ptr);
|
|
! return (p > arena
|
|
! && p < arena + arena_size);
|
|
! }
|
|
|
|
! pool emergency_pool;
|
|
! }
|
|
|
|
! extern "C" void *
|
|
! __cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) _GLIBCXX_NOTHROW
|
|
! {
|
|
! void *ret;
|
|
!
|
|
! thrown_size += sizeof (__cxa_refcounted_exception);
|
|
! ret = malloc (thrown_size);
|
|
!
|
|
! if (!ret)
|
|
! ret = emergency_pool.allocate (thrown_size);
|
|
!
|
|
! if (!ret)
|
|
! std::terminate ();
|
|
|
|
memset (ret, 0, sizeof (__cxa_refcounted_exception));
|
|
|
|
***************
|
|
*** 138,156 ****
|
|
extern "C" void
|
|
__cxxabiv1::__cxa_free_exception(void *vptr) _GLIBCXX_NOTHROW
|
|
{
|
|
! char *base = (char *) emergency_buffer;
|
|
! char *ptr = (char *) vptr;
|
|
! if (ptr >= base
|
|
! && ptr < base + sizeof (emergency_buffer))
|
|
! {
|
|
! const unsigned int which
|
|
! = (unsigned) (ptr - base) / EMERGENCY_OBJ_SIZE;
|
|
!
|
|
! __gnu_cxx::__scoped_lock sentry(emergency_mutex);
|
|
! emergency_used &= ~((bitmask_type)1 << which);
|
|
! }
|
|
else
|
|
! free (ptr - sizeof (__cxa_refcounted_exception));
|
|
}
|
|
|
|
|
|
--- 267,277 ----
|
|
extern "C" void
|
|
__cxxabiv1::__cxa_free_exception(void *vptr) _GLIBCXX_NOTHROW
|
|
{
|
|
! char *ptr = (char *) vptr - sizeof (__cxa_refcounted_exception);
|
|
! if (emergency_pool.in_pool (ptr))
|
|
! emergency_pool.free (ptr);
|
|
else
|
|
! free (ptr);
|
|
}
|
|
|
|
|
|
***************
|
|
*** 163,189 ****
|
|
(malloc (sizeof (__cxa_dependent_exception)));
|
|
|
|
if (!ret)
|
|
! {
|
|
! __gnu_cxx::__scoped_lock sentry(emergency_mutex);
|
|
!
|
|
! bitmask_type used = dependents_used;
|
|
! unsigned int which = 0;
|
|
!
|
|
! while (used & 1)
|
|
! {
|
|
! used >>= 1;
|
|
! if (++which >= EMERGENCY_OBJ_COUNT)
|
|
! goto failed;
|
|
! }
|
|
|
|
! dependents_used |= (bitmask_type)1 << which;
|
|
! ret = &dependents_buffer[which];
|
|
!
|
|
! failed:;
|
|
!
|
|
! if (!ret)
|
|
! std::terminate ();
|
|
! }
|
|
|
|
memset (ret, 0, sizeof (__cxa_dependent_exception));
|
|
|
|
--- 284,294 ----
|
|
(malloc (sizeof (__cxa_dependent_exception)));
|
|
|
|
if (!ret)
|
|
! ret = static_cast <__cxa_dependent_exception*>
|
|
! (emergency_pool.allocate (sizeof (__cxa_dependent_exception)));
|
|
|
|
! if (!ret)
|
|
! std::terminate ();
|
|
|
|
memset (ret, 0, sizeof (__cxa_dependent_exception));
|
|
|
|
***************
|
|
*** 195,211 ****
|
|
__cxxabiv1::__cxa_free_dependent_exception
|
|
(__cxa_dependent_exception *vptr) _GLIBCXX_NOTHROW
|
|
{
|
|
! char *base = (char *) dependents_buffer;
|
|
! char *ptr = (char *) vptr;
|
|
! if (ptr >= base
|
|
! && ptr < base + sizeof (dependents_buffer))
|
|
! {
|
|
! const unsigned int which
|
|
! = (unsigned) (ptr - base) / sizeof (__cxa_dependent_exception);
|
|
!
|
|
! __gnu_cxx::__scoped_lock sentry(emergency_mutex);
|
|
! dependents_used &= ~((bitmask_type)1 << which);
|
|
! }
|
|
else
|
|
free (vptr);
|
|
}
|
|
--- 300,307 ----
|
|
__cxxabiv1::__cxa_free_dependent_exception
|
|
(__cxa_dependent_exception *vptr) _GLIBCXX_NOTHROW
|
|
{
|
|
! if (emergency_pool.in_pool (vptr))
|
|
! emergency_pool.free (vptr);
|
|
else
|
|
free (vptr);
|
|
}
|
|
*** gcc-4_8-branch/gcc/testsuite/g++.old-deja/g++.eh/badalloc1.C Mon Mar 18 09:44:40 2013
|
|
--- trunk/gcc/testsuite/g++.old-deja/g++.eh/badalloc1.C Thu Jan 22 10:58:02 2015
|
|
***************
|
|
*** 3,9 ****
|
|
// itself call malloc(), and will fail if there is no more
|
|
// memory available.
|
|
// { dg-do run { xfail { { xstormy16-*-* *-*-darwin[3-7]* } || vxworks_rtp } } }
|
|
! // Copyright (C) 2000, 2002, 2003, 2010, 2012 Free Software Foundation, Inc.
|
|
// Contributed by Nathan Sidwell 6 June 2000 <nathan@codesourcery.com>
|
|
|
|
// Check we can throw a bad_alloc exception when malloc dies.
|
|
--- 3,9 ----
|
|
// itself call malloc(), and will fail if there is no more
|
|
// memory available.
|
|
// { dg-do run { xfail { { xstormy16-*-* *-*-darwin[3-7]* } || vxworks_rtp } } }
|
|
! // Copyright (C) 2000, 2002, 2003, 2010, 2012, 2014 Free Software Foundation, Inc.
|
|
// Contributed by Nathan Sidwell 6 June 2000 <nathan@codesourcery.com>
|
|
|
|
// Check we can throw a bad_alloc exception when malloc dies.
|
|
***************
|
|
*** 12,29 ****
|
|
extern "C" void abort();
|
|
extern "C" void *memcpy(void *, const void *, size_t);
|
|
|
|
// Assume that STACK_SIZE defined implies a system that does not have a
|
|
// large data space either, and additionally that we're not linking against
|
|
// a shared libstdc++ (which requires quite a bit more initialization space).
|
|
#ifdef STACK_SIZE
|
|
! const int arena_size = 256;
|
|
#else
|
|
#if defined(__FreeBSD__) || defined(__sun__) || defined(__hpux__)
|
|
// FreeBSD, Solaris and HP-UX require even more space at initialization time.
|
|
// FreeBSD 5 now requires over 131072 bytes.
|
|
! const int arena_size = 262144;
|
|
#else
|
|
! const int arena_size = 32768;
|
|
#endif
|
|
#endif
|
|
|
|
--- 12,35 ----
|
|
extern "C" void abort();
|
|
extern "C" void *memcpy(void *, const void *, size_t);
|
|
|
|
+ // libstdc++ requires a large initialization time allocation for the
|
|
+ // emergency EH allocation pool. Add that to the arena size.
|
|
+
|
|
// Assume that STACK_SIZE defined implies a system that does not have a
|
|
// large data space either, and additionally that we're not linking against
|
|
// a shared libstdc++ (which requires quite a bit more initialization space).
|
|
#ifdef STACK_SIZE
|
|
! const int arena_size = 256 + 8 * 128;
|
|
#else
|
|
#if defined(__FreeBSD__) || defined(__sun__) || defined(__hpux__)
|
|
// FreeBSD, Solaris and HP-UX require even more space at initialization time.
|
|
// FreeBSD 5 now requires over 131072 bytes.
|
|
! const int arena_size = 262144 + 72 * 1024;
|
|
#else
|
|
! // Because pointers make up the bulk of our exception-initialization
|
|
! // allocations, we scale by the pointer size from the original
|
|
! // 32-bit-systems-based estimate.
|
|
! const int arena_size = 32768 * ((sizeof (void *) + 3)/4) + 72 * 1024;
|
|
#endif
|
|
#endif
|
|
|