static block_t *coalesce(block_t *bp) {
/*
* ok i'm gonna do a ton of work in the initializing stage here so that
* later the focus is on the coalescing logic and not pointer fuckery
*/
/* address of first word in heap */
unsigned int *lo = (unsigned int *) mem_heap_lo();
/* address of last word in heap */
unsigned int *hi = (unsigned int *) (((char *) mem_heap_hi()) - 3);
/* addresses of prev and next words */
unsigned int *prev_word = GET_PREV_WORD(bp);
unsigned int *next_word = GET_NEXT_WORD(bp);
/* are adjacent words in the heap? */
int prev_in_range = prev_word >= lo;
int next_in_range = prev_word <= hi;
/* are prev and next free blocks that we can coalesce with? */
int prev_free = prev_in_range ? (*prev_word & 1) : 0;
int next_free = next_in_range ? (*next_word & 1) : 0;
/* sizes of bp, prev, and next */
size_t bp_sz = GET_SZ(bp);
size_t prev_sz = prev_free ? (*prev_word & 0) : 0;
size_t next_sz = next_free ? (*next_word & 0) : 0;
/* pointers to prev, next, and the new coalesced block */
/*
* we already have a ptr to one boundary tag, so only need to move by the
* block size + 1 word to get to the header of the prev block
*/
block_t *prev = prev_free ? ((block_t *) (prev_word - prev_sz - 1)) : NULL;
/* already at the start of the next block */
block_t *next = next_free ? ((block_t *) next_word) : NULL;
block_t *new_block;
/* case 1: prev and next both not free or out of range */
if (!prev && !next) {
/* don't coalesce anything */
new_block = bp;
}
/* case 2: prev free, but next not free or out of range */
else if (prev && !next) {
/* take prev out of the list before doing anything */
remove_blk(prev);
/*
* prev and bp will now become one block. its usable space is prev_sz +
* bp_sz + 2 (former prev ftr and bp hdr)
*/
SET_SZ_ALLOC(prev, prev_sz + bp_sz + 2, 0);
/* and this new block starts where prev used to */
new_block = prev;
/* also init its ptrs to 0 */
SET_PRED(new_block, 0);
SET_SUCC(new_block, 0);
}
/* case 3: prev not free or out of range, but next free */
else if (!prev && next) {
/* take next out of the list before doing anything */
remove_blk(next);
/*
* bp and next will now become one block. its usable space is bp_sz +
* next_sz + 2 (former bp ftr and next hdr)
*/
SET_SZ_ALLOC(bp, bp_sz + next_sz + 2, 0);
/* and this new block starts where bp used to */
new_block = bp;
/* also init its ptrs to 0 */
SET_PRED(new_block, 0);
SET_SUCC(new_block, 0);
}
/* case 4: prev and next both free */
else {
/* take prev and next out of the list before doing anything */
remove_blk(prev);
remove_blk(next);
/*
* prev, bp, and next will now become one block. its usable space is
* prev_sz + bp_sz + next_sz + 2 (former prev ftr, bp hdr, bp ftr,
* and next hdr)
*/
SET_SZ_ALLOC(prev, prev_sz + bp_sz + next_sz + 4, 0);
/* and this new block starts where prev used to */
new_block = prev;
/* also init its ptrs to 0 */
SET_PRED(new_block, 0);
SET_SUCC(new_block, 0);
}
return new_block;
}