mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-05-31 00:30:57 +00:00
[ruamoko] Install and use dispatch tables
This should speed up ruamoko code somewhat as hash table lookups have been replaced with direct array indexing. As a bonus, support for message forwarding has been added (though not tested).
This commit is contained in:
parent
1ccdd76780
commit
e2f4c189f9
2 changed files with 124 additions and 3 deletions
|
@ -94,7 +94,7 @@ typedef struct pr_class_s {
|
||||||
pr_int_t instance_size;
|
pr_int_t instance_size;
|
||||||
pointer_t ivars; // pr_ivar_list_t
|
pointer_t ivars; // pr_ivar_list_t
|
||||||
pointer_t methods; // pr_method_list_t
|
pointer_t methods; // pr_method_list_t
|
||||||
pointer_t dtable;
|
pointer_t dtable; // resource index
|
||||||
pointer_t subclass_list; // pr_class_t
|
pointer_t subclass_list; // pr_class_t
|
||||||
pointer_t sibling_class; // pr_class_t
|
pointer_t sibling_class; // pr_class_t
|
||||||
pointer_t protocols; // pr_protocol_list_t
|
pointer_t protocols; // pr_protocol_list_t
|
||||||
|
|
|
@ -56,17 +56,26 @@
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "rua_internal.h"
|
#include "rua_internal.h"
|
||||||
|
|
||||||
|
#define always_inline inline __attribute__((__always_inline__))
|
||||||
|
|
||||||
typedef struct obj_list_s {
|
typedef struct obj_list_s {
|
||||||
struct obj_list_s *next;
|
struct obj_list_s *next;
|
||||||
void *data;
|
void *data;
|
||||||
} obj_list;
|
} obj_list;
|
||||||
|
|
||||||
|
typedef struct dtable_s {
|
||||||
|
size_t size;
|
||||||
|
func_t *imp;
|
||||||
|
} dtable_t;
|
||||||
|
|
||||||
typedef struct probj_resources_s {
|
typedef struct probj_resources_s {
|
||||||
progs_t *pr;
|
progs_t *pr;
|
||||||
unsigned selector_index;
|
unsigned selector_index;
|
||||||
unsigned selector_index_max;
|
unsigned selector_index_max;
|
||||||
obj_list **selector_sels;
|
obj_list **selector_sels;
|
||||||
string_t *selector_names;
|
string_t *selector_names;
|
||||||
|
PR_RESMAP (dtable_t) dtables;
|
||||||
|
func_t obj_forward;
|
||||||
hashtab_t *selector_hash;
|
hashtab_t *selector_hash;
|
||||||
hashtab_t *classes;
|
hashtab_t *classes;
|
||||||
hashtab_t *protocols;
|
hashtab_t *protocols;
|
||||||
|
@ -79,6 +88,41 @@ typedef struct probj_resources_s {
|
||||||
obj_list *class_tree_list;
|
obj_list *class_tree_list;
|
||||||
} probj_t;
|
} probj_t;
|
||||||
|
|
||||||
|
static dtable_t *
|
||||||
|
dtable_new (probj_t *probj)
|
||||||
|
{
|
||||||
|
PR_RESNEW (dtable_t, probj->dtables);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dtable_reset (probj_t *probj)
|
||||||
|
{
|
||||||
|
PR_RESRESET (dtable_t, probj->dtables);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline dtable_t *
|
||||||
|
dtable_get (probj_t *probj, int index)
|
||||||
|
{
|
||||||
|
PR_RESGET (probj->dtables, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
dtable_index (probj_t *probj, dtable_t *dtable)
|
||||||
|
{
|
||||||
|
PR_RESINDEX (probj->dtables, dtable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static always_inline dtable_t * __attribute__((pure))
|
||||||
|
get_dtable (probj_t *probj, const char *name, int index)
|
||||||
|
{
|
||||||
|
dtable_t *dtable = dtable_get (probj, index);
|
||||||
|
|
||||||
|
if (!dtable) {
|
||||||
|
PR_RunError (probj->pr, "invalid dtable index in %s", name);
|
||||||
|
}
|
||||||
|
return dtable;
|
||||||
|
}
|
||||||
|
|
||||||
static obj_list *obj_list_free_list;
|
static obj_list *obj_list_free_list;
|
||||||
|
|
||||||
static obj_list *
|
static obj_list *
|
||||||
|
@ -832,12 +876,83 @@ obj_send_initialize (probj_t *probj, pr_class_t *class)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
obj_install_methods_in_dtable (probj_t *probj, pr_class_t *class,
|
||||||
|
pr_method_list_t *method_list)
|
||||||
|
{
|
||||||
|
progs_t *pr = probj->pr;
|
||||||
|
dtable_t *dtable;
|
||||||
|
|
||||||
|
if (!method_list) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (method_list->method_next) {
|
||||||
|
obj_install_methods_in_dtable (probj, class,
|
||||||
|
&G_STRUCT (pr, pr_method_list_t,
|
||||||
|
method_list->method_next));
|
||||||
|
}
|
||||||
|
|
||||||
|
dtable = get_dtable (probj, __FUNCTION__, class->dtable);
|
||||||
|
for (int i = 0; i < method_list->method_count; i++) {
|
||||||
|
pr_method_t *method = &method_list->method_list[i];
|
||||||
|
pr_sel_t *sel = &G_STRUCT (pr, pr_sel_t, method->method_name);
|
||||||
|
if (sel->sel_id < dtable->size) {
|
||||||
|
dtable->imp[sel->sel_id] = method->method_imp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
obj_install_dispatch_table_for_class (probj_t *probj, pr_class_t *class)
|
||||||
|
{
|
||||||
|
progs_t *pr = probj->pr;
|
||||||
|
pr_class_t *super = &G_STRUCT (pr, pr_class_t, class->super_class);
|
||||||
|
dtable_t *dtable;
|
||||||
|
|
||||||
|
Sys_MaskPrintf (SYS_RUA_OBJ, " install dispatch for class %s %x %d\n",
|
||||||
|
PR_GetString (pr, class->name),
|
||||||
|
class->methods,
|
||||||
|
PR_CLS_ISMETA(class));
|
||||||
|
|
||||||
|
if (super && !super->dtable) {
|
||||||
|
obj_install_dispatch_table_for_class (probj, super);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtable = dtable_new (probj);
|
||||||
|
class->dtable = dtable_index (probj, dtable);
|
||||||
|
dtable->size = probj->selector_index + 1;
|
||||||
|
dtable->imp = calloc (dtable->size, sizeof (func_t));
|
||||||
|
if (super) {
|
||||||
|
dtable_t *super_dtable = get_dtable (probj, __FUNCTION__,
|
||||||
|
super->dtable);
|
||||||
|
memcpy (dtable->imp, super_dtable->imp,
|
||||||
|
super_dtable->size * sizeof (*dtable->imp));
|
||||||
|
}
|
||||||
|
obj_install_methods_in_dtable (probj, class,
|
||||||
|
&G_STRUCT (pr, pr_method_list_t,
|
||||||
|
class->methods));
|
||||||
|
}
|
||||||
|
|
||||||
static func_t
|
static func_t
|
||||||
get_imp (probj_t *probj, pr_class_t *class, pr_sel_t *sel)
|
get_imp (probj_t *probj, pr_class_t *class, pr_sel_t *sel)
|
||||||
{
|
{
|
||||||
pr_method_t *method = obj_find_message (probj, class, sel);
|
func_t imp = 0;
|
||||||
|
|
||||||
return method ? method->method_imp : 0;
|
if (class->dtable) {
|
||||||
|
dtable_t *dtable = get_dtable (probj, __FUNCTION__, class->dtable);
|
||||||
|
if (sel->sel_id < dtable->size) {
|
||||||
|
imp = dtable->imp[sel->sel_id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!imp) {
|
||||||
|
if (!class->dtable) {
|
||||||
|
obj_install_dispatch_table_for_class (probj, class);
|
||||||
|
imp = get_imp (probj, class, sel);
|
||||||
|
} else {
|
||||||
|
imp = probj->obj_forward;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return imp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static func_t
|
static func_t
|
||||||
|
@ -1908,10 +2023,16 @@ rua_obj_init_runtime (progs_t *pr)
|
||||||
{
|
{
|
||||||
probj_t *probj = pr->pr_objective_resources;
|
probj_t *probj = pr->pr_objective_resources;
|
||||||
pr_def_t *def;
|
pr_def_t *def;
|
||||||
|
dfunction_t *obj_forward;
|
||||||
|
|
||||||
if ((def = PR_FindField (pr, ".this")))
|
if ((def = PR_FindField (pr, ".this")))
|
||||||
pr->fields.this = def->ofs;
|
pr->fields.this = def->ofs;
|
||||||
|
|
||||||
|
probj->obj_forward = 0;
|
||||||
|
if ((obj_forward = PR_FindFunction (pr, "__obj_forward"))) {
|
||||||
|
probj->obj_forward = (intptr_t) (obj_forward - pr->pr_functions);
|
||||||
|
}
|
||||||
|
|
||||||
PR_AddLoadFinishFunc (pr, rua_init_finish);
|
PR_AddLoadFinishFunc (pr, rua_init_finish);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue