/*
|
|
* 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
#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;
|
|
}
|