mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
143 lines
4.2 KiB
PHP
143 lines
4.2 KiB
PHP
|
// clang-format off
|
||
|
|
||
|
/* -------------------------- mspace management -------------------------- */
|
||
|
|
||
|
/* Initialize top chunk and its size */
|
||
|
static void init_top(mstate m, mchunkptr p, size_t psize) {
|
||
|
/* Ensure alignment */
|
||
|
size_t offset = align_offset(chunk2mem(p));
|
||
|
p = (mchunkptr)((char*)p + offset);
|
||
|
psize -= offset;
|
||
|
|
||
|
m->top = p;
|
||
|
m->topsize = psize;
|
||
|
p->head = psize | PINUSE_BIT;
|
||
|
/* set size of fake trailing chunk holding overhead space only once */
|
||
|
chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
|
||
|
m->trim_check = mparams.trim_threshold; /* reset on each update */
|
||
|
}
|
||
|
|
||
|
/* Initialize bins for a new mstate that is otherwise zeroed out */
|
||
|
static void init_bins(mstate m) {
|
||
|
/* Establish circular links for smallbins */
|
||
|
bindex_t i;
|
||
|
for (i = 0; i < NSMALLBINS; ++i) {
|
||
|
sbinptr bin = smallbin_at(m,i);
|
||
|
bin->fd = bin->bk = bin;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if PROCEED_ON_ERROR
|
||
|
|
||
|
/* default corruption action */
|
||
|
static void reset_on_error(mstate m) {
|
||
|
int i;
|
||
|
++malloc_corruption_error_count;
|
||
|
/* Reinitialize fields to forget about all memory */
|
||
|
m->smallmap = m->treemap = 0;
|
||
|
m->dvsize = m->topsize = 0;
|
||
|
m->seg.base = 0;
|
||
|
m->seg.size = 0;
|
||
|
m->seg.next = 0;
|
||
|
m->top = m->dv = 0;
|
||
|
for (i = 0; i < NTREEBINS; ++i)
|
||
|
*treebin_at(m, i) = 0;
|
||
|
init_bins(m);
|
||
|
}
|
||
|
#endif /* PROCEED_ON_ERROR */
|
||
|
|
||
|
/* Allocate chunk and prepend remainder with chunk in successor base. */
|
||
|
static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
|
||
|
size_t nb) {
|
||
|
mchunkptr p = align_as_chunk(newbase);
|
||
|
mchunkptr oldfirst = align_as_chunk(oldbase);
|
||
|
size_t psize = (char*)oldfirst - (char*)p;
|
||
|
mchunkptr q = chunk_plus_offset(p, nb);
|
||
|
size_t qsize = psize - nb;
|
||
|
set_size_and_pinuse_of_inuse_chunk(m, p, nb);
|
||
|
|
||
|
assert((char*)oldfirst > (char*)q);
|
||
|
assert(pinuse(oldfirst));
|
||
|
assert(qsize >= MIN_CHUNK_SIZE);
|
||
|
|
||
|
/* consolidate remainder with first chunk of old base */
|
||
|
if (oldfirst == m->top) {
|
||
|
size_t tsize = m->topsize += qsize;
|
||
|
m->top = q;
|
||
|
q->head = tsize | PINUSE_BIT;
|
||
|
check_top_chunk(m, q);
|
||
|
}
|
||
|
else if (oldfirst == m->dv) {
|
||
|
size_t dsize = m->dvsize += qsize;
|
||
|
m->dv = q;
|
||
|
set_size_and_pinuse_of_free_chunk(q, dsize);
|
||
|
}
|
||
|
else {
|
||
|
if (!is_inuse(oldfirst)) {
|
||
|
size_t nsize = chunksize(oldfirst);
|
||
|
unlink_chunk(m, oldfirst, nsize);
|
||
|
oldfirst = chunk_plus_offset(oldfirst, nsize);
|
||
|
qsize += nsize;
|
||
|
}
|
||
|
set_free_with_pinuse(q, qsize, oldfirst);
|
||
|
insert_chunk(m, q, qsize);
|
||
|
check_free_chunk(m, q);
|
||
|
}
|
||
|
|
||
|
check_malloced_chunk(m, chunk2mem(p), nb);
|
||
|
return chunk2mem(p);
|
||
|
}
|
||
|
|
||
|
/* Add a segment to hold a new noncontiguous region */
|
||
|
static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
|
||
|
/* Determine locations and sizes of segment, fenceposts, old top */
|
||
|
char* old_top = (char*)m->top;
|
||
|
msegmentptr oldsp = segment_holding(m, old_top);
|
||
|
char* old_end = oldsp->base + oldsp->size;
|
||
|
size_t ssize = pad_request(sizeof(struct malloc_segment));
|
||
|
char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
|
||
|
size_t offset = align_offset(chunk2mem(rawsp));
|
||
|
char* asp = rawsp + offset;
|
||
|
char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;
|
||
|
mchunkptr sp = (mchunkptr)csp;
|
||
|
msegmentptr ss = (msegmentptr)(chunk2mem(sp));
|
||
|
mchunkptr tnext = chunk_plus_offset(sp, ssize);
|
||
|
mchunkptr p = tnext;
|
||
|
int nfences = 0;
|
||
|
|
||
|
/* reset top to new space */
|
||
|
init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
|
||
|
|
||
|
/* Set up segment record */
|
||
|
assert(is_aligned(ss));
|
||
|
set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);
|
||
|
*ss = m->seg; /* Push current record */
|
||
|
m->seg.base = tbase;
|
||
|
m->seg.size = tsize;
|
||
|
m->seg.sflags = mmapped;
|
||
|
m->seg.next = ss;
|
||
|
|
||
|
/* Insert trailing fenceposts */
|
||
|
for (;;) {
|
||
|
mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);
|
||
|
p->head = FENCEPOST_HEAD;
|
||
|
++nfences;
|
||
|
if ((char*)(&(nextp->head)) < old_end)
|
||
|
p = nextp;
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
assert(nfences >= 2);
|
||
|
|
||
|
/* Insert the rest of old top into a bin as an ordinary free chunk */
|
||
|
if (csp != old_top) {
|
||
|
mchunkptr q = (mchunkptr)old_top;
|
||
|
size_t psize = csp - old_top;
|
||
|
mchunkptr tn = chunk_plus_offset(q, psize);
|
||
|
set_free_with_pinuse(q, psize, tn);
|
||
|
insert_chunk(m, q, psize);
|
||
|
}
|
||
|
|
||
|
check_top_chunk(m, m->top);
|
||
|
}
|