Implicit Free List Design Worksheet
Below is part of the starter code for lab 4. Use it to answer the following questions.
/* * Each block has header and footer of the form: * * 63 4 3 2 1 0 * ------------------------------------ * | s s s s ... s s 0 0 0 a/f | * ------------------------------------ * * where s are the meaningful size bits and a/f is 1 * if and only if the block is allocated. The list has the following form: * * begin end * heap heap * ----------------------------------------------------------------- * | pad | hdr(16:a) | ftr(16:a) | zero or more usr blks | hdr(0:a) | * ----------------------------------------------------------------- * | prologue | | epilogue | * | block | | block | * * The allocated prologue and epilogue blocks are overhead that * eliminate edge conditions during coalescing. */ /* Read a word at address p */ /* (size_t is an unsigned integer type with width = system word size) */ #define GET(p) (*(size_t *)(p)) /* Perform unscaled pointer arithmetic */ #define PADD(p, val) ((char *)(p) + (val)) #define PSUB(p, val) ((char *)(p) - (val)) /* Read the size and allocated fields from address p */ #define GET_SIZE(p) (GET(p) & ~0xf) #define GET_ALLOC(p) (GET(p) & 0x1) /* Given block ptr bp, compute address of its header and footer */ #define HDRP(bp) (PSUB(bp, 8)) #define FTRP(bp) (PADD(bp, GET_SIZE(HDRP(bp)) - 16)) /* Given block ptr bp, compute address of next and previous blocks */ #define NEXT_BLKP(bp) (PADD(bp, GET_SIZE(HDRP(bp)))) #define PREV_BLKP(bp) (PSUB(bp, GET_SIZE((PSUB(bp, 16)))))
- Why do
PADD
andPSUB
castp
to achar*
in order to perform "unscaled pointer arithmetic"? - How do the masks in
GET_SIZE
andGET_ALLOC
relate to the diagram of a block header/footer above? - Why does
FTRP(bp)
need to useHDRP
,GET_SIZE
,16
, andPADD
to get the address of the footer? - Given a block pointer
bp
(i.e., a pointer to the payload of a block), write the code to check if the next block in the heap is free.
- When we add or substract from a pointer, the arithmetic is scaled (multiplied) by the size of the data. If this scale is 1, we can add or substract an exact number without having to worry about scaling. A
char
is 1 byte, so arithmetic on achar*
will be multiplied by 1, thus adding or substracting the exact number. ~0xf
generates the 64-bit mask0xfffffff0
, so& ~0xf
will zero out the lower four bits (which we can see will always be 0s due to the size being a multiple of 16).& 0x1
will isolate just the lowest bit, which we can see indicates allocated or free.- Given a block pointer (a pointer to the start of the payload), we know the footer is at the other end of the block. To find where that is we need the block size. Fortunately, the block size is stored in the header, and we know the header is right before the start of the payload. Hence
GET_SIZE(HDRP(bp))
. If we add this tobp
, we will end up at the start of the payload of the next block. We further know that right before that address is the header for the next block, and right before the header is the footer of the current block. Thus, if we go two words back in memory (- 16
), we'll arrive at the footer. So, we take the current block pointer, get the size, add that minus two words, and we have the address of the footer. GET_ALLOC(HDRP(NEXT_BLKP(bp))) == 0
compared the allocated/free bit of the header of the next block to 0 (which would indicate the block is free)