This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] malloca v2
On Sat, Jan 12, 2013 at 06:22:53PM +0100, OndÅej BÃlka wrote:
> Hello,
> I realized that I can make simpler and faster malloca than my previous
> attempt.
>
>
> You need to write MALLOCA_INIT(); at function header.
> Allocation is done my malloca(n) which allocates at most __MAX_ALLOCA_CUTOFF
> bytes per stack frame.
> For deallocation it now suffices to call freeall() which frees all
> elements mallocated in frame.
I realized, that in glibc we do not have to deallocate manualy. It suffices to use
cleanup attribute which is supported since gcc 3.4. I could portably support
it in c++ with destructors.
Here is updated version.
/* Safe automatic memory allocation.
Copyright (C) 2012 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>. */
#ifndef _MALLOCA_H
#define _MALLOCA_H
#include <alloca.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/* malloca(N) is a safe variant of alloca(N). It allocates N bytes of
memory allocated on the stack until stack frame has __MAX_ALLOCA_CUTOFF
bytes and heap otherwise. When memory cannot be allocated from heap
malloca aborts.
You must write MALLOCA_INIT() at start of each function that uses malloca.
Memory is freed automaticaly.
You need at least gcc-3.4 to use this header. */
/* TODO: switch to later case when -fomit-frame-pointer.*/
#define _MALLOCA_INIT() void *__malloca_gc __attribute__ ((__cleanup__ (__ifreeall))) = NULL;
#if 1
#define MALLOCA_INIT() _MALLOCA_INIT ()
#define __FRAME_ADDRESS __builtin_frame_address (0)
#else
#define MALLOCA_INIT() _MALLOCA_INIT (); void *__frame_address = &__frame_address;
#define __FRAME_ADDRESS __frame_address
#endif
#ifdef _STACK_GROWS_DOWN
#define __MALLOCA_UB __FRAME_ADDRESS
#define __MALLOCA_LB stackinfo_get_sp ()
#endif
#ifdef _STACK_GROWS_UP
#define __MALLOCA_UB stackinfo_get_sp ()
#define __MALLOCA_LB __FRAME_ADDRESS
#endif
#ifndef __MAX_ALLOCA_CUTOFF
#define __MAX_ALLOCA_CUTOFF (1<<16)
#endif
#ifdef MALLOC_ALIGNMENT
#define _MALLOC_ALIGNMENT MALLOC_ALIGNMENT
#else
#define _MALLOC_ALIGNMENT 16
#endif
#define __libc_use_alloca(x) ( __MALLOCA_UB - __MALLOCA_LB + (x) < __MAX_ALLOCA_CUTOFF )
/* These functions are used to save space factoring out paths that rarely happen. */
#ifdef SHARED_MALLOCA
void __freeall (void *__malloca_gc);
void* __malloca_alloc (void *__malloca_gc,size_t __n);
#else
/* Noinline because gcc inlines this to __ifreeall which defeats the point. */
__attribute ((noinline))
static void __freeall (void *__malloca_gc)
{
while (__malloca_gc)
{
void * __tmp = __malloca_gc;
__malloca_gc = ((void **)__malloca_gc)[0];
free (__tmp);
}
}
static inline void __ifreeall (void * __malloca_gc)
{
if (__malloca_gc)
__freeall (__malloca_gc);
}
static void* __malloca_alloc (void *__malloca_gc,size_t __n)
{
void *__r = malloc (__n + _MALLOC_ALIGNMENT);
if (!__r || __n+_MALLOC_ALIGNMENT < _MALLOC_ALIGNMENT)
abort ();
((void **)__r)[0] = __malloca_gc;
__malloca_gc = __r;
return __r + _MALLOC_ALIGNMENT;
}
#endif
#define malloca(n) ({ \
size_t __n = (n); \
void * __r = NULL; \
if (__libc_use_alloca (__n)) \
{ \
__r = alloca (__n); \
} \
else \
{ \
__r = __malloca_alloc (__malloca_gc, __n); \
} \
__r; \
})
#undef alloca_account
#define alloca_account(n, var) ({ \
void *__r = alloca(n); \
__r; \
})
#ifdef __cplusplus
}
#endif
#endif /* _MALLOCA_H */