430 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			430 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <malloc.h>
 | |
| #include <string.h>
 | |
| #include <assert.h>
 | |
| #include "sc.h"
 | |
| #include "sctracker.h"
 | |
| 
 | |
| memuse_list_t *heapusage = NULL;
 | |
| memuse_list_t *stackusage = NULL;
 | |
| funcenum_t *firstenum = NULL;
 | |
| funcenum_t *lastenum = NULL;
 | |
| pstruct_t *firststruct = NULL;
 | |
| pstruct_t *laststruct = NULL;
 | |
| 
 | |
| structarg_t *pstructs_getarg(pstruct_t *pstruct, const char *member)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	for (i=0; i<pstruct->argcount; i++)
 | |
| 	{
 | |
| 		if (strcmp(pstruct->args[i]->name, member) == 0)
 | |
| 		{
 | |
| 			return pstruct->args[i];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| pstruct_t *pstructs_add(const char *name)
 | |
| {
 | |
| 	pstruct_t *p = (pstruct_t *)malloc(sizeof(pstruct_t));
 | |
| 	
 | |
| 	memset(p, 0, sizeof(pstruct_t));
 | |
| 	strcpy(p->name, name);
 | |
| 	
 | |
| 	if (!firststruct)
 | |
| 	{
 | |
| 		firststruct = p;
 | |
| 		laststruct = p;
 | |
| 	} else {
 | |
| 		laststruct->next = p;
 | |
| 		laststruct = p;
 | |
| 	}
 | |
| 
 | |
| 	return p;
 | |
| }
 | |
| 
 | |
| void pstructs_free()
 | |
| {
 | |
| 	pstruct_t *p, *next;
 | |
| 
 | |
| 	p = firststruct;
 | |
| 	while (p)
 | |
| 	{
 | |
| 		while (p->argcount--)
 | |
| 		{
 | |
| 			free(p->args[p->argcount]);
 | |
| 		}
 | |
| 		free(p->args);
 | |
| 		next = p->next;
 | |
| 		free(p);
 | |
| 		p = next;
 | |
| 	}
 | |
| 	firststruct = NULL;
 | |
| 	laststruct = NULL;
 | |
| }
 | |
| 
 | |
| pstruct_t *pstructs_find(const char *name)
 | |
| {
 | |
| 	pstruct_t *p = firststruct;
 | |
| 
 | |
| 	while (p)
 | |
| 	{
 | |
| 		if (strcmp(p->name, name) == 0)
 | |
| 		{
 | |
| 			return p;
 | |
| 		}
 | |
| 		p = p->next;
 | |
| 	}
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| structarg_t *pstructs_addarg(pstruct_t *pstruct, const structarg_t *arg)
 | |
| {
 | |
| 	structarg_t *newarg;
 | |
| 	int i;
 | |
| 
 | |
| 	for (i=0; i<pstruct->argcount; i++)
 | |
| 	{
 | |
| 		if (strcmp(pstruct->args[i]->name, arg->name) == 0)
 | |
| 		{
 | |
| 			/* Don't allow dup names */
 | |
| 			return NULL;
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	newarg = (structarg_t *)malloc(sizeof(structarg_t));
 | |
| 
 | |
| 	memcpy(newarg, arg, sizeof(structarg_t));
 | |
| 
 | |
| 	if (pstruct->argcount == 0)
 | |
| 	{
 | |
| 		pstruct->args = (structarg_t **)malloc(sizeof(structarg_t *) * 1);
 | |
| 	} else {
 | |
| 		pstruct->args = (structarg_t **)realloc(
 | |
| 							pstruct->args,
 | |
| 							sizeof(structarg_t *) * (pstruct->argcount + 1));
 | |
| 	}
 | |
| 
 | |
| 	newarg->offs = pstruct->argcount * sizeof(cell);
 | |
| 	newarg->index = pstruct->argcount;
 | |
| 	pstruct->args[pstruct->argcount++] = newarg;
 | |
| 
 | |
| 	return newarg;
 | |
| }
 | |
| 
 | |
| void funcenums_free()
 | |
| {
 | |
| 	funcenum_t *e, *next;
 | |
| 
 | |
| 	e = firstenum;
 | |
| 	while (e)
 | |
| 	{
 | |
| 		functag_t *tag, *nexttag;
 | |
| 		tag = e->first;
 | |
| 		while (tag)
 | |
| 		{
 | |
| 			nexttag = tag->next;
 | |
| 			free(tag);
 | |
| 			tag = nexttag;
 | |
| 		}
 | |
| 		next = e->next;
 | |
| 		free(e);
 | |
| 		e = next;
 | |
| 	}
 | |
| 
 | |
| 	firstenum = NULL;
 | |
| 	lastenum = NULL;
 | |
| }
 | |
| 
 | |
| funcenum_t *funcenums_find_byval(int value)
 | |
| {
 | |
| 	funcenum_t *e = firstenum;
 | |
| 
 | |
| 	while (e)
 | |
| 	{
 | |
| 		if (e->value == value)
 | |
| 		{
 | |
| 			return e;
 | |
| 		}
 | |
| 		e = e->next;
 | |
| 	}
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| funcenum_t *funcenums_add(const char *name)
 | |
| {
 | |
| 	funcenum_t *e = (funcenum_t *)malloc(sizeof(funcenum_t));
 | |
| 
 | |
| 	memset(e, 0, sizeof(funcenum_t));
 | |
| 
 | |
| 	if (firstenum == NULL)
 | |
| 	{
 | |
| 		firstenum = e;
 | |
| 		lastenum = e;
 | |
| 	} else {
 | |
| 		lastenum->next = e;
 | |
| 		lastenum = e;
 | |
| 	}
 | |
| 
 | |
| 	strcpy(e->name, name);
 | |
| 	e->value = pc_addfunctag((char *)name);
 | |
| 
 | |
| 	return e;
 | |
| }
 | |
| 
 | |
| functag_t *functags_add(funcenum_t *en, functag_t *src)
 | |
| {
 | |
| 	functag_t *t = (functag_t *)malloc(sizeof(functag_t));
 | |
| 	
 | |
| 	memcpy(t, src, sizeof(functag_t));
 | |
| 
 | |
| 	t->next = NULL;
 | |
| 
 | |
| 	if (en->first == NULL)
 | |
| 	{
 | |
| 		en->first = t;
 | |
| 		en->last = t;
 | |
| 	} else {
 | |
| 		en->last->next = t;
 | |
| 		en->last = t;
 | |
| 	}
 | |
| 
 | |
| 	return t;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Creates a new mem usage tracker entry
 | |
|  */
 | |
| void _push_memlist(memuse_list_t **head)
 | |
| {
 | |
|   memuse_list_t *newlist = (memuse_list_t *)malloc(sizeof(memuse_list_t));
 | |
|   if (*head != NULL)
 | |
|   {
 | |
|     newlist->list_id = (*head)->list_id + 1;
 | |
|   } else {
 | |
|     newlist->list_id = 0;
 | |
|   }
 | |
|   newlist->prev = *head;
 | |
|   newlist->head = NULL;
 | |
|   *head = newlist;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Pops a heap list but does not free it.
 | |
|  */
 | |
| memuse_list_t *_pop_save_memlist(memuse_list_t **head)
 | |
| {
 | |
|   memuse_list_t *oldlist = *head;
 | |
|   *head = (*head)->prev;
 | |
|   return oldlist;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Marks a memory usage on a memory list
 | |
|  */
 | |
| int _mark_memlist(memuse_list_t *head, int type, int size)
 | |
| {
 | |
|   memuse_t *use;
 | |
|   if (type==MEMUSE_STATIC && size==0)
 | |
|   {
 | |
|     return 0;
 | |
|   }
 | |
|   use=head->head;
 | |
|   if (use && (type==MEMUSE_STATIC) 
 | |
|       && (use->type == type))
 | |
|   {
 | |
|     use->size += size;
 | |
|   } else {
 | |
|     use=(memuse_t *)malloc(sizeof(memuse_t));
 | |
|     use->type=type;
 | |
|     use->size=size;
 | |
|     use->prev=head->head;
 | |
|     head->head=use;
 | |
|   }
 | |
|   return size;
 | |
| }
 | |
| 
 | |
| void _reset_memlist(memuse_list_t **head)
 | |
| {
 | |
|   memuse_list_t *curlist = *head;
 | |
|   memuse_list_t *tmplist;
 | |
|   while (curlist) {
 | |
|     memuse_t *curuse = curlist->head;
 | |
|     memuse_t *tmpuse;
 | |
|     while (curuse) {
 | |
|       tmpuse = curuse->prev;
 | |
|       free(curuse);
 | |
|       curuse = tmpuse;
 | |
|     }
 | |
|     tmplist = curlist->prev;
 | |
|     free(curlist);
 | |
|     curlist = tmplist;
 | |
|   }
 | |
|   *head = NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Wrapper for pushing the heap list
 | |
|  */
 | |
| void pushheaplist()
 | |
| {
 | |
|   _push_memlist(&heapusage);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Wrapper for popping and saving the heap list
 | |
|  */
 | |
| memuse_list_t *popsaveheaplist()
 | |
| {
 | |
|   return _pop_save_memlist(&heapusage);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Wrapper for marking the heap
 | |
|  */
 | |
| int markheap(int type, int size)
 | |
| {
 | |
|   return _mark_memlist(heapusage, type, size);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Wrapper for pushing the stack list
 | |
|  */
 | |
| void pushstacklist()
 | |
| {
 | |
|   _push_memlist(&stackusage);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Wrapper for marking the stack
 | |
|  */
 | |
| int markstack(int type, int size)
 | |
| {
 | |
|   return _mark_memlist(stackusage, type, size);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Generates code to free all heap allocations on a tracker
 | |
|  */
 | |
| void _heap_freeusage(memuse_list_t *heap, int dofree)
 | |
| {
 | |
|   memuse_t *cur=heap->head;
 | |
|   memuse_t *tmp;
 | |
|   while (cur)
 | |
|   {
 | |
|     if (cur->type == MEMUSE_STATIC)
 | |
| 	{
 | |
|       modheap((-1)*cur->size*sizeof(cell));
 | |
|     } else {
 | |
|       modheap_i();
 | |
|     }
 | |
|     if (dofree)
 | |
|     {
 | |
|       tmp=cur->prev;
 | |
|       free(cur);
 | |
|       cur=tmp;
 | |
|     } else {
 | |
|       cur=cur->prev;
 | |
|     }
 | |
|   }
 | |
|   if (dofree)
 | |
|   {
 | |
|     heap->head=NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void _stack_genusage(memuse_list_t *stack, int dofree)
 | |
| {
 | |
|   memuse_t *cur = stack->head;
 | |
|   memuse_t *tmp;
 | |
|   while (cur)
 | |
|   {
 | |
|     if (cur->type == MEMUSE_DYNAMIC)
 | |
| 	{
 | |
|       /* no idea yet */
 | |
|       assert(0);
 | |
| 	} else {
 | |
|       modstk(cur->size * sizeof(cell));
 | |
| 	}
 | |
| 	if (dofree)
 | |
| 	{
 | |
|       tmp = cur->prev;
 | |
|       free(cur);
 | |
|       cur = tmp;
 | |
| 	} else {
 | |
|       cur = cur->prev;
 | |
| 	}
 | |
|   }
 | |
|   if (dofree)
 | |
|   {
 | |
|     stack->head = NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Pops a heap list and frees it.
 | |
|  */
 | |
| void popheaplist()
 | |
| {
 | |
|   memuse_list_t *oldlist;
 | |
|   assert(heapusage!=NULL);
 | |
| 
 | |
|   _heap_freeusage(heapusage, 1);
 | |
|   assert(heapusage->head==NULL);
 | |
| 
 | |
|   oldlist=heapusage->prev;
 | |
|   free(heapusage);
 | |
|   heapusage=oldlist;
 | |
| }
 | |
| 
 | |
| void genstackfree(int stop_id)
 | |
| {
 | |
|   memuse_list_t *curlist = stackusage;
 | |
|   while (curlist && curlist->list_id > stop_id)
 | |
|   {
 | |
|     _stack_genusage(curlist, 0);
 | |
|     curlist = curlist->prev;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void genheapfree(int stop_id)
 | |
| {
 | |
|   memuse_list_t *curlist = heapusage;
 | |
|   while (curlist && curlist->list_id > stop_id)
 | |
|   {
 | |
|     _heap_freeusage(curlist, 0);
 | |
|     curlist = curlist->prev;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void popstacklist(int codegen)
 | |
| {
 | |
|   memuse_list_t *oldlist;
 | |
|   assert(stackusage != NULL);
 | |
| 
 | |
|   if (codegen)
 | |
|   {
 | |
|     _stack_genusage(stackusage, 1);
 | |
|     assert(stackusage->head==NULL);
 | |
|   }
 | |
| 
 | |
|   oldlist = stackusage->prev;
 | |
|   free(stackusage);
 | |
|   stackusage = oldlist;
 | |
| }
 | |
| 
 | |
| void resetstacklist()
 | |
| {
 | |
|   _reset_memlist(&stackusage);
 | |
| }
 | |
| 
 | |
| void resetheaplist()
 | |
| {
 | |
|   _reset_memlist(&heapusage);
 | |
| }
 |