cosmopolitan/third_party/dlmalloc/trees.inc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

171 lines
4.6 KiB
PHP
Raw Normal View History

/* ------------------------- Operations on trees ------------------------- */
/* Insert chunk into tree */
#define insert_large_chunk(M, X, S) {\
tbinptr* H;\
bindex_t I;\
compute_tree_index(S, I);\
H = treebin_at(M, I);\
X->index = I;\
X->child[0] = X->child[1] = 0;\
if (!treemap_is_marked(M, I)) {\
mark_treemap(M, I);\
*H = X;\
X->parent = (tchunkptr)H;\
X->fd = X->bk = X;\
}\
else {\
tchunkptr T = *H;\
size_t K = S << leftshift_for_tree_index(I);\
for (;;) {\
if (chunksize(T) != S) {\
tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
K <<= 1;\
if (*C != 0)\
T = *C;\
else if (RTCHECK(ok_address(M, C))) {\
*C = X;\
X->parent = T;\
X->fd = X->bk = X;\
break;\
}\
else {\
CORRUPTION_ERROR_ACTION(M);\
break;\
}\
}\
else {\
tchunkptr F = T->fd;\
if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
T->fd = F->bk = X;\
X->fd = F;\
X->bk = T;\
X->parent = 0;\
break;\
}\
else {\
CORRUPTION_ERROR_ACTION(M);\
break;\
}\
}\
}\
}\
}
/*
Unlink steps:
1. If x is a chained node, unlink it from its same-sized fd/bk links
and choose its bk node as its replacement.
2. If x was the last node of its size, but not a leaf node, it must
be replaced with a leaf node (not merely one with an open left or
right), to make sure that lefts and rights of descendents
correspond properly to bit masks. We use the rightmost descendent
of x. We could use any other leaf, but this is easy to locate and
tends to counteract removal of leftmosts elsewhere, and so keeps
paths shorter than minimally guaranteed. This doesn't loop much
because on average a node in a tree is near the bottom.
3. If x is the base of a chain (i.e., has parent links) relink
x's parent and children to x's replacement (or null if none).
*/
#define unlink_large_chunk(M, X) {\
tchunkptr XP = X->parent;\
tchunkptr R;\
if (X->bk != X) {\
tchunkptr F = X->fd;\
R = X->bk;\
if (RTCHECK(ok_address(M, F) && F->bk == X && R->fd == X)) {\
F->bk = R;\
R->fd = F;\
}\
else {\
CORRUPTION_ERROR_ACTION(M);\
}\
}\
else {\
tchunkptr* RP;\
if (((R = *(RP = &(X->child[1]))) != 0) ||\
((R = *(RP = &(X->child[0]))) != 0)) {\
tchunkptr* CP;\
while ((*(CP = &(R->child[1])) != 0) ||\
(*(CP = &(R->child[0])) != 0)) {\
R = *(RP = CP);\
}\
if (RTCHECK(ok_address(M, RP)))\
*RP = 0;\
else {\
CORRUPTION_ERROR_ACTION(M);\
}\
}\
}\
if (XP != 0) {\
tbinptr* H = treebin_at(M, X->index);\
if (X == *H) {\
if ((*H = R) == 0) \
clear_treemap(M, X->index);\
}\
else if (RTCHECK(ok_address(M, XP))) {\
if (XP->child[0] == X) \
XP->child[0] = R;\
else \
XP->child[1] = R;\
}\
else\
CORRUPTION_ERROR_ACTION(M);\
if (R != 0) {\
if (RTCHECK(ok_address(M, R))) {\
tchunkptr C0, C1;\
R->parent = XP;\
if ((C0 = X->child[0]) != 0) {\
if (RTCHECK(ok_address(M, C0))) {\
R->child[0] = C0;\
C0->parent = R;\
}\
else\
CORRUPTION_ERROR_ACTION(M);\
}\
if ((C1 = X->child[1]) != 0) {\
if (RTCHECK(ok_address(M, C1))) {\
R->child[1] = C1;\
C1->parent = R;\
}\
else\
CORRUPTION_ERROR_ACTION(M);\
}\
}\
else\
CORRUPTION_ERROR_ACTION(M);\
}\
}\
}
/* Relays to large vs small bin operations */
#define insert_chunk(M, P, S)\
if (is_small(S)) insert_small_chunk(M, P, S)\
else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
#define unlink_chunk(M, P, S)\
if (is_small(S)) unlink_small_chunk(M, P, S)\
else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
/* Relays to internal calls to malloc/free from realloc, memalign etc */
#if ONLY_MSPACES
#define internal_malloc(m, b) mspace_malloc(m, b)
#define internal_free(m, mem) mspace_free(m,mem);
#else /* ONLY_MSPACES */
#if MSPACES
#define internal_malloc(m, b)\
((m == gm)? dlmalloc(b) : mspace_malloc(m, b))
#define internal_free(m, mem)\
if (m == gm) dlfree(mem); else mspace_free(m,mem);
#else /* MSPACES */
#define internal_malloc(m, b) dlmalloc(b)
#define internal_free(m, mem) dlfree(mem)
#endif /* MSPACES */
#endif /* ONLY_MSPACES */