+place_chunk(uint8_t* ptr, size_t size)
+{
+ uint32_t header = *((uint32_t*)ptr);
+ size_t chunk_size = CHUNK_S(header);
+ *((uint32_t*)ptr) = PACK(size, CHUNK_PF(header) | M_ALLOCATED);
+ uint8_t* n_hdrptr = (uint8_t*)(ptr + size);
+ uint32_t diff = chunk_size - size;
+
+ if (!diff) {
+ // if the current free block is fully occupied
+ uint32_t n_hdr = LW(n_hdrptr);
+ // notify the next block about our avaliability
+ SW(n_hdrptr, n_hdr & ~0x2);
+ } else {
+ // if there is remaining free space left
+ uint32_t remainder_hdr = PACK(diff, M_NOT_ALLOCATED | M_PREV_ALLOCATED);
+ SW(n_hdrptr, remainder_hdr);
+ SW(FPTR(n_hdrptr, diff), remainder_hdr);
+
+ /*
+ | xxxx | | |
+
+ |
+ v
+
+ | xxxx | |
+ */
+ coalesce(n_hdrptr);
+ }
+}
+
+void*
+coalesce(uint8_t* chunk_ptr)
+{
+ uint32_t hdr = LW(chunk_ptr);
+ uint32_t pf = CHUNK_PF(hdr);
+ uint32_t sz = CHUNK_S(hdr);
+
+ uint32_t n_hdr = LW(chunk_ptr + sz);
+
+ if (CHUNK_A(n_hdr) && pf) {
+ // case 1: prev is free
+ uint32_t prev_ftr = LW(chunk_ptr - WSIZE);
+ size_t prev_chunk_sz = CHUNK_S(prev_ftr);
+ uint32_t new_hdr = PACK(prev_chunk_sz + sz, CHUNK_PF(prev_ftr));
+ SW(chunk_ptr - prev_chunk_sz, new_hdr);
+ SW(FPTR(chunk_ptr, sz), new_hdr);
+ chunk_ptr -= prev_chunk_sz;
+ } else if (!CHUNK_A(n_hdr) && !pf) {
+ // case 2: next is free
+ size_t next_chunk_sz = CHUNK_S(n_hdr);
+ uint32_t new_hdr = PACK(next_chunk_sz + sz, pf);
+ SW(chunk_ptr, new_hdr);
+ SW(FPTR(chunk_ptr, sz + next_chunk_sz), new_hdr);
+ } else if (!CHUNK_A(n_hdr) && pf) {
+ // case 3: both free
+ uint32_t prev_ftr = LW(chunk_ptr - WSIZE);
+ size_t next_chunk_sz = CHUNK_S(n_hdr);
+ size_t prev_chunk_sz = CHUNK_S(prev_ftr);
+ uint32_t new_hdr =
+ PACK(next_chunk_sz + prev_chunk_sz + sz, CHUNK_PF(prev_ftr));
+ SW(chunk_ptr - prev_chunk_sz, new_hdr);
+ SW(FPTR(chunk_ptr, sz + next_chunk_sz), new_hdr);
+ chunk_ptr -= prev_chunk_sz;
+ }
+
+ // (fall through) case 4: prev and next are not free
+ return chunk_ptr;
+}
+
+void*
+lx_grow_heap(heap_context_t* heap, size_t sz)
+{
+ void* start;
+
+ // The "+ WSIZE" capture the overhead for epilogue marker
+ if (!(start = lxsbrk(heap, sz + WSIZE, 0))) {
+ return NULL;
+ }
+ sz = ROUNDUP(sz, BOUNDARY);
+
+ // minus the overhead for epilogue, keep the invariant.
+ heap->brk -= WSIZE;
+
+ uint32_t old_marker = *((uint32_t*)start);
+ uint32_t free_hdr = PACK(sz, CHUNK_PF(old_marker));
+ SW(start, free_hdr);
+ SW(FPTR(start, sz), free_hdr);
+ SW(NEXT_CHK(start), PACK(0, M_ALLOCATED | M_PREV_FREE));
+
+ return coalesce(start);