diff --git a/GNUmakefile b/GNUmakefile index f6412a8..66ff6a6 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -33,7 +33,6 @@ libobjc_C_FILES = \ objects.c\ protocol.c\ runtime.c\ - sarray.c\ sarray2.c\ selector.c\ selector_table.c\ @@ -42,7 +41,7 @@ libobjc_C_FILES = \ libobjc_HEADER_FILES_DIR = objc libobjc_HEADER_FILES_INSTALL_DIR = objc -libobjc_HEADER_FILES = \ +#libobjc_HEADER_FILES = \ Availability.h\ NXConstStr.h\ Object.h\ diff --git a/class.c b/class.c index e8fee53..00cfecb 100644 --- a/class.c +++ b/class.c @@ -88,7 +88,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see structures is freeing data when is removed from the structures. */ #include "objc/runtime-legacy.h" /* the kitchen sink */ -#include "objc/sarray.h" #include "objc/objc.h" #include "objc/objc-api.h" diff --git a/dtable_legacy.c b/dtable_legacy.c deleted file mode 100644 index 33b869b..0000000 --- a/dtable_legacy.c +++ /dev/null @@ -1,351 +0,0 @@ -/* GNU Objective C Runtime initialization - Copyright (C) 1993, 1995, 1996, 1997, 2002, 2009 - Free Software Foundation, Inc. - Contributed by Kresten Krab Thorup - +load support contributed by Ovidiu Predescu - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation; either version 3, or (at your option) any later version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -details. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -. */ - -/* The uninstalled dispatch table */ -struct sarray *__objc_uninstalled_dtable = 0; /* !T:MUTEX */ - -static struct sarray *create_dtable_for_class (Class class); - - -void -__objc_init_dispatch_tables () -{ - INIT_LOCK(initialize_lock); - __objc_uninstalled_dtable = sarray_new (200, 0); -} - -/** - * Returns the dtable for a given class. If we are currently in an +initialize - * method then this will block if called from a thread other than the one - * running the +initialize method. - */ -static inline struct sarray *dtable_for_class(Class cls) -{ - if (cls->dtable != __objc_uninstalled_dtable) - { - return cls->dtable; - } - LOCK(&initialize_lock); - if (cls->dtable != __objc_uninstalled_dtable) - { - UNLOCK(&initialize_lock); - return cls->dtable; - } - /* This is a linear search, and so, in theory, could be very slow. It is - * O(n) where n is the number of +initialize methods on the stack. In - * practice, this is a very small number. Profiling with GNUstep showed that - * this peaks at 8. */ - struct sarray *dtable = __objc_uninstalled_dtable; - InitializingDtable *buffer = temporary_dtables; - while (NULL != buffer) - { - if (buffer->class == cls) - { - dtable = buffer->dtable; - break; - } - buffer = buffer->next; - } - UNLOCK(&initialize_lock); - if (dtable == 0) - dtable = __objc_uninstalled_dtable; - return dtable; -} - - -/* This function is called by objc_msg_lookup when the - dispatch table needs to be installed; thus it is called once - for each class, namely when the very first message is sent to it. */ -static void -__objc_init_install_dtable (id receiver, SEL op __attribute__ ((__unused__))) -{ - objc_mutex_lock (__objc_runtime_mutex); - - /* This may happen, if the programmer has taken the address of a - method before the dtable was initialized... too bad for him! */ - if (dtable_for_class(receiver->class_pointer) != __objc_uninstalled_dtable) - { - objc_mutex_unlock (__objc_runtime_mutex); - return; - } - - if (CLS_ISCLASS (receiver->class_pointer)) - { - /* receiver is an ordinary object */ - assert (CLS_ISCLASS (receiver->class_pointer)); - - /* call +initialize -- this will in turn install the factory - dispatch table if not already done :-) */ - __objc_send_initialize (receiver->class_pointer); - } - else - { - /* receiver is a class object */ - assert (CLS_ISCLASS ((Class)receiver)); - assert (CLS_ISMETA (receiver->class_pointer)); - __objc_send_initialize ((Class)receiver); - } - objc_mutex_unlock (__objc_runtime_mutex); -} - -/* Install dummy table for class which causes the first message to - that class (or instances hereof) to be initialized properly */ -void -__objc_install_premature_dtable (Class class) -{ - assert (__objc_uninstalled_dtable); - class->dtable = __objc_uninstalled_dtable; -} - -/* Walk on the methods list of class and install the methods in the reverse - order of the lists. Since methods added by categories are before the methods - of class in the methods list, this allows categories to substitute methods - declared in class. However if more than one category replaces the same - method nothing is guaranteed about what method will be used. - Assumes that __objc_runtime_mutex is locked down. */ -static void -__objc_install_methods_in_dtable (Class class, MethodList_t method_list, - struct sarray *dtable) -{ - int i; - - if (! method_list) - return; - - if (method_list->method_next) - __objc_install_methods_in_dtable (class, method_list->method_next, dtable); - - - for (i = 0; i < method_list->method_count; i++) - { - Method_t method = &(method_list->method_list[i]); - size_t sel_id = (size_t)method->method_name->sel_id; - /* If there is an existing slot with this value, just update it. */ - struct objc_slot *slot = sarray_get_safe(dtable, sel_id); - if (NULL != slot && slot->owner == class) - { - slot->method = method->method_imp; - slot->version++; - } - else - { - //NOTE: We can improve this by sharing slots between subclasses where - // the IMPs are the same. - slot = new_slot_for_method_in_class(method, class); - sarray_at_put_safe (dtable, sel_id, slot); - /* Invalidate the superclass's slot, if it has one. */ - slot = (NULL != class->super_class) ? - sarray_get_safe(dtable_for_class(class->super_class), sel_id) : NULL; - if (NULL != slot) - { - slot->version++; - } - } - } -} - -/** Returns the dispatch table for the given class, but does not install it. - */ -static struct sarray *create_dtable_for_class (Class class) -{ - Class super; - struct sarray *dtable = dtable_for_class(class); - if (dtable != __objc_uninstalled_dtable) return dtable; - - /* If the class has not yet had its class links resolved, we must - re-compute all class links */ - if (! CLS_ISRESOLV (class)) - objc_resolve_class(class); - - super = class->super_class; - - if (super != 0 && (dtable_for_class(super) == __objc_uninstalled_dtable)) - __objc_install_dispatch_table_for_class (super); - - /* Allocate dtable if necessary */ - if (super == 0) - { - dtable = sarray_new (__objc_selector_max_index, 0); - } - else - { - dtable = sarray_lazy_copy (dtable_for_class(super)); - } - - __objc_install_methods_in_dtable (class, class->methods, dtable); - return dtable; -} - -/* Assumes that __objc_runtime_mutex is locked down. */ -static void -__objc_install_dispatch_table_for_class(Class class) -{ - class->dtable = create_dtable_for_class(class); -} - - -static void merge_method_list_to_class (Class class, - MethodList_t method_list, - struct sarray *dtable, - struct sarray *super_dtable) -{ - // Sometimes we get method lists with no methods in them. This is weird and - // probably caused by someone else writing stupid code, but just ignore it, - // nod, smile, and move on. - if (method_list->method_count == 0) - { - if (method_list->method_next) - { - merge_method_list_to_class(class, method_list->method_next, dtable, super_dtable); - } - return; - } - /* - struct objc_slot *firstslot = - // sarray_get_safe(dtable, (size_t)method_list->method_list[0].method_name->sel_id); - // If we've already got the methods from this method list, we also have all - // of the methods from all of the ones further along the chain, so don't - // bother adding them again. - * FIXME: This doesn't take into account the lazy copying stuff in the sarray. - if (NULL != firstslot && - firstslot->owner == class && - firstslot->method == method_list->method_list[0].method_imp) - { - return; - } - */ - // If we haven't already visited this method list, then we might not have - // already visited the one after it either... - if (method_list->method_next) - { - merge_method_list_to_class(class, method_list->method_next, dtable, super_dtable); - } - - { - int i; - - /* Search the method list. */ - for (i = 0; i < method_list->method_count; ++i) - { - Method_t method = &method_list->method_list[i]; - size_t sel_id = (size_t)method->method_name->sel_id; - struct objc_slot *slot = sarray_get_safe(dtable, sel_id); - struct objc_slot *superslot = sarray_get_safe(super_dtable, sel_id); - - // If there is no existing slot, then just use the superclass's one. - if (NULL == slot) - { - sarray_at_put_safe (dtable, sel_id, superslot); - } - else - { - // If there is, we need to find whether it comes from a subclass of - // the modified class. If it does, then we don't want to override it. - Class owner = slot->owner; - do - { - if (owner == superslot->owner) - { - break; - } - owner = owner->super_class; - } while(NULL != owner); - // This is reached if class is currently inheriting a method from a - // class up the hierarchy and a new method is added to a class - // somewhere in the middle that overrides it. - if (owner != superslot->owner) - { - sarray_at_put_safe (dtable, sel_id, superslot); - slot->version++; - } - } - } - } -} -static void merge_methods_up_from_superclass (Class class, Class super, Class modifedClass, - struct sarray *dtable, - struct sarray *super_dtable) -{ - if (super->super_class && super != modifedClass) - { - merge_methods_up_from_superclass(class, super->super_class, modifedClass, - dtable, super_dtable); - } - if (super->methods) - { - merge_method_list_to_class(class, super->methods, dtable, super_dtable); - } -} - -static void merge_methods_to_subclasses (Class class, Class modifedClass) -{ - struct sarray *super_dtable = dtable_for_class(class); - // Don't merge things into the uninitialised dtable. That would be very bad. - if (super_dtable == __objc_uninstalled_dtable) { return; } - - - if (class->subclass_list) /* Traverse subclasses */ - { - for (Class next = class->subclass_list; next; next = next->sibling_class) - { - struct sarray *dtable = dtable_for_class(next); - // Don't merge things into the uninitialised dtable. That would be very bad. - if (dtable != __objc_uninstalled_dtable) - { - merge_methods_up_from_superclass(next, class, modifedClass, dtable, - super_dtable); - merge_methods_to_subclasses(next, modifedClass); - } - } - } -} - -void -__objc_update_dispatch_table_for_class (Class class) -{ - /* not yet installed -- skip it */ - if (dtable_for_class(class) == __objc_uninstalled_dtable) - return; - - objc_mutex_lock (__objc_runtime_mutex); - - __objc_install_methods_in_dtable (class, class->methods, - dtable_for_class(class)); - // Don't merge things into the uninitialised dtable. That would be very bad. - if (dtable_for_class(class) != __objc_uninstalled_dtable) - { - merge_methods_to_subclasses(class, class); - } - - objc_mutex_unlock (__objc_runtime_mutex); -} - -void objc_resize_uninstalled_dtable(void) -{ - assert(__objc_uninstalled_dtable != NULL); - sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1); -} - diff --git a/init.c b/init.c index 56a537e..cac07b9 100644 --- a/init.c +++ b/init.c @@ -92,6 +92,8 @@ static void __objc_call_callback (Module_t module); installed in the runtime. */ static BOOL class_is_subclass_of_class (Class class, Class superclass); +extern void *__objc_uninstalled_dtable; + typedef struct objc_class_tree { Class class; struct objc_list *subclasses; /* `head' is pointer to an objc_class_tree */ @@ -596,8 +598,8 @@ __objc_exec_class (Module_t module) __objc_register_selectors_from_class ((Class) class->class_pointer); /* Install the fake dispatch tables */ - __objc_install_premature_dtable (class); - __objc_install_premature_dtable (class->class_pointer); + class->dtable = __objc_uninstalled_dtable; + class->class_pointer->dtable = __objc_uninstalled_dtable; /* Register the instance methods as class methods, this is only done for root classes. */ diff --git a/objc/sarray.h b/objc/sarray.h deleted file mode 100644 index 32a7ef2..0000000 --- a/objc/sarray.h +++ /dev/null @@ -1,243 +0,0 @@ -/* Sparse Arrays for Objective C dispatch tables - Copyright (C) 1993, 1995, 1996, 2004, 2009 Free Software Foundation, Inc. - Contributed by Kresten Krab Thorup. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -. */ - - -#ifndef __sarray_INCLUDE_GNU -#define __sarray_INCLUDE_GNU - -#include "thr.h" - -#define OBJC_SPARSE2 /* 2-level sparse array */ -/* #define OBJC_SPARSE3 */ /* 3-level sparse array */ - -#ifdef OBJC_SPARSE2 -extern const char* __objc_sparse2_id; -#endif - -#ifdef OBJC_SPARSE3 -extern const char* __objc_sparse3_id; -#endif - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -extern int nbuckets; /* for stats */ -extern int nindices; -extern int narrays; -extern int idxsize; - -/* An unsigned integer of same size as a pointer */ -#define SIZET_BITS (sizeof(size_t)*8) - -#if defined(__sparc__) || defined(OBJC_SPARSE2) -#define PRECOMPUTE_SELECTORS -#endif - -#ifdef OBJC_SPARSE3 - -/* Buckets are 8 words each */ -#define BUCKET_BITS 3 -#define BUCKET_SIZE (1< - indices[x.off.ioffset]-> - buckets[x.off.boffset]-> - elems[x.off.eoffset]; -#else /* OBJC_SPARSE2 */ - return array->buckets[x.off.boffset]->elems[x.off.eoffset]; -#endif /* OBJC_SPARSE2 */ -#else /* not PRECOMPUTE_SELECTORS */ -#ifdef OBJC_SPARSE3 - return array-> - indices[indx/INDEX_CAPACITY]-> - buckets[(indx/BUCKET_SIZE)%INDEX_SIZE]-> - elems[indx%BUCKET_SIZE]; -#else /* OBJC_SPARSE2 */ - return array->buckets[indx/BUCKET_SIZE]->elems[indx%BUCKET_SIZE]; -#endif /* not OBJC_SPARSE3 */ -#endif /* not PRECOMPUTE_SELECTORS */ -} - -static inline void* sarray_get_safe(struct sarray* array, sidx indx) -{ - if(soffset_decode(indx) < array->capacity) - return sarray_get(array, indx); - else - return (array->empty_bucket->elems[0]); -} - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __sarray_INCLUDE_GNU */ diff --git a/runtime.c b/runtime.c index fa4c772..a9d8eb5 100644 --- a/runtime.c +++ b/runtime.c @@ -84,25 +84,15 @@ extern objc_mutex_t __objc_runtime_mutex; */ static Method class_getInstanceMethodNonrecursive(Class aClass, SEL aSelector) { - const char *name = sel_get_name(aSelector); - const char *types = sel_get_type(aSelector); - for (struct objc_method_list *methods = aClass->methods; methods != NULL ; methods = methods->method_next) { for (int i=0 ; imethod_count ; i++) { Method_t method = &methods->method_list[i]; - if (strcmp(sel_get_name(method->method_name), name) == 0) + if (method->method_name->sel_id == aSelector->sel_id) { - if (NULL == types || - strcmp(types, method->method_types) == 0) - { - return method; - } - // Return NULL if the method exists with this name but has the - // wrong types - return NULL; + return method; } } } diff --git a/sarray.c b/sarray.c deleted file mode 100644 index a091f11..0000000 --- a/sarray.c +++ /dev/null @@ -1,517 +0,0 @@ -/* Sparse Arrays for Objective C dispatch tables - Copyright (C) 1993, 1995, 1996, 2002, 2004, 2009 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -. */ - - -#include "objc/sarray.h" -#include "objc/runtime-legacy.h" -#include -#include "assert.h" - -int nbuckets = 0; /* !T:MUTEX */ -int nindices = 0; /* !T:MUTEX */ -int narrays = 0; /* !T:MUTEX */ -int idxsize = 0; /* !T:MUTEX */ - -static void *first_free_data = NULL; /* !T:MUTEX */ - -#ifdef OBJC_SPARSE2 -const char *__objc_sparse2_id = "2 level sparse indices"; -#endif - -#ifdef OBJC_SPARSE3 -const char *__objc_sparse3_id = "3 level sparse indices"; -#endif - -/* This function removes any structures left over from free operations - that were not safe in a multi-threaded environment. */ -void -sarray_remove_garbage (void) -{ - void **vp; - void *np; - - objc_mutex_lock (__objc_runtime_mutex); - - vp = first_free_data; - first_free_data = NULL; - - while (vp) { - np = *vp; - objc_free (vp); - vp = np; - } - - objc_mutex_unlock (__objc_runtime_mutex); -} - -/* Free a block of dynamically allocated memory. If we are in multi-threaded - mode, it is ok to free it. If not, we add it to the garbage heap to be - freed later. */ - -static void -sarray_free_garbage (void *vp) -{ - objc_mutex_lock (__objc_runtime_mutex); - - if (__objc_runtime_threads_alive == 1) { - objc_free (vp); - if (first_free_data) - sarray_remove_garbage (); - } - else { - *(void **)vp = first_free_data; - first_free_data = vp; - } - - objc_mutex_unlock (__objc_runtime_mutex); -} - -/* sarray_at_put : copies data in such a way as to be thread reader safe. */ -void -sarray_at_put (struct sarray *array, sidx index, void *element) -{ -#ifdef OBJC_SPARSE3 - struct sindex **the_index; - struct sindex *new_index; -#endif - struct sbucket **the_bucket; - struct sbucket *new_bucket; -#ifdef OBJC_SPARSE3 - size_t ioffset; -#endif - size_t boffset; - size_t eoffset; -#ifdef PRECOMPUTE_SELECTORS - union sofftype xx; - xx.idx = index; -#ifdef OBJC_SPARSE3 - ioffset = xx.off.ioffset; -#endif - boffset = xx.off.boffset; - eoffset = xx.off.eoffset; -#else /* not PRECOMPUTE_SELECTORS */ -#ifdef OBJC_SPARSE3 - ioffset = index/INDEX_CAPACITY; - boffset = (index/BUCKET_SIZE)%INDEX_SIZE; - eoffset = index%BUCKET_SIZE; -#else - boffset = index/BUCKET_SIZE; - eoffset = index%BUCKET_SIZE; -#endif -#endif /* not PRECOMPUTE_SELECTORS */ - - assert (soffset_decode (index) < array->capacity); /* Range check */ - -#ifdef OBJC_SPARSE3 - the_index = &(array->indices[ioffset]); - the_bucket = &((*the_index)->buckets[boffset]); -#else - the_bucket = &(array->buckets[boffset]); -#endif - - if ((*the_bucket)->elems[eoffset] == element) - return; /* great! we just avoided a lazy copy */ - -#ifdef OBJC_SPARSE3 - - /* First, perform lazy copy/allocation of index if needed */ - - if ((*the_index) == array->empty_index) { - - /* The index was previously empty, allocate a new */ - new_index = (struct sindex *) objc_malloc (sizeof (struct sindex)); - memcpy (new_index, array->empty_index, sizeof (struct sindex)); - new_index->version.version = array->version.version; - *the_index = new_index; /* Prepared for install. */ - the_bucket = &((*the_index)->buckets[boffset]); - - nindices += 1; - } else if ((*the_index)->version.version != array->version.version) { - - /* This index must be lazy copied */ - struct sindex *old_index = *the_index; - new_index = (struct sindex *) objc_malloc (sizeof (struct sindex)); - memcpy (new_index, old_index, sizeof (struct sindex)); - new_index->version.version = array->version.version; - *the_index = new_index; /* Prepared for install. */ - the_bucket = &((*the_index)->buckets[boffset]); - - nindices += 1; - } - -#endif /* OBJC_SPARSE3 */ - - /* next, perform lazy allocation/copy of the bucket if needed */ - - if ((*the_bucket) == array->empty_bucket) { - - /* The bucket was previously empty (or something like that), */ - /* allocate a new. This is the effect of `lazy' allocation */ - new_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket)); - memcpy ((void *) new_bucket, (const void *) array->empty_bucket, - sizeof (struct sbucket)); - new_bucket->version.version = array->version.version; - *the_bucket = new_bucket; /* Prepared for install. */ - - nbuckets += 1; - - } else if ((*the_bucket)->version.version != array->version.version) { - - /* Perform lazy copy. */ - struct sbucket *old_bucket = *the_bucket; - new_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket)); - memcpy (new_bucket, old_bucket, sizeof (struct sbucket)); - new_bucket->version.version = array->version.version; - *the_bucket = new_bucket; /* Prepared for install. */ - - nbuckets += 1; - - } - (*the_bucket)->elems[eoffset] = element; -} - -void -sarray_at_put_safe (struct sarray *array, sidx index, void *element) -{ - if (soffset_decode (index) >= array->capacity) - sarray_realloc (array, soffset_decode (index) + 1); - sarray_at_put (array, index, element); -} - -struct sarray * -sarray_new (int size, void *default_element) -{ - struct sarray *arr; -#ifdef OBJC_SPARSE3 - size_t num_indices = ((size - 1)/(INDEX_CAPACITY)) + 1; - struct sindex **new_indices; -#else /* OBJC_SPARSE2 */ - size_t num_indices = ((size - 1)/BUCKET_SIZE) + 1; - struct sbucket **new_buckets; -#endif - size_t counter; - - assert (size > 0); - - /* Allocate core array */ - arr = (struct sarray *) objc_malloc (sizeof (struct sarray)); - arr->version.version = 0; - - /* Initialize members */ -#ifdef OBJC_SPARSE3 - arr->capacity = num_indices*INDEX_CAPACITY; - new_indices = (struct sindex **) - objc_malloc (sizeof (struct sindex *) * num_indices); - - arr->empty_index = (struct sindex *) objc_malloc (sizeof (struct sindex)); - arr->empty_index->version.version = 0; - - narrays += 1; - idxsize += num_indices; - nindices += 1; - -#else /* OBJC_SPARSE2 */ - arr->capacity = num_indices*BUCKET_SIZE; - new_buckets = (struct sbucket **) - objc_malloc (sizeof (struct sbucket *) * num_indices); - - narrays += 1; - idxsize += num_indices; - -#endif - - arr->empty_bucket = (struct sbucket *) objc_malloc (sizeof (struct sbucket)); - arr->empty_bucket->version.version = 0; - - nbuckets += 1; - - arr->ref_count = 1; - arr->is_copy_of = (struct sarray *) 0; - - for (counter = 0; counter < BUCKET_SIZE; counter++) - arr->empty_bucket->elems[counter] = default_element; - -#ifdef OBJC_SPARSE3 - for (counter = 0; counter < INDEX_SIZE; counter++) - arr->empty_index->buckets[counter] = arr->empty_bucket; - - for (counter = 0; counter < num_indices; counter++) - new_indices[counter] = arr->empty_index; - -#else /* OBJC_SPARSE2 */ - - for (counter = 0; counter < num_indices; counter++) - new_buckets[counter] = arr->empty_bucket; - -#endif - -#ifdef OBJC_SPARSE3 - arr->indices = new_indices; -#else /* OBJC_SPARSE2 */ - arr->buckets = new_buckets; -#endif - - return arr; -} - - -/* Reallocate the sparse array to hold `newsize' entries - Note: We really allocate and then free. We have to do this to ensure that - any concurrent readers notice the update. */ - -void -sarray_realloc (struct sarray *array, int newsize) -{ -#ifdef OBJC_SPARSE3 - size_t old_max_index = (array->capacity - 1)/INDEX_CAPACITY; - size_t new_max_index = ((newsize - 1)/INDEX_CAPACITY); - size_t rounded_size = (new_max_index + 1) * INDEX_CAPACITY; - - struct sindex **new_indices; - struct sindex **old_indices; - -#else /* OBJC_SPARSE2 */ - size_t old_max_index = (array->capacity - 1)/BUCKET_SIZE; - size_t new_max_index = ((newsize - 1)/BUCKET_SIZE); - size_t rounded_size = (new_max_index + 1) * BUCKET_SIZE; - - struct sbucket **new_buckets; - struct sbucket **old_buckets; - -#endif - - size_t counter; - - assert (newsize > 0); - - /* The size is the same, just ignore the request */ - if (rounded_size <= array->capacity) - return; - -// assert (array->ref_count == 1); /* stop if lazy copied... */ - - /* We are asked to extend the array -- allocate new bucket table, */ - /* and insert empty_bucket in newly allocated places. */ - if (rounded_size > array->capacity) - { - -#ifdef OBJC_SPARSE3 - new_max_index += 4; - rounded_size = (new_max_index + 1) * INDEX_CAPACITY; - -#else /* OBJC_SPARSE2 */ - new_max_index += 4; - rounded_size = (new_max_index + 1) * BUCKET_SIZE; -#endif - - /* update capacity */ - array->capacity = rounded_size; - -#ifdef OBJC_SPARSE3 - /* alloc to force re-read by any concurrent readers. */ - old_indices = array->indices; - new_indices = (struct sindex **) - objc_malloc ((new_max_index + 1) * sizeof (struct sindex *)); -#else /* OBJC_SPARSE2 */ - old_buckets = array->buckets; - new_buckets = (struct sbucket **) - objc_malloc ((new_max_index + 1) * sizeof (struct sbucket *)); -#endif - - /* copy buckets below old_max_index (they are still valid) */ - for (counter = 0; counter <= old_max_index; counter++ ) { -#ifdef OBJC_SPARSE3 - new_indices[counter] = old_indices[counter]; -#else /* OBJC_SPARSE2 */ - new_buckets[counter] = old_buckets[counter]; -#endif - } - -#ifdef OBJC_SPARSE3 - /* reset entries above old_max_index to empty_bucket */ - for (counter = old_max_index + 1; counter <= new_max_index; counter++) - new_indices[counter] = array->empty_index; -#else /* OBJC_SPARSE2 */ - /* reset entries above old_max_index to empty_bucket */ - for (counter = old_max_index + 1; counter <= new_max_index; counter++) - new_buckets[counter] = array->empty_bucket; -#endif - -#ifdef OBJC_SPARSE3 - /* install the new indices */ - array->indices = new_indices; -#else /* OBJC_SPARSE2 */ - array->buckets = new_buckets; -#endif - -#ifdef OBJC_SPARSE3 - /* free the old indices */ - sarray_free_garbage (old_indices); -#else /* OBJC_SPARSE2 */ - sarray_free_garbage (old_buckets); -#endif - - idxsize += (new_max_index-old_max_index); - return; - } -} - - -/* Free a sparse array allocated with sarray_new */ - -void -sarray_free (struct sarray *array) { -#ifdef OBJC_SPARSE3 - size_t old_max_index = (array->capacity - 1)/INDEX_CAPACITY; - struct sindex **old_indices; -#else - size_t old_max_index = (array->capacity - 1)/BUCKET_SIZE; - struct sbucket **old_buckets; -#endif - size_t counter = 0; - - assert (array->ref_count != 0); /* Freed multiple times!!! */ - - if (--(array->ref_count) != 0) /* There exists copies of me */ - return; - -#ifdef OBJC_SPARSE3 - old_indices = array->indices; -#else - old_buckets = array->buckets; -#endif - - /* Free all entries that do not point to empty_bucket */ - for (counter = 0; counter <= old_max_index; counter++ ) { -#ifdef OBJC_SPARSE3 - struct sindex *idx = old_indices[counter]; - if ((idx != array->empty_index) && - (idx->version.version == array->version.version)) { - int c2; - for (c2 = 0; c2 < INDEX_SIZE; c2++) { - struct sbucket *bkt = idx->buckets[c2]; - if ((bkt != array->empty_bucket) && - (bkt->version.version == array->version.version)) - { - sarray_free_garbage (bkt); - nbuckets -= 1; - } - } - sarray_free_garbage (idx); - nindices -= 1; - } -#else /* OBJC_SPARSE2 */ - struct sbucket *bkt = array->buckets[counter]; - if ((bkt != array->empty_bucket) && - (bkt->version.version == array->version.version)) - { - sarray_free_garbage (bkt); - nbuckets -= 1; - } -#endif - } - -#ifdef OBJC_SPARSE3 - /* free empty_index */ - if (array->empty_index->version.version == array->version.version) { - sarray_free_garbage (array->empty_index); - nindices -= 1; - } -#endif - - /* free empty_bucket */ - if (array->empty_bucket->version.version == array->version.version) { - sarray_free_garbage (array->empty_bucket); - nbuckets -= 1; - } - idxsize -= (old_max_index + 1); - narrays -= 1; - -#ifdef OBJC_SPARSE3 - /* free bucket table */ - sarray_free_garbage (array->indices); - -#else - /* free bucket table */ - sarray_free_garbage (array->buckets); - -#endif - - /* If this is a copy of another array, we free it (which might just - * decrement its reference count so it will be freed when no longer in use). - */ - if (array->is_copy_of) - sarray_free (array->is_copy_of); - - /* free array */ - sarray_free_garbage (array); -} - -/* This is a lazy copy. Only the core of the structure is actually */ -/* copied. */ - -struct sarray * -sarray_lazy_copy (struct sarray *oarr) -{ - struct sarray *arr; - -#ifdef OBJC_SPARSE3 - size_t num_indices = ((oarr->capacity - 1)/INDEX_CAPACITY) + 1; - struct sindex **new_indices; -#else /* OBJC_SPARSE2 */ - size_t num_indices = ((oarr->capacity - 1)/BUCKET_SIZE) + 1; - struct sbucket **new_buckets; -#endif - - /* Allocate core array */ - arr = (struct sarray *) objc_malloc (sizeof (struct sarray)); /* !!! */ - arr->version.version = oarr->version.version + 1; -#ifdef OBJC_SPARSE3 - arr->empty_index = oarr->empty_index; -#endif - arr->empty_bucket = oarr->empty_bucket; - arr->ref_count = 1; - oarr->ref_count += 1; - arr->is_copy_of = oarr; - arr->capacity = oarr->capacity; - -#ifdef OBJC_SPARSE3 - /* Copy bucket table */ - new_indices = (struct sindex **) - objc_malloc (sizeof (struct sindex *) * num_indices); - memcpy (new_indices, oarr->indices, sizeof (struct sindex *) * num_indices); - arr->indices = new_indices; -#else - /* Copy bucket table */ - new_buckets = (struct sbucket **) - objc_malloc (sizeof (struct sbucket *) * num_indices); - memcpy (new_buckets, oarr->buckets, sizeof (struct sbucket *) * num_indices); - arr->buckets = new_buckets; -#endif - - idxsize += num_indices; - narrays += 1; - - return arr; -} diff --git a/sarray2.c b/sarray2.c index 219991e..bc511fe 100644 --- a/sarray2.c +++ b/sarray2.c @@ -68,33 +68,32 @@ SparseArray *SparseArrayExpandingArray(SparseArray *sarray) return new; } - -void * SparseArrayNext(SparseArray * sarray, uint32_t * index) +static void *SparseArrayFind(SparseArray * sarray, uint32_t * index) { uint32_t j = MASK_INDEX((*index)); uint32_t max = MAX_INDEX(sarray); - if(sarray->shift == 0) + if (sarray->shift == 0) { - while(jdata[j] != SARRAY_EMPTY) + if (sarray->data[j] != SARRAY_EMPTY) { return sarray->data[j]; } + (*index)++; j++; } } - else while(jmask >> base_shift); - while(jdata[j] != SARRAY_EMPTY) + if (sarray->data[j] != SARRAY_EMPTY) { - void * ret = SparseArrayNext(sarray->data[j], index); - if(ret != SARRAY_EMPTY) + void * ret = SparseArrayFind(sarray->data[j], index); + if (ret != SARRAY_EMPTY) { return ret; } @@ -110,6 +109,12 @@ void * SparseArrayNext(SparseArray * sarray, uint32_t * index) return SARRAY_EMPTY; } +void *SparseArrayNext(SparseArray * sarray, uint32_t * idx) +{ + (*idx)++; + return SparseArrayFind(sarray, idx); +} + void SparseArrayInsert(SparseArray * sarray, uint32_t index, void *value) { fprintf(stderr, "Inserting in : %p\n", sarray); diff --git a/sarray2.h b/sarray2.h index 8667484..8a1a6a1 100644 --- a/sarray2.h +++ b/sarray2.h @@ -67,7 +67,7 @@ static inline void* SparseArrayLookup(SparseArray * sarray, uint32_t index) ((SparseArray*)((SparseArray*)((SparseArray*) sarray->data[(i & 0xff000000)>>24])-> data[(i & 0xff0000)>>16])-> - data[(i & 0xff00)>>8])->data[(i & 0xff)]; + data[(i & 0xff00)>>8])->data[(i & 0xff)]; } /* while(sarray->shift > 0) diff --git a/selector.c b/selector.c index e67bca3..d2eaf47 100644 --- a/selector.c +++ b/selector.c @@ -24,7 +24,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include "objc/runtime-legacy.h" -#include "objc/sarray.h" #include "objc/encoding.h" /* Register instance methods as class methods for root classes */ diff --git a/selector_table.c b/selector_table.c index 17b82f5..73c5403 100644 --- a/selector_table.c +++ b/selector_table.c @@ -33,7 +33,7 @@ * registered, its name field is replaced with its index in the selector_list * array. */ -uint32_t __objc_selector_max_index; +static uint32_t selector_count = 1; /** * Mapping from selector numbers to selector names. */ @@ -44,7 +44,7 @@ static SparseArray *selector_list = NULL; inline static BOOL isSelRegistered(SEL sel) { - if ((uintptr_t)sel->name < (uintptr_t)__objc_selector_max_index) + if ((uintptr_t)sel->name < (uintptr_t)selector_count) { return YES; } @@ -112,9 +112,10 @@ mutex_t selector_table_lock; /** - * Hack to make the uninstalled dtable the right size. Won't be needed with sarray2. + * Resizes the dtables to ensure that they can store as many selectors as + * exist. */ -void objc_resize_uninstalled_dtable(void); +void objc_resize_dtables(uint32_t); /** * Create data structures to store selectors. @@ -149,11 +150,11 @@ static inline void add_selector_to_table(SEL aSel, int32_t uid, uint32_t idx) */ static inline void register_selector_locked(SEL aSel) { - uintptr_t idx = __objc_selector_max_index++; + uintptr_t idx = selector_count++; if (NULL == aSel->types) { add_selector_to_table(aSel, idx, idx); - objc_resize_uninstalled_dtable(); + objc_resize_dtables(selector_count); return; } SEL untyped = selector_lookup(aSel->name, 0); @@ -166,7 +167,7 @@ static inline void register_selector_locked(SEL aSel) add_selector_to_table(untyped, idx, idx); // If we are in type dependent dispatch mode, the uid for the typed // and untyped versions will be different - idx++; __objc_selector_max_index++; + idx++; selector_count++; } uintptr_t uid = (uintptr_t)untyped->name; TDD(uid = idx); @@ -182,7 +183,7 @@ static inline void register_selector_locked(SEL aSel) typeList->value = aSel->types; typeList->next = typeListHead->next; typeListHead->next = typeList; - objc_resize_uninstalled_dtable(); + objc_resize_dtables(selector_count); } /** * Registers a selector. This assumes that the argument is never deallocated. @@ -326,7 +327,9 @@ void __objc_register_selectors_from_class(Class class) } void __objc_register_selector_array(SEL selectors, unsigned long count) { - for (unsigned long i=0 ; (iname); // Skip the head, which just contains the name, not the types. @@ -359,7 +364,18 @@ SEL sel_get_typed_uid (const char *name, const char *types) SEL sel_get_any_typed_uid (const char *name) { - return selector_lookup(name, 0); + SEL sel = selector_lookup(name, 0); + if (NULL == sel) { return sel_registerName(name); } + + struct sel_type_list *l = + SparseArrayLookup(selector_list, (uint32_t)(uintptr_t)sel->name); + // Skip the head, which just contains the name, not the types. + l = l->next; + if (NULL != l) + { + sel = selector_lookup(name, l->value); + } + return sel; } SEL sel_get_any_uid (const char *name) @@ -405,13 +421,14 @@ static void logSelector(SEL sel) { fprintf(stderr, "%s = {%p, %s}\n", sel_getName(sel), sel->name, sel_getType_np(sel)); } -void objc_resize_uninstalled_dtable(void) {} +void objc_resize_dtables(uint32_t ignored) {} int main(void) { __objc_init_selector_tables(); SEL a = sel_registerTypedName_np("foo:", "1234"); logSelector(a); + a = sel_registerName("bar:"); a = sel_registerName("foo:"); logSelector(a); logSelector(sel_get_any_typed_uid("foo:")); @@ -427,6 +444,12 @@ int main(void) { fprintf(stderr, "Found type %s\n", types[i]); } + uint32_t idx=0; + struct sel_type_list *type; + while ((type= SparseArrayNext(selector_list, &idx))) + { + fprintf(stderr, "Idx: %d, sel: %s (%s)\n", idx, type->value, ((struct sel_type_list *)SparseArrayLookup(selector_list, idx))->value); + } fprintf(stderr, "Number of types: %d\n", count); SEL sel; } diff --git a/sendmsg.c b/sendmsg.c index eabea34..6d232cf 100644 --- a/sendmsg.c +++ b/sendmsg.c @@ -27,7 +27,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include #include "objc/runtime-legacy.h" #include "objc/slot.h" -#include "objc/sarray.h" #include "objc/encoding.h" #include "lock.h" #include "slot_pool.h" @@ -37,6 +36,8 @@ static mutex_t initialize_lock; void objc_resolve_class(Class); +#define sidx uint32_t + /* Two hooks for method forwarding. If either is set, it is invoked * to return a function that performs the real forwarding. If both * are set, the result of __objc_msg_forward2 will be preferred over @@ -52,18 +53,8 @@ static void __objc_send_initialize (Class); static void __objc_install_dispatch_table_for_class (Class); -typedef struct _InitializingDtable -{ - Class class; - void *dtable; - struct _InitializingDtable *next; -} InitializingDtable; - -/** Protected by initialize_lock */ -InitializingDtable *temporary_dtables; -#include "dtable_legacy.c" -//#include "dtable.c" +#include "dtable.c" /* Forward declare some functions */ static void __objc_init_install_dtable (id, SEL); @@ -365,6 +356,41 @@ __objc_send_initialize (Class class) } } +/* This function is called by objc_msg_lookup when the + dispatch table needs to be installed; thus it is called once + for each class, namely when the very first message is sent to it. */ +static void +__objc_init_install_dtable (id receiver, SEL op __attribute__ ((__unused__))) +{ + objc_mutex_lock (__objc_runtime_mutex); + + /* This may happen, if the programmer has taken the address of a + method before the dtable was initialized... too bad for him! */ + if (dtable_for_class(receiver->class_pointer) != __objc_uninstalled_dtable) + { + objc_mutex_unlock (__objc_runtime_mutex); + return; + } + + if (CLS_ISCLASS (receiver->class_pointer)) + { + /* receiver is an ordinary object */ + assert (CLS_ISCLASS (receiver->class_pointer)); + + /* call +initialize -- this will in turn install the factory + dispatch table if not already done :-) */ + __objc_send_initialize (receiver->class_pointer); + } + else + { + /* receiver is a class object */ + assert (CLS_ISCLASS ((Class)receiver)); + assert (CLS_ISMETA (receiver->class_pointer)); + __objc_send_initialize ((Class)receiver); + } + objc_mutex_unlock (__objc_runtime_mutex); +} + /* This function adds a method list to a class. This function is typically called by another function specific to the run-time. As such this function does not worry about thread safe issues. @@ -458,36 +484,6 @@ search_for_method_in_list (MethodList_t list, SEL op) return NULL; } -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) ((size_t) narrays * sizeof (struct sarray))); - total += narrays * sizeof (struct sarray); - printf ("buckets: %d = %ld bytes\n", nbuckets, - (long) ((size_t) nbuckets * sizeof (struct sbucket))); - total += nbuckets * sizeof (struct sbucket); - - printf ("idxtables: %d = %ld bytes\n", - idxsize, (long) ((size_t) idxsize * sizeof (void *))); - total += idxsize * sizeof (void *); - printf ("-----------------------------------\n"); - printf ("total: %d bytes\n", total); - printf ("===================================\n"); - - objc_mutex_unlock (__objc_runtime_mutex); -} - /* Returns the uninstalled dispatch table indicator. If a class' dispatch table points to __objc_uninstalled_dtable then that means it needs its dispatch table to be installed. */ diff --git a/sendmsg2.c b/sendmsg2.c index bebe9af..6d1974b 100644 --- a/sendmsg2.c +++ b/sendmsg2.c @@ -117,7 +117,7 @@ Slot_t objc_slot_lookup_super(Super_t super, SEL selector) if (receiver) { Class class = super->class; - Slot_t result = sarray_get_safe(class->dtable, (sidx)selector->sel_id); + Slot_t result = sarray_get_safe(dtable_for_class(class), (sidx)selector->sel_id); if (0 == result) { // Dtable should always be installed in the superclass