diff --git a/tools/qfcc/include/class.h b/tools/qfcc/include/class.h index a4f65538b..726a272be 100644 --- a/tools/qfcc/include/class.h +++ b/tools/qfcc/include/class.h @@ -83,6 +83,11 @@ typedef struct protocollist_s { protocol_t **list; } protocollist_t; +typedef struct static_instance_s { + const char *class; + struct def_s *instance; +} static_instance_t; + extern struct type_s type_id; extern struct type_s type_obj_object; extern struct type_s type_obj_class; diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 64ebf692f..0b981d065 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -66,6 +66,8 @@ static hashtab_t *class_hash; static hashtab_t *category_hash; static hashtab_t *protocol_hash; +static hashtab_t *static_instances; +static hashtab_t *static_instance_classes; // these will be built up further type_t type_obj_selector = { ev_invalid, 0, 0, ty_struct}; @@ -178,6 +180,141 @@ static struct_def_t object_struct[] = { {0, 0} }; +static const char * +static_instance_get_key (const void *instance, void *unused) +{ + return ((static_instance_t *) instance)->class; +} + +static void +add_static_instance (const char *class, def_t *instance_def) +{ + static_instance_t *instance = malloc (sizeof (*instance)); + + if (!static_instances) { + static_instances = Hash_NewTable (1021, static_instance_get_key, 0, 0); + static_instance_classes = Hash_NewTable (1021, static_instance_get_key, + 0, 0); + } + + instance->class = save_string (class); + instance->instance = instance_def; + Hash_Add (static_instances, instance); + + // uniqued set of class names for all static instances + if (!Hash_Find (static_instance_classes, class)) { + Hash_Add (static_instance_classes, instance); + } +} +typedef struct { + const char *class_name; + int num_instances; + static_instance_t **instances; +} obj_static_instances_data_t; + +static void +emit_instance_classname (def_t *def, void *data, int index) +{ + obj_static_instances_data_t *da = (obj_static_instances_data_t *)data; + + if (def->type != &type_string) + internal_error (0, "%s: expected string def", __FUNCTION__); + EMIT_STRING (def->space, D_STRING (def), da->class_name); +} + +static void +emit_instance_defs (def_t *def, void *data, int index) +{ + obj_static_instances_data_t *da = (obj_static_instances_data_t *)data; + + if (!is_array (def->type) || def->type->t.array.type->type != ev_pointer) + internal_error (0, "%s: expected array of pointers def", __FUNCTION__); + if (index < 0 || index >= da->num_instances + 1) + internal_error (0, "%s: out of bounds index: %d %d", + __FUNCTION__, index, da->num_instances + 1); + D_INT (def) = 0; + if (index < da->num_instances) { + EMIT_DEF (def->space, D_INT (def), da->instances[index]->instance); + } +} + +static def_t * +emit_static_instances (const char *classname) +{ + static struct_def_t instances_struct[] = { + {"class_name", &type_string, emit_instance_classname}, + {"instances", 0, emit_instance_defs}, + {0, 0} + }; + obj_static_instances_data_t data = {}; + def_t *instances_def; + + data.class_name = classname; + data.instances = (static_instance_t **) Hash_FindList (static_instances, + classname); + for (static_instance_t **inst = data.instances; *inst; inst++) { + data.num_instances++; + } + instances_struct[1].type = array_type (&type_pointer, + data.num_instances + 1); + instances_def = emit_structure (va ("_OBJ_STATIC_INSTANCES_%s", classname), + 's', instances_struct, 0, &data, + sc_static); + free (data.instances); + return instances_def; +} + +static def_t * +emit_static_instances_list (void) +{ + static_instance_t **classes; + int num_classes = 0; + def_t **instance_lists; + type_t *instance_lists_type; + symbol_t *instance_lists_sym; + def_t *instance_lists_def; + pointer_t *list; + defspace_t *space; + + if (!static_instance_classes || !static_instances) { + return 0; + } + + classes = (static_instance_t **) Hash_GetList (static_instance_classes); + for (static_instance_t **c = classes; *c; c++) { + num_classes++; + } + if (!num_classes) { + free (classes); + return 0; + } + instance_lists = alloca (num_classes * sizeof (*instance_lists)); + for (int i = 0; i < num_classes; i++) { + instance_lists[i] = emit_static_instances (classes[i]->class); + } + free (classes); + + // +1 for terminating null + instance_lists_type = array_type (&type_pointer, num_classes + 1); + instance_lists_sym = make_symbol ("_OBJ_STATIC_INSTANCES", + instance_lists_type, + pr.far_data, sc_static); + if (!instance_lists_sym->table) { + symtab_addsymbol (pr.symtab, instance_lists_sym); + } + instance_lists_def = instance_lists_sym->s.def; + instance_lists_def->initialized = instance_lists_def->constant = 1; + instance_lists_def->nosave = 1; + + list = D_POINTER (pointer_t, instance_lists_def); + space = instance_lists_def->space; + for (int i = 0; i < num_classes; i++, list++) { + EMIT_DEF (space, *list, instance_lists[i]); + } + *list = 0; + return instance_lists_def; +} + int obj_is_id (const type_t *type) { @@ -1185,6 +1322,7 @@ typedef struct { int cls_def_cnt; category_t **categories; int cat_def_cnt; + def_t *instances_list; } obj_symtab_data_t; static void @@ -1238,10 +1376,10 @@ emit_symtab_defs (def_t *def, void *data, int index) if (!is_array (def->type) || def->type->t.array.type->type != ev_pointer) internal_error (0, "%s: expected array of pointers def", __FUNCTION__); - if (index < 0 || index >= da->cls_def_cnt + da->cat_def_cnt) + if (index < 0 || index >= da->cls_def_cnt + da->cat_def_cnt + 1) internal_error (0, "%s: out of bounds index: %d %d", __FUNCTION__, index, - da->cls_def_cnt + da->cat_def_cnt); + da->cls_def_cnt + da->cat_def_cnt + 1); if (index < da->cls_def_cnt) { class_t **cl; @@ -1250,7 +1388,7 @@ emit_symtab_defs (def_t *def, void *data, int index) if (!index--) break; EMIT_DEF (def->space, D_INT (def), (*cl)->def); - } else { + } else if (index < da->cls_def_cnt + da->cat_def_cnt) { category_t **ca; index -= da->cls_def_cnt; for (ca = da->categories; *ca; ca++) @@ -1258,6 +1396,11 @@ emit_symtab_defs (def_t *def, void *data, int index) if (!index--) break; EMIT_DEF (def->space, D_INT (def), (*ca)->def); + } else { + D_INT (def) = 0; + if (da->instances_list) { + EMIT_DEF (def->space, D_INT (def), da->instances_list); + } } } @@ -1273,7 +1416,7 @@ class_finish_module (void) {0, 0} }; - obj_symtab_data_t data = {0, 0, 0, 0, 0}; + obj_symtab_data_t data = {}; class_t **cl; category_t **ca; @@ -1299,10 +1442,14 @@ class_finish_module (void) if ((*ca)->def && !(*ca)->def->external) data.cat_def_cnt++; } - if (!data.refs && !data.cls_def_cnt && !data.cat_def_cnt) + data.instances_list = emit_static_instances_list (); + if (!data.refs && !data.cls_def_cnt && !data.cat_def_cnt + && !data.instances_list) return; symtab_struct[4].type = array_type (&type_pointer, - data.cls_def_cnt + data.cat_def_cnt); + data.cls_def_cnt + + data.cat_def_cnt + + 1); symtab_def = emit_structure ("_OBJ_SYMTAB", 's', symtab_struct, 0, &data, sc_static); free (data.classes); @@ -1389,6 +1536,7 @@ protocol_def (protocol_t *protocol) { if (!protocol->def) { protocol->def = emit_protocol (protocol); + add_static_instance ("Protocol", protocol->def); } return protocol->def; } @@ -1548,6 +1696,10 @@ clear_classes (void) Hash_FlushTable (protocol_hash); if (category_hash) Hash_FlushTable (category_hash); + if (static_instances) + Hash_FlushTable (static_instances); + if (static_instance_classes) + Hash_FlushTable (static_instance_classes); obj_initialized = 0; } diff --git a/tools/qfcc/source/dump_modules.c b/tools/qfcc/source/dump_modules.c index 6bb559003..68cee44eb 100644 --- a/tools/qfcc/source/dump_modules.c +++ b/tools/qfcc/source/dump_modules.c @@ -89,22 +89,41 @@ dump_selector (progs_t *pr, pr_sel_t *sel) printf (" %s\n", sel_types); } +static void +dump_method_description_list (progs_t *pr, char c, + pr_method_description_list_t *list) +{ + if (list) { + for (int i = 0; i < list->count; i++) { + printf ("%*s%s\n", 20, "", PR_GetString (pr, list->list[i].name)); + printf ("%*s%s\n", 20, "", PR_GetString (pr, list->list[i].types)); + } + } +} + static void dump_protocol (progs_t *pr, pr_protocol_t *proto) { const char *protocol_name = ""; - printf (" %d ", proto->class_pointer); + printf (" %x %x ", + (pointer_t) ((pr_int_t *) proto - (pr_int_t *) pr->pr_globals), + proto->class_pointer); if (PR_StringValid (pr, proto->protocol_name)) protocol_name = PR_GetString (pr, proto->protocol_name); printf ("<%s>\n", protocol_name); + dump_method_description_list (pr, '-', + &G_STRUCT (pr, pr_method_description_list_t, + proto->instance_methods)); + dump_method_description_list (pr, '-', + &G_STRUCT (pr, pr_method_description_list_t, + proto->class_methods)); } static void dump_protocol_list (progs_t *pr, pr_protocol_list_t *list) { int i; - printf (" %d\n", list->next); - printf (" %d\n", list->count); + printf (" %x %d\n", list->next, list->count); for (i = 0; i < list->count; i++) { if (list->list[i] <= 0 || list->list[i] >= pr->globals_size) { printf ("invalid pointer\n"); @@ -171,6 +190,32 @@ dump_category (progs_t *pr, pr_category_t *category) category->protocols)); } +static void +dump_static_instance_lists (progs_t *pr, pointer_t instance_lists) +{ + pointer_t *ptr = &G_STRUCT (pr, pointer_t, instance_lists); + + printf (" static instance lists @ %x\n", instance_lists); + while (*ptr) { + __auto_type list = &G_STRUCT (pr, pr_static_instances_t, *ptr); + const char *class_name = "*** INVALID ***"; + + if (PR_StringValid (pr, list->class_name)) { + class_name = PR_GetString (pr, list->class_name); + } + printf (" %x %s\n", *ptr, class_name); + for (int i = 0; list->instances[i]; i++) { + if (!strcmp (class_name, "Protocol")) { + dump_protocol (pr, &G_STRUCT (pr, pr_protocol_t, + list->instances[i])); + } else { + printf (" %x\n", list->instances[i]); + } + } + ptr++; + } +} + static void dump_module (progs_t *pr, pr_module_t *module) { @@ -197,6 +242,9 @@ dump_module (progs_t *pr, pr_module_t *module) dump_class (pr, &G_STRUCT (pr, pr_class_t, *ptr++)); for (i = 0; i < symtab->cat_def_cnt; i++) dump_category (pr, &G_STRUCT (pr, pr_category_t, *ptr++)); + if (*ptr) { + dump_static_instance_lists (pr, *ptr); + } } void diff --git a/tools/qfcc/source/dump_strings.c b/tools/qfcc/source/dump_strings.c index fc0c0cb7d..77f3c0ae4 100644 --- a/tools/qfcc/source/dump_strings.c +++ b/tools/qfcc/source/dump_strings.c @@ -44,14 +44,14 @@ dump_string_block (const char *strblock, unsigned size) { const char *s = strblock; - printf ("%d ", 0); + printf ("%x ", 0); while (s - strblock < size) { char c = *s++; switch (c) { case 0: fputs ("\n", stdout); if (s - strblock < size) - printf ("%ld ", s - strblock); + printf ("%lx ", s - strblock); break; case 9: fputs ("\\t", stdout);