mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
fa20edc44d
- Remove most __ASSEMBLER__ __LINKER__ ifdefs - Rename libc/intrin/bits.h to libc/serialize.h - Block pthread cancelation in fchmodat() polyfill - Remove `clang-format off` statements in third_party
170 lines
4.6 KiB
C++
170 lines
4.6 KiB
C++
|
|
/* ------------------------- 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 */
|