home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_300
/
357_01
/
cstar1.exe
/
MEM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-18
|
11KB
|
519 lines
/*
C* -- Memory management routines and node allocation routines.
source: mem.c
started: September 20, 1985
version:
May 8, 1987
March 7, 1989
PUBLIC DOMAIN SOFTWARE
The CSTAR program was placed in the public domain on June 15, 1991,
by its author and sole owner,
Edward K. Ream
1617 Monroe Street
Madison, WI 53711
(608) 257-0802
CSTAR may be used for any commercial or non-commercial purpose.
See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
*/
#include "cstar.h"
/*
----- NODE ALLOCATION ROUTINES -----
*/
struct node * new_pnode (int size);
void * node_dupl (byte *s, int size);
struct type_node *
new_tnode (void);
struct node * new_cnode (void);
struct node * new_rloc (int regfield);
struct node * new_grloc (int regfield);
struct node * new_cloc (long constant);
struct node * new_clabel (void);
struct node * new_culabel (char * symbol);
struct iblock * new_iblock (unsigned long size);
void * mg_alloc (int n);
void mg_free (char *p);
void * ml_alloc (int n);
void ml_release (void);
void mm_init (void);
void mm_stat (void);
/*
Create a parse node which is generally compatible with other nodes
contained within expressions, and then get_token().
node is zero-filled.
*/
struct node *
new_pnode(int size)
{
register struct node *p;
TRACEPB("new_pnode", printf("(%d)\n", size));
/* allocate the node */
p = (struct node *) ml_alloc(size);
p -> n_type = t_type;
p -> n_linno = t_line;
RETURN_PTR("new_pnode", p);
}
/*
Reproduce a parse node
*/
void *
node_dupl(register byte *s, register int size)
{
register byte *d, *dd;
register int i;
TRACEPB("node_dupl", printf("(%s, %d)\n", s, size));
if (sizeof(int) == 2) {
i = size >> 1;
}
else {
fatal("mem: node_dupl: check sizeof(int)");
}
d = dd = ml_alloc(size);
while (i--) {
*((int *)d)++ = *((int *)s)++;
}
RETURN_PTR("node_dupl", dd);
}
/*
Create a new type_node, and fill it as though it is a base
integer type, so as to help prevent crashes from unset
entries.
type_nodes are always to be copied if they need to
be altered in a context separate from their creation,
since there may always be more than one link into any
given node
node is zero filled
*/
struct type_node *
new_tnode(void)
{
register struct type_node *t;
TICKB("new_tnode");
switch(scope.s_scope) {
case FILE_SCOPE:
case FNDEF_SCOPE:
TRACEP("new_tnode", printf("global\n"));
t = (struct type_node *) mg_alloc(sizeof(struct type_node));
break;
default:
t = (struct type_node *) ml_alloc(sizeof(struct type_node));
break;
}
t -> t_typtok = INT_TYPE;
t -> t_tsize = 2L;
RETURN_PTR("new_tnode", t);
}
/*
Allocate a new code node with two arg fields.
CAUTION: the peephole requires that nodes be of uniform size,
since it occasionally adds an argument to a node.
*/
struct node *
new_cnode(void)
{
register struct node *p;
TICKB("new_cnode");
p = (struct node *) ml_alloc(sizeof(struct code_node));
RETURN_PTR("new_cnode", p);
}
/*
Allocate a loc node standing for a register.
*/
struct node *
new_rloc(register int regfield)
{
register struct node *p;
TRACEPB("new_rloc", printf("(%d)\n", regfield));
p = (struct node *) ml_alloc(sizeof (struct loc_node));
p -> n_linno = t_line;
p -> n_type = ID_TOK;
p -> n_reg1 = regfield;
RETURN_PTR("new_rloc", p);
}
struct node *
new_grloc(register int regfield)
{
register struct node *p;
TRACEPB("new_grloc", printf("(%d)\n", regfield));
p = (struct node *) mg_alloc(sizeof (struct loc_node));
p -> n_linno = t_line;
p -> n_type = ID_TOK;
p -> n_reg1 = regfield;
RETURN_PTR("new_grloc", p);
}
/*
Allocate a loc node standing for a constant.
*/
struct node *
new_cloc(long constant)
{
register struct node *p;
TRACEPB("new_cloc", printf("(%ld)\n", constant));
p = (struct node *) ml_alloc(sizeof (struct loc_node));
p -> n_linno = t_line;
p -> n_type = ID_TOK;
p -> n_const = constant;
RETURN_PTR("new_cloc", p);
}
/*
Return a pointer to a new internal label code node.
All fields are filled in with default values.
*/
struct node *
new_clabel(void)
{
register struct node *p;
TICKB("new_clabel");
p = (struct node *) ml_alloc(sizeof(struct clabel_node));
p -> c_code = O_LABEL; /* Header fields. */
p -> c_mark = FALSE; /* Non-header fields. */
p -> c_labnum = ++cur_lab;
RETURN_PTR("new_clabel", p);
}
/*
Return a pointer to a new internal label code node.
All fields are filled in with default values.
*/
struct node *
new_culabel(char * symbol)
{
register struct node *p;
TRACEPB("new_culabel", printf("(%s)\n", symbol));
p = (struct node *) ml_alloc(sizeof(struct culabel_node));
p -> c_code = O_ULABEL; /* Header fields. */
p -> c_mark = FALSE; /* Non-header fields. */
p -> c_labsym = str_lalloc(symbol);
p -> c_labnum = ++u_lab; /* First assignment is 1! */
RETURN_PTR("new_culabel", p);
}
/*
Return an initializer block of a given data size, measured in long
entries. These blocks are made in the local scope even for file
scope initializers. If it becomes necessary to group initializers,
these blocks will have to be made in file scope, as will all
declarations, typenodes, etc.
*/
struct iblock *
new_iblock(unsigned long size)
{
register struct iblock *p;
TRACEPB("new_iblock", printf("(%lu)\n", size));
if (size > IDATA_SIZE) {
size = IDATA_SIZE;
}
p = (struct iblock *) ml_alloc( (unsigned int)
(sizeof(*p) + sizeof(p -> idata[0]) * (unsigned int) size) );
p -> idim = size;
RETURN_PTR("new_iblock", p);
}
/*
----- MEMORY ALLOCATION ROUTINES -----
These routines handle two kinds of memory:
local memory:
This memory is deallocated at the end of every function.
The ml_alloc() routine gets local memory.
The ml_release() routine releases ALL local memory.
The local memory is obtained from the system in fixed-sized chunks.
Each chunk contains a pointer to the next chunk.
The ml_alloc() routine allocates another chunk if needed, then returns
a pointer into the latest chunk.
The ml_release() routine just releases all chunks.
global memory:
This memory is used for global information that is NEVER deallocated.
It is also possible to use this memory for temporary memory, although
it is more efficient to use local memory if not too much is needed.
The mg_alloc() routine gets global memory.
The mg_free() routine releases memory obtained by mg_free().
This memory is allocated and released using alloc() and free().
*/
/*
Define variables used by this routine.
*/
static struct chunk {
struct chunk * mm_next; /* Next pointer */
char mm_data [DATA_SIZE]; /* Data area */
};
static struct chunk * local_list;
static struct chunk * free_list;
static long ml_c; /* Current local count. */
static char * ml_p; /* Current local pointer. */
static long g_tot; /* Total global memory allocated. */
static long l_tot; /* Cumulative local memory allocation. */
static long l_blocks; /* Non-cumulative local chunks allocated. */
/*
Allocate n bytes using calloc(), assumed to get memory from system
The returned memory IS zeroed.
*/
void *
mg_alloc(int n)
{
register byte *p;
TRACEPB("mg_alloc", printf("(%d) ", n));
/* Align the request now. */
while (n & (sizeof(short int)-1) ) {
n++;
}
p = calloc(1, n);
if (p == NULL) {
printf("sorry, out of memory\n");
printf("%ld (0x%lx) bytes allocated\n", g_tot, g_tot);
exit(0);
}
/* Update statistic. */
g_tot += (long)n;
RETURN_PTR("mg_alloc", p);
}
/*
Free memory allocated by mg_alloc().
*/
void
mg_free(char *p)
{
TRACEP("mg_free", printf("(%p)\n", p));
free(p);
}
/*
Allocate bytes from local memory area.
Return pointer to allocated area or NULL.
*/
void *
ml_alloc(register int n)
{
register byte *p;
register int x;
struct chunk *cp;
/* Align the request now. */
TRACEPB("ml_alloc", printf("(%d) ", n));
if (n & 1) {
n++;
}
/* Check to see if there is room in the current chunk. */
if ((long)n > ml_c) {
if (cp = free_list) {
/* Get block from the free list. */
free_list = cp -> mm_next;
/* set ml_p to its beginning */
ml_p = &((cp -> mm_data)[0]);
/* clear the block */
p = (void *) ml_p;
x = DATA_SIZE / sizeof(long);
do {
* ((long *) p)++ = 0L;
}
while (--x);
}
else {
/* Get a newly allocated and cleared block. */
cp = (struct chunk *)mg_alloc(sizeof(struct chunk));
ml_p = &((cp -> mm_data)[0]);
/* Update statistic. */
l_blocks++;
}
/* Link the block to the local list. */
cp -> mm_next = local_list;
local_list = cp;
ml_c = DATA_SIZE;
/* Check for oversize request. */
if (n > DATA_SIZE) {
fatal("ml_alloc: requested chunk too long");
}
}
/* Allocate the memory. */
p = ml_p;
ml_p += n;
ml_c -= (long)n;
l_tot += (long)n;
RETURN_PTR("ml_alloc", p);
}
/* Deallocate all local memory. */
void
ml_release(void)
{
register struct chunk *p, *q;
#ifdef SHERLOCK
register long c = 0;
#endif /* SHERLOCK */
/* Put all local chunks on the free list. */
TICKB("ml_release");
if (local_list) {
p = local_list;
while(p -> mm_next) {
p = p -> mm_next;
}
/* p points to last of local list */
/* Put the local list at the head of the free list. */
p -> mm_next = free_list;
free_list = local_list;
}
TRACEP("ml_release",
p = free_list;
while (p) {
c++;
p = p -> mm_next;
}
printf("%ld blocks on free list 0x%lx bytes\n",c, c*DATA_SIZE);
);
/* Initialize. */
local_list = NULL;
ml_c = 0L;
ml_p = NULL;
TICKX("ml_release");
}
/* Define TPA block for BDOS get TPA call. */
struct TPAB {
int param; /* 0 for get, 1 or 2 for set */
char * low;
char * high;
};
/* Define format of the start of the base page. */
struct BASE_PAGE {
long lowtpa;
long hightpa;
char * text_start;
long text_length;
char * data_start;
long data_length;
char * bss_start;
long bss_length;
};
/*
Initialize the memory manager.
*/
void
mm_init(void)
{
TICK("mm_init");
/* Initialize local memory. */
local_list = NULL;
free_list = NULL;
ml_c = 0;
/* Initialize statistics. */
g_tot = 0;
l_tot = 0;
l_blocks = 0;
}
/*
Print statistics about memory manager.
*/
void
mm_stat(void)
{
SL_DISABLE();
printf("mm_stat: l_tot: %ld (0x%lx), l_blocks: %ld\n",
l_tot, l_tot, l_blocks);
printf("mm_stat: g_tot: %ld (0x%lx)\n", g_tot, g_tot);
}