/* * mm-naive.c - The fastest, least memory-efficient malloc package. * * In this naive approach, a block is allocated by simply incrementing * the brk pointer. A block is pure payload. There are no headers or * footers. Blocks are never coalesced or reused. Realloc is * implemented directly using mm_malloc and mm_free. * * NOTE TO STUDENTS: Replace this header comment with your own header * comment that gives a high level description of your solution. */ #include #include #include #include #include #include "mm.h" #include "memlib.h" /********************************************************* * NOTE TO STUDENTS: Before you do anything else, please * provide your team information in the following struct. ********************************************************/ team_t team = { /* Team name */ "ateam", /* First member's full name */ "Harry Bovik", /* First member's email address */ "bovik@cs.cmu.edu", /* Second member's full name (leave blank if none) */ "", /* Second member's email address (leave blank if none) */ "" }; /* single word (4) or double word (8) alignment */ #define ALIGNMENT 8 /* rounds up to the nearest multiple of ALIGNMENT */ #define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7) #define SIZE_T_SIZE (ALIGN(sizeof(size_t))) #define WSIZE 4 /* Word and header/footer size (bytes) */ #define DSIZE 8 /* Double word size (bytes) */ #define CHUNKSIZE (1<<12) /* Extend heap by this amount (bytes) */ #define MAX(x, y) ((x) > (y)? (x) : (y)) #define MIN(x, y) ((x) > (y)? (y) : (x)) /* Pack a size and allocated bit into a word(4 bytes) */ #define PACK(size, alloc) ((size) | (alloc)) /* Read and write a word at address p */ #define GET(ptr) (*(unsigned int *)(ptr)) #define PUT(ptr, val) (*(unsigned int *)(ptr) = (val)) /* not affected in the case that the first bit is 1 */ /* if use int, may affected */ /* Read the size and allocated flags from address ptr */ #define GET_SIZE(ptr) (GET(ptr) & ~0x7) #define GET_ALLOC(ptr) (GET(ptr) & 0x1) /* ALIGN return the nearest multiple of 8, so the last 3 bits are always 000 */ /* Given block ptr ptr, compute address of its header and footer */ #define HDRP(ptr) ((char *)(ptr) - WSIZE) #define FTRP(ptr) ((char *)(ptr) + GET_SIZE(HDRP(ptr)) - DSIZE) /* Given block ptr ptr, compute address of next and previous blocks */ #define NEXT_BLKP(ptr) ((char *)(ptr) + GET_SIZE(((char *)(ptr) - WSIZE))) #define PREV_BLKP(ptr) ((char *)(ptr) - GET_SIZE(((char *)(ptr) - DSIZE))) /* ptr means the address of payload */ /* * I don't know why PREV_BLKP is written like this, but according to the information * I have found, it seems that this method can work properly. */ /* Modified micros */ /* Add two micros only for free blocks */ /* Point to next and prev free block, only free blocks have*/ #define PREV_LINKNODE_RP(ptr) ((char *)(ptr)) #define NEXT_LINKNODE_RP(ptr) ((char *)(ptr) + WSIZE) char *heap_ptr = NULL; char *root = NULL; /* * Insert_linknode - insert p to the root of explcit list. */ inline void insert_linknode(char *p){ //inline decreases the cost of calling the func. /* insert p to explcit list. */ char *next = GET(root); if (next != NULL) PUT(PREV_LINKNODE_RP(next), p); PUT(NEXT_LINKNODE_RP(p), next); PUT(root, p); } /* * Del_linknode - delete linknode p. */ inline void del_linknode(char *p){ char *prev = GET(PREV_LINKNODE_RP(p)); char *next = GET(NEXT_LINKNODE_RP(p)); if (prev == NULL){ if (next != NULL) PUT(PREV_LINKNODE_RP(next), 0); PUT(root, next); } else if (prev != NULL){ if (next != NULL) PUT(PREV_LINKNODE_RP(next), prev); PUT(NEXT_LINKNODE_RP(prev), next); } PUT(NEXT_LINKNODE_RP(p), 0); PUT(PREV_LINKNODE_RP(p), 0); } /* * coalesce - Boundary tag coalescing. Return ptr to coalesced block */ static void *coalesce(void *ptr) { size_t prev_alloc = GET_ALLOC(FTRP(PREV_BLKP(ptr))); size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(ptr))); size_t size = GET_SIZE(HDRP(ptr)); if (prev_alloc && next_alloc) { /* left and right used */ //return ptr; } else if (prev_alloc && !next_alloc) { /* only right free */ size += GET_SIZE(HDRP(NEXT_BLKP(ptr))); del_linknode(NEXT_LINKNODE_RP(ptr)); /* remove from linklist*/ PUT(HDRP(ptr), PACK(size, 0)); PUT(FTRP(ptr), PACK(size,0)); } else if (!prev_alloc && next_alloc) { /* only left free */ size += GET_SIZE(HDRP(PREV_BLKP(ptr))); del_linknode(PREV_BLKP(ptr)); PUT(FTRP(ptr), PACK(size, 0)); PUT(HDRP(PREV_BLKP(ptr)), PACK(size, 0)); ptr = PREV_BLKP(ptr); } else { /* both sides free */ size += GET_SIZE(HDRP(PREV_BLKP(ptr))) + GET_SIZE(FTRP(NEXT_BLKP(ptr))); del_linknode(PREV_BLKP(ptr)); del_linknode(NEXT_BLKP(ptr)); PUT(HDRP(PREV_BLKP(ptr)), PACK(size, 0)); PUT(FTRP(NEXT_BLKP(ptr)), PACK(size, 0)); ptr = PREV_BLKP(ptr); } insert_linknode(ptr); return ptr; } /* * extend_heap - Extend heap with free block and return its block pointer */ static void *extend_heap(size_t extendsize) { char *ptr; size_t size; /* Allocate an even number of extendsize to maintain alignment */ size = (extendsize % 2) ? (extendsize+1) * WSIZE : extendsize * WSIZE; if ((long)(ptr = mem_sbrk(size)) == -1) /* this means ptr -> 0xffffffff */ return NULL; /* Initialize free block header,footer and the epilogue header */ PUT(HDRP(ptr), PACK(size, 0)); /* Free block header */ PUT(FTRP(ptr), PACK(size, 0)); /* Free block footer */ // HDRP make a left 8-bits shift, the same to a node size. PUT(NEXT_LINKNODE_RP(ptr), 0); /* Next linknode */ PUT(PREV_LINKNODE_RP(ptr), 0); /* Prev linknode */ PUT(HDRP(NEXT_BLKP(ptr)), PACK(0, 1)); /* New epilogue header */ /* Coalesce free blocks */ return coalesce(ptr); } /* * find_fit - Find a fit for a block with size bytes */ static void *find_fit(size_t asize) { char *tmp = GET(root); int count = 0; while (tmp != NULL){ if (GET_SIZE(HDRP(tmp)) >= asize && (count++) != 0) return tmp; tmp = GET(NEXT_LINKNODE_RP(tmp)); } return NULL; /* No fit */ } /* * place - Place block of size bytes at start of free block ptr * and split if remainder would be at least minimum block size */ static void place(void *ptr, size_t size) { size_t newsize = GET_SIZE(HDRP(ptr)); del_linknode(ptr); if ((newsize - size) >= (2*DSIZE)) { PUT(HDRP(ptr), PACK(size, 1)); PUT(FTRP(ptr), PACK(size, 1)); ptr = NEXT_BLKP(ptr); PUT(HDRP(ptr), PACK(newsize-size, 0)); PUT(FTRP(ptr), PACK(newsize-size, 0)); PUT(NEXT_LINKNODE_RP(ptr), 0); PUT(PREV_LINKNODE_RP(ptr), 0); coalesce(ptr); } else { PUT(HDRP(ptr), PACK(newsize, 1)); PUT(FTRP(ptr), PACK(newsize, 1)); } } int mm_init(void) { /* Create the initial empty heap */ if ((heap_ptr = mem_sbrk(6*WSIZE)) == (void *)-1) /* 0xffffffff */ return -1; PUT(heap_ptr, 0); /* Alignment padding */ PUT(heap_ptr + (1*WSIZE), 0); /* Free prev linknode */ PUT(heap_ptr + (2*WSIZE), 0); /* Free next linknode */ PUT(heap_ptr + (3*WSIZE), PACK(DSIZE, 1)); /* Prologue header */ PUT(heap_ptr + (4*WSIZE), PACK(DSIZE, 1)); /* Prologue footer */ PUT(heap_ptr + (5*WSIZE), PACK(0, 1)); /* Epilogue header */ root = heap_ptr + (1 * WSIZE); heap_ptr += (4*WSIZE); /* Extend the empty heap with a free block of CHUNKSIZE bytes */ if (extend_heap(CHUNKSIZE/WSIZE) == NULL) return -1; return 0; } void *mm_malloc(size_t size) { size_t newsize; /* Adjusted block size */ size_t extendsize; /* Amount to extend heap if no fit */ char *ptr; if (heap_ptr == NULL){ mm_init(); } if (size == 0) return NULL; /* Adjust block size to include overhead and alignment reqs. */ /* Need to use this method, but I don't know why */ if (size <= DSIZE) newsize = 2*DSIZE; else newsize = DSIZE * ((size + (DSIZE) + (DSIZE-1)) / DSIZE); /* Search the free list for a fit */ if ((ptr = find_fit(newsize)) != NULL) { place(ptr, newsize); return ptr; } /* No fit found. Get more memory and place the block */ extendsize = MAX(newsize,CHUNKSIZE); if ((ptr = extend_heap(extendsize/WSIZE)) == NULL) return NULL; place(ptr, newsize); return ptr; } void mm_free(void *ptr) { if (ptr == NULL) return; size_t size = GET_SIZE(HDRP(ptr)); PUT(HDRP(ptr), PACK(size, 0)); PUT(FTRP(ptr), PACK(size, 0)); /* Reset linknodes */ PUT(NEXT_LINKNODE_RP(ptr), 0); PUT(PREV_LINKNODE_RP(ptr), 0); coalesce(ptr); } void *mm_realloc(void *ptr, size_t size) { size_t oldsize; void *newptr; if(size == 0) { mm_free(ptr); return 0; } if(ptr == NULL) { return mm_malloc(size); } newptr = mm_malloc(size); /* realloc failed */ if(newptr == NULL) { return 0; } /* Copy the old heap area. */ oldsize = GET_SIZE(HDRP(ptr)); if(size < oldsize) oldsize = size; memcpy(newptr, ptr, oldsize); /* Free the old block. */ mm_free(ptr); return newptr; }