mirror of
https://github.com/encounter/bdwgc.git
synced 2026-03-30 10:57:55 -07:00
1b5b1b71ce
(code refactoring)
* backgraph.c (FOR_EACH_PRED): Wrap outermost block into do/while (0).
* include/gc_inline.h (GC_FAST_MALLOC_GRANS, GC_MALLOC_WORDS,
GC_MALLOC_ATOMIC_WORDS, GC_CONS): Likewise.
* include/private/gc_hdrs.h (HC_GET_HDR, GET_BI, GET_HDR_ADDR,
GET_HDR, SET_HDR): Likewise.
* include/private/gc_locks.h (LOCK, UNLOCK): Likewise.
* include/private/gc_pmark.h (PUSH_OBJ, PUSH_CONTENTS,
SET_MARK_BIT_EXIT_IF_SET, OR_WORD_EXIT_IF_SET, LONG_MULT,
PUSH_CONTENTS_HDR, GC_PUSH_ONE_STACK, GC_PUSH_ONE_HEAP, GC_MARK_FO):
Likewise.
* include/private/gc_priv.h (GET_TIME, GC_ASSERT, COND_DUMP_CHECKS,
DISABLE_CANCEL, RESTORE_CANCEL): Likewise.
* include/private/gcconfig.h (PREFETCH): Likewise.
* mark.c (PUSH_GRANULE): Likewise.
* misc.c (GC_PRINTF_FILLBUF): Likewise.
* include/private/gc_locks.h (SET_LOCK_HOLDER, UNSET_LOCK_HOLDER):
Define as "(void)0" instead of empty.
* include/private/gc_priv.h (ASSERT_CANCEL_DISABLED): Likewise.
* include/private/gcconfig.h (PREFETCH, PREFETCH_FOR_WRITE): Likewise.
* win32_threads.c (UNPROTECT_THREAD): Likewise.
* include/private/gc_priv.h (GC_INLINE): Refine comment.
* include/private/gc_priv.h (MAKE_COOLER, MAKE_HOTTER,
GC_ADD_TO_BLACK_LIST_NORMAL, GC_ADD_TO_BLACK_LIST_STACK, COND_DUMP):
Replace block in "else" branch with a statement and remove trailing
';' symbol.
* include/private/gc_priv.h (ABORT_RET): Invert "if" condition moving
statement from "then" branch to "else" one; remove outermost {};
remove trailing ';' symbol
* os_dep.c (PROTECT, UNPROTECT): Likewise.
* pthread_support.c (INIT_REAL_SYMS): Likewise.
* win32_threads.c (SET_PTHREAD_MAP_CACHE): Cast result to void.
* win32_threads.c (PUSH2, PUSH4): Add outermost parentheses.
147 lines
6.7 KiB
C
147 lines
6.7 KiB
C
/*
|
|
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
|
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
|
|
* Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
|
|
*
|
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
|
*
|
|
* Permission is hereby granted to use or copy this program
|
|
* for any purpose, provided the above notices are retained on all copies.
|
|
* Permission to modify the code and to distribute modified code is granted,
|
|
* provided the above notices are retained, and a notice that the code was
|
|
* modified is included with the above copyright notice.
|
|
*/
|
|
|
|
#ifndef GC_INLINE_H
|
|
#define GC_INLINE_H
|
|
|
|
/* WARNING: */
|
|
/* Note that for these routines, it is the clients responsibility to */
|
|
/* add the extra byte at the end to deal with one-past-the-end pointers.*/
|
|
/* In the standard collector configuration, the collector assumes that */
|
|
/* such a byte has been added, and hence does not trace the last word */
|
|
/* in the resulting object. */
|
|
/* This is not an issue if the collector is compiled with */
|
|
/* DONT_ADD_BYTE_AT_END, or if GC_all_interior_pointers is not set. */
|
|
/* This interface is most useful for compilers that generate C. */
|
|
/* It is also used internally for thread-local allocation. */
|
|
/* Manual use is hereby discouraged. */
|
|
|
|
#include "gc.h"
|
|
#include "gc_tiny_fl.h"
|
|
|
|
#if __GNUC__ >= 3
|
|
# define GC_EXPECT(expr, outcome) __builtin_expect(expr,outcome)
|
|
/* Equivalent to (expr), but predict that usually (expr)==outcome. */
|
|
#else
|
|
# define GC_EXPECT(expr, outcome) (expr)
|
|
#endif /* __GNUC__ */
|
|
|
|
#ifndef GC_ASSERT
|
|
# define GC_ASSERT(expr) /* empty */
|
|
#endif
|
|
|
|
/* Store a pointer to a list of newly allocated objects of kind k and */
|
|
/* size lb in *result. The caller must make sure that *result is */
|
|
/* traced even if objects are ptrfree. */
|
|
GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
|
|
void ** /* result */);
|
|
|
|
/* The ultimately general inline allocation macro. Allocate an object */
|
|
/* of size granules, putting the resulting pointer in result. Tiny_fl */
|
|
/* is a "tiny" free list array, which will be used first, if the size */
|
|
/* is appropriate. If granules is too large, we allocate with */
|
|
/* default_expr instead. If we need to refill the free list, we use */
|
|
/* GC_generic_malloc_many with the indicated kind. */
|
|
/* Tiny_fl should be an array of GC_TINY_FREELISTS void * pointers. */
|
|
/* If num_direct is nonzero, and the individual free list pointers */
|
|
/* are initialized to (void *)1, then we allocate numdirect granules */
|
|
/* directly using gmalloc before putting multiple objects into the */
|
|
/* tiny_fl entry. If num_direct is zero, then the free lists may also */
|
|
/* be initialized to (void *)0. */
|
|
/* Note that we use the zeroth free list to hold objects 1 granule in */
|
|
/* size that are used to satisfy size 0 allocation requests. */
|
|
/* We rely on much of this hopefully getting optimized away in the */
|
|
/* num_direct = 0 case. */
|
|
/* Particularly if granules is constant, this should generate a small */
|
|
/* amount of code. */
|
|
# define GC_FAST_MALLOC_GRANS(result,granules,tiny_fl,num_direct,\
|
|
kind,default_expr,init) \
|
|
do { \
|
|
if (GC_EXPECT((granules) >= GC_TINY_FREELISTS,0)) { \
|
|
result = (default_expr); \
|
|
} else { \
|
|
void **my_fl = (tiny_fl) + (granules); \
|
|
void *my_entry=*my_fl; \
|
|
void *next; \
|
|
\
|
|
while (GC_EXPECT((GC_word)my_entry \
|
|
<= (num_direct) + GC_TINY_FREELISTS + 1, 0)) { \
|
|
/* Entry contains counter or NULL */ \
|
|
if ((GC_word)my_entry - 1 < (num_direct)) { \
|
|
/* Small counter value, not NULL */ \
|
|
*my_fl = (char *)my_entry + (granules) + 1; \
|
|
result = (default_expr); \
|
|
goto out; \
|
|
} else { \
|
|
/* Large counter or NULL */ \
|
|
GC_generic_malloc_many(((granules) == 0? GC_GRANULE_BYTES : \
|
|
GC_RAW_BYTES_FROM_INDEX(granules)), \
|
|
kind, my_fl); \
|
|
my_entry = *my_fl; \
|
|
if (my_entry == 0) { \
|
|
result = (*GC_get_oom_fn())((granules)*GC_GRANULE_BYTES); \
|
|
goto out; \
|
|
} \
|
|
} \
|
|
} \
|
|
next = *(void **)(my_entry); \
|
|
result = (void *)my_entry; \
|
|
*my_fl = next; \
|
|
init; \
|
|
PREFETCH_FOR_WRITE(next); \
|
|
GC_ASSERT(GC_size(result) >= (granules)*GC_GRANULE_BYTES); \
|
|
GC_ASSERT((kind) == PTRFREE || ((GC_word *)result)[1] == 0); \
|
|
out: ; \
|
|
} \
|
|
} while (0)
|
|
|
|
# define GC_WORDS_TO_WHOLE_GRANULES(n) \
|
|
GC_WORDS_TO_GRANULES((n) + GC_GRANULE_WORDS - 1)
|
|
|
|
/* Allocate n words (NOT BYTES). X is made to point to the result. */
|
|
/* This should really only be used if GC_all_interior_pointers is */
|
|
/* not set, or DONT_ADD_BYTE_AT_END is set. See above. */
|
|
/* The semantics changed in version 7.0; we no longer lock, and */
|
|
/* the caller is responsible for supplying a cleared tiny_fl */
|
|
/* free list array. For single-threaded applications, this may be */
|
|
/* a global array. */
|
|
# define GC_MALLOC_WORDS(result,n,tiny_fl) \
|
|
do { \
|
|
size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
|
|
GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
|
|
NORMAL, GC_malloc(grans*GC_GRANULE_BYTES), \
|
|
*(void **)(result) = 0); \
|
|
} while (0)
|
|
|
|
# define GC_MALLOC_ATOMIC_WORDS(result,n,tiny_fl) \
|
|
do { \
|
|
size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
|
|
GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
|
|
PTRFREE, GC_malloc_atomic(grans*GC_GRANULE_BYTES), \
|
|
(void)0 /* no initialization */); \
|
|
} while (0)
|
|
|
|
/* And once more for two word initialized objects: */
|
|
# define GC_CONS(result, first, second, tiny_fl) \
|
|
do { \
|
|
size_t grans = GC_WORDS_TO_WHOLE_GRANULES(2); \
|
|
GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
|
|
NORMAL, GC_malloc(grans*GC_GRANULE_BYTES), \
|
|
*(void **)(result) = (void *)(first)); \
|
|
((void **)(result))[1] = (void *)(second); \
|
|
} while (0)
|
|
|
|
#endif /* !GC_INLINE_H */
|