home *** CD-ROM | disk | FTP | other *** search
- /*
- 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);
- }
-