#include "lint.h" #include "y-tab.h" #include "lnode.h" #include "config.h" #define NUM_CHUNK 100 /* Number of chunks to allocate */ extern char *xalloc(); extern int current_line; int tot_alloc_lnode; struct lnode_var_def *prog_status; void free_lnode PROT((struct lnode *, int)), free_lnode_string PROT((struct lnode *)); void free_sub_part PROT((struct lnode *, int)); void free(); static int tot_lnode_single; struct lnode_single *alloc_lnode_single(type) 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; } static struct lnode_number *lnode_number_list; static int tot_lnode_number; struct lnode_number *alloc_lnode_number(type, number) int type, number; { struct lnode_number *p; if (!lnode_number_list) { int i; lnode_number_list = (struct lnode_number *)xalloc(NUM_CHUNK * sizeof (struct lnode_number)); for (p = lnode_number_list, i=0; i<NUM_CHUNK - 1; p++, i++) p->number = (int)(p+1); p->number = 0; tot_lnode_number += NUM_CHUNK; } p = lnode_number_list; lnode_number_list = (struct lnode_number *)lnode_number_list->number; p->type = type; p->number = number; p->line = current_line + L_NUMBER; return p; } /* * Strings are allocated from the shared string area. * Be carfule not to free() such an area through free(). */ static struct lnode_name *lnode_name_list; static int tot_lnode_name; struct lnode_name *alloc_lnode_name(type, name) char *name; int type; { struct lnode_name *p; char *spn; if (!lnode_name_list) { int i; lnode_name_list = (struct lnode_name *)xalloc(NUM_CHUNK * sizeof (struct lnode_name)); for (p = lnode_name_list, i=0; i<NUM_CHUNK - 1; p++, i++) p->name = (char *)(p+1); p->name = 0; tot_lnode_name += NUM_CHUNK; } p = lnode_name_list; lnode_name_list = (struct lnode_name *)lnode_name_list->name; p->type = type; p->name = make_shared_string(name); free(name); p->line = current_line + L_NAME; return p; } static int tot_lnode_variable; struct lnode_variable *alloc_lnode_variable(type, number) int type, 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; /* p->is_static = 0; */ tot_lnode_variable++; return p; } static struct lnode_1 *lnode_1_list; static int tot_lnode_1; struct lnode_1 *alloc_lnode_1(type, expr) struct lnode *expr; int type; { struct lnode_1 *p; if (!lnode_1_list) { int i; lnode_1_list = (struct lnode_1 *)xalloc(NUM_CHUNK * sizeof (struct lnode_1)); for (p = lnode_1_list, i=0; i<NUM_CHUNK - 1; p++, i++) p->expr = (struct lnode *)(p+1); p->expr = 0; tot_lnode_1 += NUM_CHUNK; } p = lnode_1_list; lnode_1_list = (struct lnode_1 *)lnode_1_list->expr; p->type = type; p->expr = expr; p->line = current_line + L_1; return p; } static struct lnode_2 *lnode_2_list; static int tot_lnode_2; struct lnode_2 *alloc_lnode_2(type, expr1, expr2) struct lnode *expr1, *expr2; int type; { 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; } static int tot_lnode_3; struct lnode_3 *alloc_lnode_3(type, expr1, expr2, expr3) struct lnode *expr1, *expr2, *expr3; int type; { 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; } static int tot_lnode_def; struct lnode_def *alloc_lnode_def(type, name, block, num_var) struct lnode *block; char *name; int type, 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; p->name = make_shared_string(name); free(name); p->length = strlen(p->name); p->num_var = num_var; p->block = block; p->next = 0; p->num_ref = 0; p->is_static = 0; p->num_arg = 0; tot_lnode_def++; return p; } static int tot_var_def; void alloc_lnode_var_def(type, name, num_var) char *name; int type, num_var; { extern int static_variable_flag; 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 = make_shared_string(name); free(name); p->num_var = num_var; p->next = prog_status; p->is_static = static_variable_flag; prog_status = p; tot_var_def++; } static int tot_funcall; struct lnode_funcall *alloc_lnode_funcall(type, name, arg) struct lnode *arg; char *name; int type; { struct lnode_funcall *p; char *spn; p = (struct lnode_funcall *)xalloc(sizeof (struct lnode_funcall)); p->type = type; p->line = current_line + L_FUNCALL; p->name = make_shared_string(name); free(name); p->expr = arg; tot_funcall++; return p; } /* * Statements in a block (list of statements) are stored with cons * node (lnode_2). This is very expensive, as one lnode_2 is required as * overhead for every statement. This function will take such a list * and move all statements in a block into one single memory vector, storing * them consecutively. */ int tot_lnode_block; struct lnode_block *alloc_lnode_block(p) struct lnode *p; { int size, num; char *block, *block2; struct lnode *l, *next; struct lnode_block *ret; if (p == 0) return 0; 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 + 100); 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(tot_before_this) int tot_before_this; { int tot = tot_lnode_number * sizeof (struct lnode_number) + tot_lnode_name * sizeof (struct lnode_name) + 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(" 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); } int lnode_size[(L_MAX >> L_SHIFT) + 1]; /* * Setup fast access to the size of an lnode. */ void compute_lnode_size() { 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(p, update_count) struct lnode *p; int update_count; { switch(p->line & L_MASK) { case L_SINGLE: if (update_count) tot_lnode_single--; break; case L_NUMBER: ((struct lnode_number *)p)->number = (int)lnode_number_list; lnode_number_list = (struct lnode_number *)p; return; case L_NAME: ((struct lnode_name *)p)->name = (char *)lnode_name_list; lnode_name_list = (struct lnode_name *)p; return; case L_VARIABLE: if (update_count) tot_lnode_variable--; break; case L_1: ((struct lnode_1 *)p)->expr = (struct lnode *)lnode_1_list; lnode_1_list = (struct lnode_1 *)p; return; 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((char *)p); } void add_prog_ref(p) struct lnode_def *p; { p->num_ref++; } /* * The program is stored at one of two places. Either a tree pointed * to by ob->prog (first argument), or a consecutive area pointed * to by 'block'. These two different trees has to be free'd in different * ways. It is load_ob_from_swap() that loads a prog into the ob->block * instead of ob->prog. ob->block will also contain all variable definitions. */ int free_prog(p, block, size) struct lnode_def *p; int size; char *block; { extern int total_num_prog_blocks, total_prog_block_size; p->num_ref--; if (p->num_ref > 0) return 0; if (block) { /* free_lnode_string((struct lnode *)block); */ free(block); total_prog_block_size -= size; total_num_prog_blocks -= 1; } else { 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(p, do_free) 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: free_string(((struct lnode_name *)p)->name); 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; free_string(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: { struct lnode_var_def *lp; lp = (struct lnode_var_def *)p; if (lp->next) free_sub_part((struct lnode *)lp->next, 1); free_string(lp->name); lp->name = 0; break; } case L_FUNCALL: free_string(((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); } /* * Free shared strings used by this lnode. * This is only done for programs that has been swapped out, and * thus are allocated in one big block. Then, only strings has to * be manually freed. */ void free_lnode_string(p) struct lnode *p; { if (p == 0) return; switch(p->line & L_MASK) { case L_CONSTANT: break; case L_SINGLE: break; case L_NUMBER: break; case L_NAME: free_string(((struct lnode_name *)p)->name); break; case L_VARIABLE: break; case L_1: free_lnode_string(((struct lnode_1 *)p)->expr); break; case L_2: free_lnode_string(((struct lnode_2 *)p)->expr1); free_lnode_string(((struct lnode_2 *)p)->expr2); break; case L_3: free_lnode_string(((struct lnode_3 *)p)->expr1); free_lnode_string(((struct lnode_3 *)p)->expr2); free_lnode_string(((struct lnode_3 *)p)->expr3); break; case L_DEF: { struct lnode_def *dp = (struct lnode_def *)p; free_string(dp->name); free_lnode_string(dp->block); if (dp->next) { free_lnode_string((struct lnode *)dp->next); } break; } case L_VAR_DEF: { struct lnode_var_def *lp; lp = (struct lnode_var_def *)p; if (lp->next) free_lnode_string((struct lnode *)lp->next); free_string(lp->name); break; } case L_FUNCALL: free_string(((struct lnode_funcall *)p)->name); free_lnode_string(((struct lnode_funcall *)p)->expr); 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_lnode_string((struct lnode *)block); block += lnode_size[((struct lnode *)block)->line >> L_SHIFT]; } break; } default: fatal("Bad type in free_lnode_string(): 0x%x\n", p->line & L_MASK); } } #define NUM_LNODE_NUMBER_CONST 20 static struct lnode_number lnode_number_const[NUM_LNODE_NUMBER_CONST]; static struct lnode_number lnode_number_const_id[NUM_LNODE_NUMBER_CONST]; static struct lnode_number lnode_number_const_loc[NUM_LNODE_NUMBER_CONST]; static int num_number_match; static int lnode_func_list[] = { F_ENABLE_COMMANDS, F_THIS_OBJECT, F_THIS_PLAYER, F_TIME, F_USERS, F_RETURN, }; #define NUM_FUNCS (sizeof lnode_func_list / sizeof lnode_func_list[0]) static struct lnode_1 funcalls[NUM_FUNCS]; static int num_funcall_match; init_constant_lnodes() { int i, num; for (i=0; i < NUM_FUNCS; i++) { funcalls[i].line = L_CONSTANT; funcalls[i].type = lnode_func_list[i]; funcalls[i].expr = 0; } for (i=0; i < NUM_LNODE_NUMBER_CONST; i++) { lnode_number_const[i].line = L_CONSTANT; lnode_number_const[i].type = F_NUMBER; lnode_number_const[i].number = i; lnode_number_const_id[i].line = L_CONSTANT; lnode_number_const_id[i].type = F_IDENTIFIER; lnode_number_const_id[i].number = i; lnode_number_const_loc[i].line = L_CONSTANT; lnode_number_const_loc[i].type = F_LOCAL_NAME; lnode_number_const_loc[i].number = i; } } struct lnode_single lnode_const0 = { F_CONST0, L_CONSTANT }; struct lnode_single lnode_const1 = { F_CONST1, L_CONSTANT }; int num_lnode_single; int match_and_replace_lnode(match, destp) struct lnode *match, **destp; { struct lnode_number *p = (struct lnode_number *)match; struct lnode_1 *p1 = (struct lnode_1 *)match; if (match->type == F_CONST0) { *destp = (struct lnode *)&lnode_const0; num_lnode_single++; return 1; } if (match->type == F_CONST1) { *destp = (struct lnode *)&lnode_const1; num_lnode_single++; return 1; } if ((p1->line & L_MASK) == L_1 && p1->expr == 0) { int i; for (i=0; i < NUM_FUNCS; i++) { if (p1->type != lnode_func_list[i]) continue; *destp = (struct lnode *)&funcalls[i]; num_funcall_match++; return 1; } return 0; } if ((p->line & L_MASK) == L_NUMBER && p->type == F_NUMBER) { if (p->number < 0 || p->number >= NUM_LNODE_NUMBER_CONST) return 0; *destp = (struct lnode *)&lnode_number_const[p->number]; num_number_match++; return 1; } if ((p->line & L_MASK) == L_NUMBER && p->type == F_IDENTIFIER) { if (p->number < 0 || p->number >= NUM_LNODE_NUMBER_CONST) return 0; *destp = (struct lnode *)&lnode_number_const_id[p->number]; num_number_match++; return 1; } if ((p->line & L_MASK) == L_NUMBER && p->type == F_LOCAL_NAME) { if (p->number < 0 || p->number >= NUM_LNODE_NUMBER_CONST) return 0; *destp = (struct lnode *)&lnode_number_const_loc[p->number]; num_number_match++; return 1; } return 0; } void status_lnodes_matched() { add_message("Saved lnode_numbers: %6d (%7d bytes)\n", num_number_match, num_number_match * sizeof (struct lnode_number) - sizeof lnode_number_const_loc - sizeof lnode_number_const_id - sizeof lnode_number_const); add_message("Saved lnode_1 : %6d (%7d bytes)\n", num_funcall_match, sizeof (struct lnode_1) * (num_funcall_match - NUM_FUNCS)); add_message("Saved lnode_single : %6d (%7d bytes)\n", num_lnode_single, sizeof (struct lnode_single) * (num_lnode_single - 2)); }