#include "tconfig.h"
#include "runtime.h"
#include "sarray.h"
#include "encoding.h"
#include "runtime-info.h"
#define gen_rtx(args...) 1
#define gen_rtx_MEM(args...) 1
#define gen_rtx_REG(args...) 1
#define rtx int
#if ! defined (STRUCT_VALUE) || STRUCT_VALUE == 0
#define INVISIBLE_STRUCT_RETURN 1
#else
#define INVISIBLE_STRUCT_RETURN 0
#endif
struct sarray *__objc_uninstalled_dtable = 0;
IMP (*__objc_msg_forward) (SEL) = NULL;
static void __objc_send_initialize (Class);
static void __objc_install_dispatch_table_for_class (Class);
static void __objc_init_install_dtable (id, SEL);
static double __objc_double_forward (id, SEL, ...);
static id __objc_word_forward (id, SEL, ...);
typedef struct { id many[8]; } __big;
#if INVISIBLE_STRUCT_RETURN
static __big
#else
static id
#endif
__objc_block_forward (id, SEL, ...);
static Method_t search_for_method_in_hierarchy (Class class, SEL sel);
Method_t search_for_method_in_list (MethodList_t list, SEL op);
id nil_method (id, SEL);
__inline__
IMP
__objc_get_forward_imp (SEL sel)
{
if (__objc_msg_forward)
{
IMP result;
if ((result = __objc_msg_forward (sel)) != NULL)
return result;
}
{
const char *t = sel->sel_types;
if (t && (*t == '[' || *t == '(' || *t == '{')
#ifdef OBJC_MAX_STRUCT_BY_VALUE
&& objc_sizeof_type (t) > OBJC_MAX_STRUCT_BY_VALUE
#endif
)
return (IMP)__objc_block_forward;
else if (t && (*t == 'f' || *t == 'd'))
return (IMP)__objc_double_forward;
else
return (IMP)__objc_word_forward;
}
}
__inline__
IMP
get_imp (Class class, SEL sel)
{
void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
if (res == 0)
{
if (class->dtable == __objc_uninstalled_dtable)
{
objc_mutex_lock (__objc_runtime_mutex);
__objc_install_dispatch_table_for_class (class);
objc_mutex_unlock (__objc_runtime_mutex);
res = get_imp (class, sel);
}
else
{
res = __objc_get_forward_imp (sel);
}
}
return res;
}
__inline__
BOOL
__objc_responds_to (id object, SEL sel)
{
void *res;
if (object->class_pointer->dtable == __objc_uninstalled_dtable)
{
objc_mutex_lock (__objc_runtime_mutex);
__objc_install_dispatch_table_for_class (object->class_pointer);
objc_mutex_unlock (__objc_runtime_mutex);
}
res = sarray_get_safe (object->class_pointer->dtable, (size_t) sel->sel_id);
return (res != 0);
}
__inline__
IMP
objc_msg_lookup (id receiver, SEL op)
{
IMP result;
if (receiver)
{
result = sarray_get_safe (receiver->class_pointer->dtable,
(sidx)op->sel_id);
if (result == 0)
{
if (receiver->class_pointer->dtable == __objc_uninstalled_dtable)
{
__objc_init_install_dtable (receiver, op);
result = get_imp (receiver->class_pointer, op);
}
else
{
result = __objc_get_forward_imp (op);
}
}
return result;
}
else
return (IMP)nil_method;
}
IMP
objc_msg_lookup_super (Super_t super, SEL sel)
{
if (super->self)
return get_imp (super->class, sel);
else
return (IMP)nil_method;
}
int method_get_sizeof_arguments (Method *);
retval_t
objc_msg_sendv (id object, SEL op, arglist_t arg_frame)
{
Method *m = class_get_instance_method (object->class_pointer, op);
const char *type;
*((id *) method_get_first_argument (m, arg_frame, &type)) = object;
*((SEL *) method_get_next_argument (arg_frame, &type)) = op;
return __builtin_apply ((apply_t) m->method_imp,
arg_frame,
method_get_sizeof_arguments (m));
}
void
__objc_init_dispatch_tables ()
{
__objc_uninstalled_dtable = sarray_new (200, 0);
}
static void
__objc_init_install_dtable (id receiver, SEL op __attribute__ ((__unused__)))
{
if (receiver->class_pointer->dtable != __objc_uninstalled_dtable)
return;
objc_mutex_lock (__objc_runtime_mutex);
if (CLS_ISCLASS (receiver->class_pointer))
{
assert (CLS_ISCLASS (receiver->class_pointer));
__objc_install_dispatch_table_for_class (receiver->class_pointer);
__objc_send_initialize (receiver->class_pointer);
}
else
{
assert (CLS_ISCLASS ((Class)receiver));
assert (CLS_ISMETA (receiver->class_pointer));
__objc_install_dispatch_table_for_class (receiver->class_pointer);
__objc_send_initialize ((Class)receiver);
}
objc_mutex_unlock (__objc_runtime_mutex);
}
void
__objc_install_premature_dtable (Class class)
{
assert (__objc_uninstalled_dtable);
class->dtable = __objc_uninstalled_dtable;
}
static void
__objc_send_initialize (Class class)
{
assert (CLS_ISCLASS (class));
assert (! CLS_ISMETA (class));
if (! CLS_ISINITIALIZED (class))
{
CLS_SETINITIALIZED (class);
CLS_SETINITIALIZED (class->class_pointer);
__objc_generate_gc_type_description (class);
if (class->super_class)
__objc_send_initialize (class->super_class);
{
SEL op = sel_register_name ("initialize");
IMP imp = 0;
MethodList_t method_list = class->class_pointer->methods;
while (method_list) {
int i;
Method_t method;
for (i = 0; i < method_list->method_count; i++) {
method = &(method_list->method_list[i]);
if (method->method_name
&& method->method_name->sel_id == op->sel_id) {
imp = method->method_imp;
break;
}
}
if (imp)
break;
method_list = method_list->method_next;
}
if (imp)
(*imp) ((id) class, op);
}
}
}
static void
__objc_install_methods_in_dtable (Class class, MethodList_t method_list)
{
int i;
if (! method_list)
return;
if (method_list->method_next)
__objc_install_methods_in_dtable (class, method_list->method_next);
for (i = 0; i < method_list->method_count; i++)
{
Method_t method = &(method_list->method_list[i]);
sarray_at_put_safe (class->dtable,
(sidx) method->method_name->sel_id,
method->method_imp);
}
}
static void
__objc_install_dispatch_table_for_class (Class class)
{
Class super;
if (! CLS_ISRESOLV (class))
__objc_resolve_class_links ();
super = class->super_class;
if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
__objc_install_dispatch_table_for_class (super);
if (super == 0)
{
objc_mutex_lock (__objc_runtime_mutex);
class->dtable = sarray_new (__objc_selector_max_index, 0);
objc_mutex_unlock (__objc_runtime_mutex);
}
else
class->dtable = sarray_lazy_copy (super->dtable);
__objc_install_methods_in_dtable (class, class->methods);
}
void
__objc_update_dispatch_table_for_class (Class class)
{
Class next;
struct sarray *arr;
if (class->dtable == __objc_uninstalled_dtable)
return;
objc_mutex_lock (__objc_runtime_mutex);
arr = class->dtable;
__objc_install_premature_dtable (class);
sarray_free (arr);
__objc_install_dispatch_table_for_class (class);
if (class->subclass_list)
for (next = class->subclass_list; next; next = next->sibling_class)
__objc_update_dispatch_table_for_class (next);
objc_mutex_unlock (__objc_runtime_mutex);
}
void
class_add_method_list (Class class, MethodList_t list)
{
int i;
assert (! list->method_next);
for (i = 0; i < list->method_count; ++i)
{
Method_t method = &list->method_list[i];
if (method->method_name)
{
method->method_name =
sel_register_typed_name ((const char *) method->method_name,
method->method_types);
}
}
list->method_next = class->methods;
class->methods = list;
__objc_update_dispatch_table_for_class (class);
}
Method_t
class_get_instance_method (Class class, SEL op)
{
return search_for_method_in_hierarchy (class, op);
}
Method_t
class_get_class_method (MetaClass class, SEL op)
{
return search_for_method_in_hierarchy (class, op);
}
static Method_t
search_for_method_in_hierarchy (Class cls, SEL sel)
{
Method_t method = NULL;
Class class;
if (! sel_is_mapped (sel))
return NULL;
for (class = cls; ((! method) && class); class = class->super_class)
method = search_for_method_in_list (class->methods, sel);
return method;
}
Method_t
search_for_method_in_list (MethodList_t list, SEL op)
{
MethodList_t method_list = list;
if (! sel_is_mapped (op))
return NULL;
while (method_list)
{
int i;
for (i = 0; i < method_list->method_count; ++i)
{
Method_t method = &method_list->method_list[i];
if (method->method_name)
if (method->method_name->sel_id == op->sel_id)
return method;
}
method_list = method_list->method_next;
}
return NULL;
}
static retval_t __objc_forward (id object, SEL sel, arglist_t args);
static id
__objc_word_forward (id rcv, SEL op, ...)
{
void *args, *res;
args = __builtin_apply_args ();
res = __objc_forward (rcv, op, args);
if (res)
__builtin_return (res);
else
return res;
}
static double
__objc_double_forward (id rcv, SEL op, ...)
{
void *args, *res;
args = __builtin_apply_args ();
res = __objc_forward (rcv, op, args);
__builtin_return (res);
}
#if INVISIBLE_STRUCT_RETURN
static __big
#else
static id
#endif
__objc_block_forward (id rcv, SEL op, ...)
{
void *args, *res;
args = __builtin_apply_args ();
res = __objc_forward (rcv, op, args);
if (res)
__builtin_return (res);
else
#if INVISIBLE_STRUCT_RETURN
return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
#else
return nil;
#endif
}
static retval_t
__objc_forward (id object, SEL sel, arglist_t args)
{
IMP imp;
static SEL frwd_sel = 0;
SEL err_sel;
if (! frwd_sel)
frwd_sel = sel_get_any_uid ("forward::");
if (__objc_responds_to (object, frwd_sel))
{
imp = get_imp (object->class_pointer, frwd_sel);
return (*imp) (object, frwd_sel, sel, args);
}
err_sel = sel_get_any_uid ("doesNotRecognize:");
if (__objc_responds_to (object, err_sel))
{
imp = get_imp (object->class_pointer, err_sel);
return (*imp) (object, err_sel, sel);
}
{
char msg[256 + strlen ((const char *) sel_get_name (sel))
+ strlen ((const char *) object->class_pointer->name)];
sprintf (msg, "(%s) %s does not recognize %s",
(CLS_ISMETA (object->class_pointer)
? "class"
: "instance" ),
object->class_pointer->name, sel_get_name (sel));
err_sel = sel_get_any_uid ("error:");
if (__objc_responds_to (object, err_sel))
{
imp = get_imp (object->class_pointer, err_sel);
return (*imp) (object, sel_get_any_uid ("error:"), msg);
}
objc_error (object, OBJC_ERR_UNIMPLEMENTED, "%s\n", msg);
return 0;
}
}
void
__objc_print_dtable_stats ()
{
int total = 0;
objc_mutex_lock (__objc_runtime_mutex);
#ifdef OBJC_SPARSE2
printf ("memory usage: (%s)\n", "2-level sparse arrays");
#else
printf ("memory usage: (%s)\n", "3-level sparse arrays");
#endif
printf ("arrays: %d = %ld bytes\n", narrays,
(long) narrays * sizeof (struct sarray));
total += narrays * sizeof (struct sarray);
printf ("buckets: %d = %ld bytes\n", nbuckets,
(long) nbuckets * sizeof (struct sbucket));
total += nbuckets * sizeof (struct sbucket);
printf ("idxtables: %d = %ld bytes\n",
idxsize, (long) idxsize * sizeof (void *));
total += idxsize * sizeof (void *);
printf ("-----------------------------------\n");
printf ("total: %d bytes\n", total);
printf ("===================================\n");
objc_mutex_unlock (__objc_runtime_mutex);
}
__inline__
struct sarray *
objc_get_uninstalled_dtable ()
{
return __objc_uninstalled_dtable;
}