mempool: define standard mempools, fixes to the mempool allocator

Define standard mempools reclaimed at various stages. Fix various
problems with the mempool allocator.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin 2018-06-03 02:47:06 -07:00
parent 9d06db9dab
commit 36e2a0c887
5 changed files with 131 additions and 66 deletions

View File

@ -60,6 +60,7 @@
#include "outform.h" #include "outform.h"
#include "listing.h" #include "listing.h"
#include "iflag.h" #include "iflag.h"
#include "mempool.h"
#include "ver.h" #include "ver.h"
/* /*
@ -502,7 +503,6 @@ int main(int argc, char **argv)
if (!terminate_after_phase) { if (!terminate_after_phase) {
ofmt->cleanup(); ofmt->cleanup();
cleanup_labels();
fflush(ofile); fflush(ofile);
if (ferror(ofile)) { if (ferror(ofile)) {
nasm_error(ERR_NONFATAL|ERR_NOFILE, nasm_error(ERR_NONFATAL|ERR_NOFILE,
@ -525,11 +525,14 @@ int main(int argc, char **argv)
if (want_usage) if (want_usage)
usage(); usage();
cleanup_labels();
raa_free(offsets); raa_free(offsets);
saa_free(forwrefs); saa_free(forwrefs);
eval_cleanup(); eval_cleanup();
stdscan_cleanup(); stdscan_cleanup();
src_free(); src_free();
mempool_free(mempool_perm);
mempool_reclaim();
return terminate_after_phase; return terminate_after_phase;
} }
@ -1540,6 +1543,7 @@ static void assemble_file(const char *fname, StrList **depend_ptr)
end_of_line: end_of_line:
nasm_free(line); nasm_free(line);
mempool_free(mempool_line);
} /* end while (line = preproc->getline... */ } /* end while (line = preproc->getline... */
if (pass0 == 2 && global_offset_changed && !terminate_after_phase) if (pass0 == 2 && global_offset_changed && !terminate_after_phase)
@ -1559,10 +1563,12 @@ static void assemble_file(const char *fname, StrList **depend_ptr)
stall_count++; stall_count++;
} }
mempool_free(mempool_pass);
if (terminate_after_phase) if (terminate_after_phase)
break; break;
if ((stall_count > 997U) || (passn >= pass_max)) { if (!terminate_after_phase &&
((stall_count > 997U) || (passn >= pass_max))) {
/* We get here if the labels don't converge /* We get here if the labels don't converge
* Example: FOO equ FOO + 1 * Example: FOO equ FOO + 1
*/ */
@ -1571,10 +1577,11 @@ static void assemble_file(const char *fname, StrList **depend_ptr)
"after %d passes, giving up.", passn); "after %d passes, giving up.", passn);
nasm_error(ERR_NONFATAL, nasm_error(ERR_NONFATAL,
"Possible causes: recursive EQUs, macro abuse."); "Possible causes: recursive EQUs, macro abuse.");
break; terminate_after_phase = true;
} }
} }
mempool_free(mempool_pass);
preproc->cleanup(0); preproc->cleanup(0);
lfmt->cleanup(); lfmt->cleanup();
if (!terminate_after_phase && opt_verbose_info) { if (!terminate_after_phase && opt_verbose_info) {

View File

@ -147,6 +147,12 @@ PA_HAVE_FUNC(__builtin_clzll, (0ULL))
PA_HAVE_FUNC(_BitScanReverse, (0)) PA_HAVE_FUNC(_BitScanReverse, (0))
PA_HAVE_FUNC(_BitScanReverse64, (0)) PA_HAVE_FUNC(_BitScanReverse64, (0))
dnl alignment stuff
PA_ADD_HEADERS(stdalign.h)
PA_HAVE_FUNC(alignof,(0))
PA_HAVE_FUNC(_Alignof,(0))
AC_CHECK_TYPES(max_align_t)
dnl Functions for which we have replacements available in stdlib/ dnl Functions for which we have replacements available in stdlib/
AC_CHECK_FUNCS([vsnprintf _vsnprintf]) AC_CHECK_FUNCS([vsnprintf _vsnprintf])
AC_CHECK_FUNCS([snprintf _snprintf]) AC_CHECK_FUNCS([snprintf _snprintf])
@ -258,7 +264,8 @@ PA_ARG_ENABLED([sanitizer],
[compile with sanitizers enabled], [compile with sanitizers enabled],
[PA_ADD_CFLAGS([-fno-omit-frame-pointer]) [PA_ADD_CFLAGS([-fno-omit-frame-pointer])
PA_ADD_CLDFLAGS([-fsanitize=address]) PA_ADD_CLDFLAGS([-fsanitize=address])
PA_ADD_CLDFLAGS([-fsanitize=undefined])]) PA_ADD_CLDFLAGS([-fsanitize=undefined])
AC_DEFINE([WITH_SANITIZER], 1, [Define to 1 to enable sanitizer options])])
dnl dnl
dnl Don't make symbols visible, there is no point and it just dnl Don't make symbols visible, there is no point and it just

View File

@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- * /* ----------------------------------------------------------------------- *
* *
* Copyright 2007-2017 The NASM Authors - All Rights Reserved * Copyright 2007-2018 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for * See the file AUTHORS included with the NASM distribution for
* the specific copyright holders. * the specific copyright holders.
* *
@ -71,18 +71,18 @@
#define __STDC_LIMIT_MACROS 1 #define __STDC_LIMIT_MACROS 1
#define __STDC_FORMAT_MACROS 1 #define __STDC_FORMAT_MACROS 1
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#else
# include "nasmint.h"
#endif
#include <assert.h> #include <assert.h>
#include <stddef.h> #include <stddef.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <limits.h> #include <limits.h>
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#else
# include "nasmint.h"
#endif
#ifdef HAVE_SYS_TYPES_H #ifdef HAVE_SYS_TYPES_H
# include <sys/types.h> # include <sys/types.h>
#endif #endif
@ -186,6 +186,37 @@ typedef enum bool { false, true } bool;
# define container_of(p, c, m) ((c *)((char *)(p) - offsetof(c,m))) # define container_of(p, c, m) ((c *)((char *)(p) - offsetof(c,m)))
#endif #endif
/*
* alignof(), and make a best guess at what the maximum alignment we
* may need might be
*/
#ifdef HAVE_STDALIGN_H
# include <stdalign.h>
#endif
#ifdef HAVE_MAX_ALIGN_T
typedef max_align_t nasm_max_align_t;
#else
typedef union {
void *p;
uint64_t i;
} nasm_max_align_t;
#endif
#if !defined(HAVE_ALIGNOF) && !defined(alignof) && defined(HAVE__ALIGNOF)
# define alignof(x) _Alignof(x)
# define HAVE_ALIGNOF 1
#endif
#ifdef __BIGGEST_ALIGNMENT__
# define MAX_ALIGNMENT __BIGGEST_ALIGNMENT__
#elif defined(HAVE_ALIGNOF)
# define MAX_ALIGNMENT alignof(nasm_max_align_t)
#elif
# define MAX_ALIGNMENT sizeof(nasm_max_align_t)
#endif
#ifndef HAVE_ALIGNOF
# define alignof(x) MAX_ALIGNMENT /* Safe but probably inefficient */
#endif
/* Some misguided platforms hide the defs for these */ /* Some misguided platforms hide the defs for these */
#if defined(HAVE_STRCASECMP) && !HAVE_DECL_STRCASECMP #if defined(HAVE_STRCASECMP) && !HAVE_DECL_STRCASECMP
int strcasecmp(const char *, const char *); int strcasecmp(const char *, const char *);

View File

@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- * /* ----------------------------------------------------------------------- *
* *
* Copyright 2017 The NASM Authors - All Rights Reserved * Copyright 2017-2018 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for * See the file AUTHORS included with the NASM distribution for
* the specific copyright holders. * the specific copyright holders.
* *
@ -51,15 +51,36 @@ struct mempool {
/* A single-member array which can decay to a pointer for simplicity */ /* A single-member array which can decay to a pointer for simplicity */
typedef struct mempool mempool[1]; typedef struct mempool mempool[1];
char *mempool_add(struct mempool *pool, const char *str); char * safe_alloc mempool_cpy(struct mempool *pool, const char *str);
char *mempool_cat(struct mempool *pool, const char *str1, const char *str2); char * safe_alloc mempool_cat(struct mempool *pool, const char *str1, const char *str2);
char *mempool_cat3(struct mempool *pool, const char *str1, char * safe_alloc mempool_cat3(struct mempool *pool, const char *str1,
const char *str2, const char *str3); const char *str2, const char *str3);
char *mempool_vprintf(struct mempool *pool, const char *fmt, va_list va); char * safe_alloc mempool_vprintf(struct mempool *pool, const char *fmt, va_list va);
char *mempool_printf(struct mempool *pool, const char *fmt, ...); char * safe_alloc mempool_printf(struct mempool *pool, const char *fmt, ...);
void *mempool_alloc(struct mempool *pool, size_t bytes); void * safe_malloc(2) mempool_alloc(struct mempool *pool, size_t bytes);
void * safe_malloc(2) mempool_align(struct mempool *pool, size_t bytes, size_t align);
void mempool_free(struct mempool *pool); void mempool_free(struct mempool *pool);
void mempool_reclaim(void); void mempool_reclaim(void);
#ifdef HAVE_ALIGNOF
#define mempool_new(pool,ptr) \
((ptr) = mempool_align(pool, sizeof *(ptr), alignof(*(ptr))))
#else
#define mempool_new(pool,ptr) \
((ptr) = mempool_alloc(pool, sizeof *(ptr)))
#endif
/*
* Common memory pools that are freed after every line, pass, or session,
* respectively.
*/
extern mempool mempool_perm;
extern mempool mempool_pass;
extern mempool mempool_line;
/* Routines to copy strings into mempool_perm */
char *perm_copy(const char *string);
char *perm_copy3(const char *s1, const char *s2, const char *s3);
#endif /* NASM_STRPOOL_H */ #endif /* NASM_STRPOOL_H */

View File

@ -52,37 +52,15 @@
#include "nasmlib.h" #include "nasmlib.h"
#include "ilog2.h" #include "ilog2.h"
#ifdef WITH_SANITIZER
# undef DEBUG_MEMPOOL
#endif
#define MAX(x,y) ((x) > (y) ? (x) : (y)) #define MAX(x,y) ((x) > (y) ? (x) : (y))
#define MIN(x,y) ((x) < (y) ? (x) : (y)) #define MIN(x,y) ((x) < (y) ? (x) : (y))
/* #define ALLOC_ALIGN(x) (((size_t)(x) + MAX_ALIGNMENT - 1) & \
* Make a best guess at what the maximum alignment we may need might be ~((size_t)MAX_ALIGNMENT - 1))
*/
#ifdef HAVE_STDALIGN_H
# include <stdalign.h>
#endif
#if !defined(HAVE_ALIGNOF) && defined(HAVE__ALIGNOF)
# define HAVE_ALIGNOF 1
# define alignof(x) _Alignof(x)
#endif
#ifdef __BIGGEST_ALIGNMENT__ /* gcc at least provides this */
# define SYS_ALIGNMENT __BIGGEST_ALIGNMENT__
#elif defined(HAVE_ALIGNOF)
# ifdef HAVE_MAX_ALIGN_T
# define SYS_ALIGNMENT alignof(max_align_t)
# else
/* Best guess for what we may actually need */
# define SYS_ALIGNMENT MAX(alignof(void *), alignof(uint64_t))
# endif
#else
# define SYS_ALIGNMENT sizeof(void *)
#endif
/* Always align to a multiple of uint64_t even if not required by the system */
#define MY_ALIGNMENT MAX(SYS_ALIGNMENT, sizeof(uint64_t)) /* Chaotic good? */
#define ALLOC_ALIGN(x) (((size_t)(x) + MY_ALIGNMENT - 1) & \
~((size_t)MY_ALIGNMENT - 1))
/* /*
* Sizes of allocation blocks. We default to ALLOC_START, but allocate * Sizes of allocation blocks. We default to ALLOC_START, but allocate
@ -132,9 +110,9 @@ void mempool_free(struct mempool *sp)
*/ */
void mempool_reclaim(void) void mempool_reclaim(void)
{ {
struct mempool_storage *s; struct mempool_storage *s, *sn;
list_for_each(s, ssfree) list_for_each_safe(s, sn, ssfree)
nasm_free(s); nasm_free(s);
ssfree = NULL; ssfree = NULL;
} }
@ -142,14 +120,9 @@ void mempool_reclaim(void)
static struct mempool_storage *mempool_more(struct mempool *sp, size_t l) static struct mempool_storage *mempool_more(struct mempool *sp, size_t l)
{ {
struct mempool_storage *sps, **ssp; struct mempool_storage *sps, **ssp;
size_t n; size_t n, nmin;
size_t nmin;
const size_t header = ALLOC_ALIGN(sizeof(struct mempool_storage));
sps = sp->sstail; l += ALLOC_ALIGN(sizeof(struct mempool_storage));
ssp = sps ? &sps->next : &sp->sshead;
l += header;
nmin = ALLOC_ALIGN(MAX(l, ALLOC_MIN)); nmin = ALLOC_ALIGN(MAX(l, ALLOC_MIN));
/* Is the top block on the free list which is big enough for us? */ /* Is the top block on the free list which is big enough for us? */
@ -159,7 +132,7 @@ static struct mempool_storage *mempool_more(struct mempool *sp, size_t l)
goto have_sps; goto have_sps;
} }
n = sps ? sp->totalbytes : ALLOC_START; n = MAX(sp->totalbytes, ALLOC_START);
n = MIN(n, ALLOC_MAX); n = MIN(n, ALLOC_MAX);
n = MAX(n, nmin); n = MAX(n, nmin);
n = ((size_t)2) << ilog2_64(n-1); /* Round up to a power of 2 */ n = ((size_t)2) << ilog2_64(n-1); /* Round up to a power of 2 */
@ -181,44 +154,52 @@ static struct mempool_storage *mempool_more(struct mempool *sp, size_t l)
sps->nbytes = nmin; sps->nbytes = nmin;
have_sps: have_sps:
ssp = sp->sstail ? &sps->next : &sp->sshead;
*ssp = sp->sstail = sps; *ssp = sp->sstail = sps;
if (!sp->sshead) if (!sp->sshead)
sp->sshead = sp->sstail; sp->sshead = sp->sstail;
sps->next = NULL; sps->next = NULL;
sps->idx = header; sps->idx = sizeof *sps;
sp->totalbytes += sps->nbytes; sp->totalbytes += sps->nbytes;
return sps; return sps;
} }
static inline void * void *mempool_align(struct mempool *sp, size_t l, const size_t align)
mempool_get_aligned(struct mempool *sp, size_t l, const size_t align)
{ {
struct mempool_storage *sps; struct mempool_storage *sps;
char *p; char *p;
size_t idx; size_t idx;
sps = sp->sstail; sps = sp->sstail;
if (unlikely(!sps))
goto need_more;
idx = (sps->idx + align - 1) & ~(align - 1); idx = (sps->idx + align - 1) & ~(align - 1);
if (unlikely(l > sps->nbytes - idx)) { if (unlikely(l > sps->nbytes - idx))
sps = mempool_more(sp, l); goto need_more;
idx = sps->idx;
} ok:
p = (char *)sps + idx; p = (char *)sps + idx;
sps->idx = idx+l; sps->idx = idx+l;
return p; return p;
need_more:
sps = mempool_more(sp, l);
idx = sps->idx;
goto ok;
} }
static inline char *mempool_get(struct mempool *sp, size_t l) static inline char *mempool_get(struct mempool *sp, size_t l)
{ {
return mempool_get_aligned(sp, l, 1); return mempool_align(sp, l, 1);
} }
void *mempool_alloc(struct mempool *sp, size_t l) void *mempool_alloc(struct mempool *sp, size_t l)
{ {
return mempool_get_aligned(sp, l, MY_ALIGNMENT); return mempool_align(sp, l, MAX_ALIGNMENT);
} }
char *mempool_add(struct mempool *sp, const char *str) char *mempool_cpy(struct mempool *sp, const char *str)
{ {
char *p; char *p;
size_t l = strlen(str) + 1; size_t l = strlen(str) + 1;
@ -307,3 +288,21 @@ char *mempool_printf(struct mempool *sp, const char *fmt, ...)
return p; return p;
} }
/*
* Common memory pools that are freed after every line, pass, or session,
* respectively.
*/
mempool mempool_perm;
mempool mempool_pass;
mempool mempool_line;
char *perm_copy(const char *string)
{
return mempool_cpy(mempool_perm, string);
}
char *perm_copy3(const char *s1, const char *s2, const char *s3)
{
return mempool_cat3(mempool_perm, s1, s2, s3);
}