#include "os.h" #include "y.tab.h" #include "lnode.h" #include "config.h" #define NUM_CHUNK 50 /* Number of chunks to allocate */ extern int current_line; /* lexical.l */ extern char string_space[], *end_of_string_space; /* string_space.c */ /* comm1.c */ extern void add_message(char *fmt, ...); /* simulate.c */ extern void fatal(char *fmt, ...); /* main.c */ extern void *xalloc(int size); /* string_space.h */ extern char *find_string_space (char *str); int tot_alloc_lnode; int tot_alloc_strings; int tot_lnode_block; int lnode_size[(L_MAX >> L_SHIFT) + 1]; struct lnode_var_def *prog_status; static int tot_lnode_single; static int tot_lnode_number; static int tot_lnode_name; static int tot_lnode_variable; static int tot_lnode_1; static struct lnode_2 *lnode_2_list; static int tot_lnode_2; static int tot_lnode_3; static int tot_lnode_def; static int tot_var_def; static int tot_funcall; struct lnode_single *alloc_lnode_single (int type) { struct lnode_single *p; p = (struct lnode_single *) xalloc (sizeof (struct lnode_single)); p->type = type; p->line = current_line + L_SINGLE; tot_lnode_single++; return p; } struct lnode_number *alloc_lnode_number (int type, int number) { struct lnode_number *p; p = (struct lnode_number *) xalloc (sizeof (struct lnode_number)); p->type = type; p->number = number; p->line = current_line + L_NUMBER; tot_lnode_number++; return p; } /* * Try tro use string_space if possible. * Be carfule not to free() such an area. */ struct lnode_name *alloc_lnode_name (int type, char *name) { struct lnode_name *p; char *spn; p = (struct lnode_name *) xalloc (sizeof (struct lnode_name)); p->type = type; spn = find_string_space (name); if (spn) { free (name); p->name = spn; } else { p->name = name; tot_alloc_strings += strlen (name) + 1; } p->line = current_line + L_NAME; tot_lnode_name++; return p; } struct lnode_variable *alloc_lnode_variable (int type, int number) { struct lnode_variable *p; p = (struct lnode_variable *) xalloc (sizeof (struct lnode_variable)); p->type = type; p->number = number; p->line = current_line + L_VARIABLE; tot_lnode_variable++; return p; } struct lnode_1 *alloc_lnode_1 (int type, struct lnode *expr) { struct lnode_1 *p; p = (struct lnode_1 *) xalloc (sizeof (struct lnode_1)); p->type = type; p->expr = expr; p->line = current_line + L_1; tot_lnode_1++; return p; } struct lnode_2 *alloc_lnode_2 (int type, struct lnode *expr1, struct lnode *expr2) { struct lnode_2 *p; if (!lnode_2_list) { int i; lnode_2_list = (struct lnode_2 *) xalloc (NUM_CHUNK * sizeof (struct lnode_2)); for (p = lnode_2_list, i = 0; i < NUM_CHUNK - 1; p++, i++) p->expr1 = (struct lnode *) (p + 1); p->expr1 = 0; tot_lnode_2 += NUM_CHUNK; } p = lnode_2_list; lnode_2_list = (struct lnode_2 *) lnode_2_list->expr1; p->type = type; p->line = current_line + L_2; p->expr1 = expr1; p->expr2 = expr2; return p; } struct lnode_3 *alloc_lnode_3 (int type, struct lnode *expr1, struct lnode *expr2, struct lnode *expr3) { struct lnode_3 *p; p = (struct lnode_3 *) xalloc (sizeof (struct lnode_3)); p->type = type; p->line = current_line + L_3; p->expr1 = expr1; p->expr2 = expr2; p->expr3 = expr3; tot_lnode_3++; return p; } struct lnode_def *alloc_lnode_def (int type, char *name, struct lnode *block, int num_var) { struct lnode_def *p; char *spn; p = (struct lnode_def *) xalloc (sizeof (struct lnode_def)); p->type = type; p->line = current_line + L_DEF; spn = find_string_space (name); if (spn) { free (name); p->name = spn; } else { p->name = name; tot_alloc_strings += strlen (name) + 1; } p->num_var = num_var; p->block = block; p->next = 0; p->num_ref = 0; tot_lnode_def++; return p; } void alloc_lnode_var_def (int type, char *name, int num_var) { struct lnode_var_def *p; p = (struct lnode_var_def *) xalloc (sizeof (struct lnode_var_def)); p->type = type; p->line = current_line + L_VAR_DEF; p->name = name; p->num_var = num_var; p->next = prog_status; prog_status = p; tot_var_def++; } struct lnode_funcall *alloc_lnode_funcall (int type, char *name, struct lnode *arg) { struct lnode_funcall *p; char *spn; p = (struct lnode_funcall *) xalloc (sizeof (struct lnode_funcall)); p->type = type; p->line = current_line + L_FUNCALL; spn = find_string_space (name); if (spn) { free (name); p->name = spn; } else { p->name = name; tot_alloc_strings += strlen (name) + 1; } p->expr = arg; tot_funcall++; return p; } struct lnode_block *alloc_lnode_block (struct lnode *p) { int size, num; char *block, *block2; struct lnode *l, *next; struct lnode_block *ret; for (num = 0, size = 0, l = p; l; l = l->a2) { size += lnode_size[l->a1->line >> L_SHIFT]; num++; } if (num == 1) { /* Only one statement. No need to make a block ! */ struct lnode *stat; stat = p->a1; free_lnode (p, 1); return (struct lnode_block *) stat; } block = xalloc (sizeof (int) + size); block2 = block; for (l = p; l; l = next) { int s; s = lnode_size[l->a1->line >> L_SHIFT]; memcpy (block2, (char *) l->a1, s); free_lnode (l->a1, 0); /* Node has been copied. */ l->a1 = 0; block2 += s; next = l->a2; free_lnode (l, 1); } ret = (struct lnode_block *) xalloc (sizeof (struct lnode_block)); ret->type = F_BLOCK; ret->line = current_line + L_BLOCK; ret->block = block; ret->num_nodes = num; tot_lnode_block++; return ret; } void print_lnode_status (int tot_before_this) { int tot = tot_lnode_number * sizeof (struct lnode_number) + tot_lnode_name * sizeof (struct lnode_name) + tot_lnode_variable * sizeof (struct lnode_variable) + tot_lnode_1 * sizeof (struct lnode_1) + tot_lnode_2 * sizeof (struct lnode_2) + tot_lnode_3 * sizeof (struct lnode_3) + tot_var_def * sizeof (struct lnode_var_def) + tot_funcall * sizeof (struct lnode_funcall) + tot_lnode_def * sizeof (struct lnode_def) + tot_lnode_block * sizeof (struct lnode_block) + tot_before_this; add_message ("lnode:\n"); add_message (" single: %5d %6d\n", tot_lnode_single, tot_lnode_single * sizeof (struct lnode_single)); add_message (" numbers: %5d %6d\n", tot_lnode_number, tot_lnode_number * sizeof (struct lnode_number)); add_message (" names: %5d %6d\n", tot_lnode_name, tot_lnode_name * sizeof (struct lnode_name)); add_message (" variables: %5d %6d\n", tot_lnode_variable, tot_lnode_variable * sizeof (struct lnode_variable)); add_message (" 1 size expr:%5d %6d\n", tot_lnode_1, tot_lnode_1 * sizeof (struct lnode_1)); add_message (" 2 size expr:%5d %6d\n", tot_lnode_2, tot_lnode_2 * sizeof (struct lnode_2)); add_message (" 3 size expr:%5d %6d\n", tot_lnode_3, tot_lnode_3 * sizeof (struct lnode_3)); add_message (" functions: %5d %6d\n", tot_lnode_def, tot_lnode_def * sizeof (struct lnode_def)); add_message (" glob vars: %5d %6d\n", tot_var_def, tot_var_def * sizeof (struct lnode_var_def)); add_message (" fun calls: %5d %6d\n", tot_funcall, tot_funcall * sizeof (struct lnode_funcall)); add_message (" blocks: %5d %6d\n", tot_lnode_block, tot_lnode_block * sizeof (struct lnode_block)); add_message (" Total bytes %6d\n", tot); } /* * Setup fast access to the size of an lnode. */ void compute_lnode_size (void) { lnode_size[L_SINGLE >> L_SHIFT] = sizeof (struct lnode_single); lnode_size[L_NUMBER >> L_SHIFT] = sizeof (struct lnode_number); lnode_size[L_NAME >> L_SHIFT] = sizeof (struct lnode_name); lnode_size[L_VARIABLE >> L_SHIFT] = sizeof (struct lnode_variable); lnode_size[L_1 >> L_SHIFT] = sizeof (struct lnode_1); lnode_size[L_2 >> L_SHIFT] = sizeof (struct lnode_2); lnode_size[L_3 >> L_SHIFT] = sizeof (struct lnode_3); lnode_size[L_DEF >> L_SHIFT] = sizeof (struct lnode_def); lnode_size[L_VARIABLE >> L_SHIFT] = sizeof (struct lnode_var_def); lnode_size[L_FUNCALL >> L_SHIFT] = sizeof (struct lnode_funcall); lnode_size[L_BLOCK >> L_SHIFT] = sizeof (struct lnode_block); } void free_lnode (struct lnode *p, int update_count) { switch (p->line & L_MASK) { case L_SINGLE: if (update_count) tot_lnode_single--; break; case L_NUMBER: if (update_count) tot_lnode_number--; break; case L_NAME: if (update_count) tot_lnode_name--; break; case L_VARIABLE: if (update_count) tot_lnode_variable--; break; case L_1: if (update_count) tot_lnode_1--; break; case L_2: ((struct lnode_2 *) p)->expr1 = (struct lnode *) lnode_2_list; lnode_2_list = (struct lnode_2 *) p; return; case L_3: if (update_count) tot_lnode_3--; break; case L_DEF: if (update_count) tot_lnode_def--; break; case L_VAR_DEF: if (update_count) tot_var_def--; break; case L_FUNCALL: if (update_count) tot_funcall--; break; case L_BLOCK: if (update_count) tot_lnode_block--; break; default: fatal ("Bad type in lnode_size(): 0x%x\n", p->line & L_MASK); } free (p); } void add_prog_ref (struct lnode_def *p) { p->num_ref++; } int free_prog (struct lnode_def *p) { p->num_ref--; if (p->num_ref > 0) return 0; free_sub_part ((struct lnode *)p, 1); return 1; } /* * Free the space of one node, and all linkes from it. * When a L_BLOCK is freed, don't call free_lnode() with the nodes * in the top of the block, because these are allocated in one big * chunk. */ void free_sub_part (struct lnode *p, int do_free) { extern int tot_alloc_strings; if (p == 0) return; switch (p->line & L_MASK) { case L_SINGLE: break; case L_NUMBER: break; case L_NAME: if (((struct lnode_name *) p)->name < string_space || ((struct lnode_name *) p)->name >= end_of_string_space) { tot_alloc_strings -= strlen (((struct lnode_name *) p)->name) + 1; free (((struct lnode_name *) p)->name); } ((struct lnode_name *) p)->name = 0; break; case L_VARIABLE: break; case L_1: free_sub_part (((struct lnode_1 *) p)->expr, 1); ((struct lnode_1 *) p)->expr = 0; break; case L_2: free_sub_part (((struct lnode_2 *) p)->expr1, 1); ((struct lnode_2 *) p)->expr1 = 0; free_sub_part (((struct lnode_2 *) p)->expr2, 1); ((struct lnode_2 *) p)->expr2 = 0; break; case L_3: free_sub_part (((struct lnode_3 *) p)->expr1, 1); ((struct lnode_3 *) p)->expr1 = 0; free_sub_part (((struct lnode_3 *) p)->expr2, 1); ((struct lnode_3 *) p)->expr2 = 0; free_sub_part (((struct lnode_3 *) p)->expr3, 1); ((struct lnode_3 *) p)->expr3 = 0; break; case L_DEF: { struct lnode_def *dp = (struct lnode_def *) p; if (dp->name < string_space || dp->name >= end_of_string_space) { tot_alloc_strings -= strlen (dp->name) + 1; free (dp->name); } dp->name = 0; free_sub_part (dp->block, 1); dp->block = 0; if (dp->next) { free_sub_part ((struct lnode *) dp->next, 1); dp->next = 0; } break; } case L_VAR_DEF: free (((struct lnode_var_def *) p)->name); ((struct lnode_var_def *) p)->name = 0; break; case L_FUNCALL: if (((struct lnode_funcall *) p)->name < string_space || ((struct lnode_funcall *) p)->name >= end_of_string_space) { tot_alloc_strings -= strlen (((struct lnode_funcall *) p)->name) + 1; free (((struct lnode_funcall *) p)->name); } ((struct lnode_funcall *) p)->name = 0; free_sub_part (((struct lnode_funcall *) p)->expr, 1); ((struct lnode_funcall *) p)->expr = 0; break; case L_BLOCK: { struct lnode_block *lb = (struct lnode_block *) p; char *block = lb->block; int i; for (i = 0; i < lb->num_nodes; i++) { free_sub_part ((struct lnode *) block, 0); block += lnode_size[((struct lnode *) block)->line >> L_SHIFT]; } free (lb->block); break; } default: fatal ("Bad type in free_sub_part(): 0x%x\n", p->line & L_MASK); } if (do_free) free_lnode (p, 1); }