diff --git a/GNUmakefile b/GNUmakefile index aae950a..f6eb4aa 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -12,7 +12,6 @@ libobjc_OBJC_FILES = \ Object.m\ Protocol.m\ blocks_runtime.m\ - linking.m\ mutation.m\ properties.m\ sync.m @@ -22,6 +21,7 @@ libobjc_C_FILES = \ abi_version.c\ category_loader.c\ class_table.c\ + dtable.c\ encoding.c\ hash_table.c\ exception.c\ @@ -29,17 +29,15 @@ libobjc_C_FILES = \ ivar.c\ loader.c\ misc.c\ - nil_method.c\ protocol.c\ runtime.c\ sarray2.c\ selector_table.c\ - sendmsg.c\ + sendmsg2.c\ statics_loader.c ifneq ($(enable_legacy), no) libobjc_C_FILES += \ - gc.c\ objects.c\ thr.c endif diff --git a/dtable.c b/dtable.c index 47dd87e..821f3b5 100644 --- a/dtable.c +++ b/dtable.c @@ -1,31 +1,18 @@ +#include +#include "objc/runtime.h" #include "sarray2.h" -#define isa class_pointer +#include "selector.h" #include "class.h" #include "lock.h" -#define objc_method_list method_list_new -#define objc_method method_new #include "method_list.h" +#include "slot_pool.h" +#include "dtable.h" SparseArray *__objc_uninstalled_dtable; -/** - * Structure for maintaining a linked list of temporary dtables. When sending - * an +initialize message to a class, we create a temporary dtables and store - * it in a linked list. This is then used when sending other messages to - * instances of classes in the middle of initialisation. - */ -typedef struct _InitializingDtable -{ - /** The class that owns the dtable. */ - Class class; - /** The dtable for this class. */ - void *dtable; - /** The next uninstalled dtable in the list. */ - struct _InitializingDtable *next; -} InitializingDtable; - /** Head of the list of temporary dtables. Protected by initialize_lock. */ InitializingDtable *temporary_dtables; +mutex_t initialize_lock; static uint32_t dtable_depth = 8; @@ -35,56 +22,6 @@ void __objc_init_dispatch_tables () __objc_uninstalled_dtable = SparseArrayNewWithDepth(dtable_depth); } -static inline int classHasInstalledDtable(struct objc_class *cls) -{ - return ((void*)cls->dtable != __objc_uninstalled_dtable); -} - - -/** - * 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 SparseArray *dtable_for_class(Class cls) -{ - if (classHasInstalledDtable(cls)) - { - return (SparseArray*)cls->dtable; - } - LOCK_UNTIL_RETURN(&initialize_lock); - if (classHasInstalledDtable(cls)) - { - return (SparseArray*)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. */ - SparseArray *dtable = __objc_uninstalled_dtable; - InitializingDtable *buffer = temporary_dtables; - while (NULL != buffer) - { - if (buffer->class == cls) - { - dtable = (SparseArray*)buffer->dtable; - break; - } - buffer = buffer->next; - } - UNLOCK(&initialize_lock); - if (dtable == 0) - { - dtable = __objc_uninstalled_dtable; - } - return dtable; -} - -static inline int classHasDtable(struct objc_class *cls) -{ - return (dtable_for_class(cls) != __objc_uninstalled_dtable); -} - static void collectMethodsForMethodListToSparseArray( struct objc_method_list *list, SparseArray *sarray) @@ -95,7 +32,7 @@ static void collectMethodsForMethodListToSparseArray( } for (unsigned i=0 ; icount ; i++) { - SparseArrayInsert(sarray, PTR_TO_IDX(list->methods[i].selector->sel_id), + SparseArrayInsert(sarray, PTR_TO_IDX(list->methods[i].selector->name), (void*)&list->methods[i]); } } @@ -107,7 +44,7 @@ static BOOL installMethodInDtable(Class class, BOOL replaceExisting) { assert(__objc_uninstalled_dtable != dtable); - uint32_t sel_id = PTR_TO_IDX(method->selector->sel_id); + uint32_t sel_id = PTR_TO_IDX(method->selector->name); struct objc_slot *slot = SparseArrayLookup(dtable, sel_id); if (NULL != slot) { @@ -222,6 +159,9 @@ void __objc_update_dispatch_table_for_class(Class cls) objc_update_dtable_for_class(cls); } +static void __objc_install_dispatch_table_for_class(Class class); + + static SparseArray *create_dtable_for_class(Class class) { // Don't create a dtable for a class that already has one @@ -305,7 +245,119 @@ void objc_resize_dtables(uint32_t newSize) } } +void objc_resolve_class(Class); + +/** + * Send a +initialize message to the receiver, if required. + */ +void objc_send_initialize(id object) +{ + Class class = object->isa; + // If the first message is sent to an instance (weird, but possible and + // likely for things like NSConstantString, make sure +initialize goes to + // the class not the metaclass. + if (objc_test_class_flag(class, objc_class_flag_meta)) + { + class = (Class)object; + } + Class meta = class->isa; + + // If this class is already initialized (e.g. in another thread), give up. + if (objc_test_class_flag(class, objc_class_flag_initialized)) { return; } + + // Grab a lock to make sure we are only sending one +initialize message at + // once. + // + // NOTE: Ideally, we would actually lock on the class object using + // objc_sync_enter(). This should be fixed once sync.m contains a (fast) + // special case for classes. + LOCK_UNTIL_RETURN(&initialize_lock); -#define sarray_get_safe(x,y) SparseArrayLookup((SparseArray*)x, y) -#undef objc_method_list -#undef objc_method + // Make sure that the class is resolved. + objc_resolve_class(class); + + // Make sure that the superclass is initialized first. + if (Nil != class->super_class) + { + objc_send_initialize((id)class->super_class); + } + + // Superclass +initialize might possibly send a message to this class, in + // which case this method would be called again. See NSObject and + // NSAutoreleasePool +initialize interaction in GNUstep. + if (objc_test_class_flag(class, objc_class_flag_initialized)) { return; } + + // Set the initialized flag on both this class and its metaclass, to make + // sure that +initialize is only ever sent once. + objc_set_class_flag(class, objc_class_flag_initialized); + objc_set_class_flag(meta, objc_class_flag_initialized); + + + // Create a temporary dtable, to be installed later. + SparseArray *class_dtable = create_dtable_for_class(class); + SparseArray *dtable = create_dtable_for_class(meta); + + // Create an entry in the dtable look-aside buffer for this. When sending + // a message to this class in future, the lookup function will check this + // buffer if the receiver's dtable is not installed, and block if + // attempting to send a message to this class. + InitializingDtable meta_buffer = { meta, dtable, temporary_dtables }; + InitializingDtable buffer = { class, class_dtable, &meta_buffer }; + + // Store the buffer in the temporary dtables list. Note that it is safe to + // insert it into a global list, even though it's a temporary variable, + // because we will clean it up after this function. + // + // FIXME: This will actually break if +initialize throws an exception... + temporary_dtables = &buffer; + + static SEL initializeSel = 0; + if (0 == initializeSel) + { + initializeSel = sel_registerName("initialize"); + } + struct objc_slot *initializeSlot = + SparseArrayLookup(dtable, PTR_TO_IDX(initializeSel->name)); + + if (0 != initializeSlot) + { + if (Nil != class->super_class) + { + // The dtable to use for sending messages to the superclass. This is + // the superclass's metaclass' dtable. + SparseArray *super_dtable = class->super_class->isa->dtable; + struct objc_slot *superSlot = SparseArrayLookup(super_dtable, + PTR_TO_IDX(initializeSel->name)); + // Check that this IMP comes from the class, not from its superclass. + // Note that the superclass dtable is guaranteed to be installed at + // this point because we sent it a +initialize message already. + if (0 == superSlot || superSlot->method != initializeSlot->method) + { + initializeSlot->method((id)class, initializeSel); + } + } + else + { + initializeSlot->method((id)class, initializeSel); + } + } + + // Install the real dtable for both the class and the metaclass. + meta->dtable = dtable; + class->dtable = class_dtable; + + // Remove the look-aside buffer entry. + if (temporary_dtables == &buffer) + { + temporary_dtables = meta_buffer.next; + } + else + { + InitializingDtable *prev = temporary_dtables; + while (prev->next->class != class) + { + prev = prev->next; + } + prev->next = meta_buffer.next; + } +} diff --git a/dtable.h b/dtable.h new file mode 100644 index 0000000..229e273 --- /dev/null +++ b/dtable.h @@ -0,0 +1,75 @@ +#include "lock.h" +#include "class.h" +#include "sarray2.h" +/** + * Pointer to the sparse array representing the pretend (uninstalled) dtable. + */ +extern SparseArray *__objc_uninstalled_dtable; +/** + * Structure for maintaining a linked list of temporary dtables. When sending + * an +initialize message to a class, we create a temporary dtables and store + * it in a linked list. This is then used when sending other messages to + * instances of classes in the middle of initialisation. + */ +typedef struct _InitializingDtable +{ + /** The class that owns the dtable. */ + Class class; + /** The dtable for this class. */ + void *dtable; + /** The next uninstalled dtable in the list. */ + struct _InitializingDtable *next; +} InitializingDtable; + +/** Head of the list of temporary dtables. Protected by initialize_lock. */ +extern InitializingDtable *temporary_dtables; +mutex_t initialize_lock; + +static inline int classHasInstalledDtable(struct objc_class *cls) +{ + return ((void*)cls->dtable != __objc_uninstalled_dtable); +} + +/** + * 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 SparseArray *dtable_for_class(Class cls) +{ + if (classHasInstalledDtable(cls)) + { + return (SparseArray*)cls->dtable; + } + LOCK_UNTIL_RETURN(&initialize_lock); + if (classHasInstalledDtable(cls)) + { + return (SparseArray*)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. */ + SparseArray *dtable = __objc_uninstalled_dtable; + InitializingDtable *buffer = temporary_dtables; + while (NULL != buffer) + { + if (buffer->class == cls) + { + dtable = (SparseArray*)buffer->dtable; + break; + } + buffer = buffer->next; + } + UNLOCK(&initialize_lock); + if (dtable == 0) + { + dtable = __objc_uninstalled_dtable; + } + return dtable; +} + +static inline int classHasDtable(struct objc_class *cls) +{ + return (dtable_for_class(cls) != __objc_uninstalled_dtable); +} diff --git a/gc.c b/gc.c deleted file mode 100644 index cc8fe11..0000000 --- a/gc.c +++ /dev/null @@ -1,451 +0,0 @@ -/* Basic data types for Objective C. - Copyright (C) 1998, 2002, 2004, 2005, 2006, 2009 Free Software Foundation, Inc. - 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 -. */ - -#include "objc/objc.h" -#include "objc/encoding.h" - -#include -#include -#include - -#if OBJC_WITH_GC - -#include -#include - -/* gc_typed.h uses the following but doesn't declare them */ -typedef GC_word word; -typedef GC_signed_word signed_word; -#define BITS_PER_WORD (CHAR_BIT * sizeof (word)) - -#include - -/* The following functions set up in `mask` the corresponding pointers. - The offset is incremented with the size of the type. */ - -#define ROUND(V, A) \ - ({ typeof (V) __v = (V); typeof (A) __a = (A); \ - __a * ((__v+__a - 1)/__a); }) - -#define SET_BIT_FOR_OFFSET(mask, offset) \ - GC_set_bit (mask, offset / sizeof (void *)) - -/* Some prototypes */ -static void -__objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset); -static void -__objc_gc_setup_union (GC_bitmap mask, const char *type, int offset); - - -static void -__objc_gc_setup_array (GC_bitmap mask, const char *type, int offset) -{ - int i, len = atoi (type + 1); - - while (isdigit (*++type)) - /* do nothing */; /* skip the size of the array */ - - switch (*type) { - case _C_ARY_B: - for (i = 0; i < len; i++) - __objc_gc_setup_array (mask, type, offset); - break; - - case _C_STRUCT_B: - for (i = 0; i < len; i++) - __objc_gc_setup_struct (mask, type, offset); - break; - - case _C_UNION_B: - for (i = 0; i < len; i++) - __objc_gc_setup_union (mask, type, offset); - break; - - default: - break; - } -} - -static void -__objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset) -{ - struct objc_struct_layout layout; - unsigned int position; - const char *mtype; - - objc_layout_structure (type, &layout); - - while (objc_layout_structure_next_member (&layout)) - { - BOOL gc_invisible = NO; - - objc_layout_structure_get_info (&layout, &position, NULL, &mtype); - - /* Skip the variable name */ - if (*mtype == '"') - { - for (mtype++; *mtype++ != '"';) - /* do nothing */; - } - - if (*mtype == _C_GCINVISIBLE) - { - gc_invisible = YES; - mtype++; - } - - /* Add to position the offset of this structure */ - position += offset; - - switch (*mtype) { - case _C_ID: - case _C_CLASS: - case _C_SEL: - case _C_PTR: - case _C_CHARPTR: - case _C_ATOM: - if (! gc_invisible) - SET_BIT_FOR_OFFSET (mask, position); - break; - - case _C_ARY_B: - __objc_gc_setup_array (mask, mtype, position); - break; - - case _C_STRUCT_B: - __objc_gc_setup_struct (mask, mtype, position); - break; - - case _C_UNION_B: - __objc_gc_setup_union (mask, mtype, position); - break; - - default: - break; - } - } -} - -static void -__objc_gc_setup_union (GC_bitmap mask, const char *type, int offset) -{ - /* Sub-optimal, quick implementation: assume the union is made of - pointers, set up the mask accordingly. */ - - int i, size, align; - - /* Skip the variable name */ - if (*type == '"') - { - for (type++; *type++ != '"';) - /* do nothing */; - } - - size = objc_sizeof_type (type); - align = objc_alignof_type (type); - - offset = ROUND (offset, align); - for (i = 0; i < size; i += sizeof (void *)) - { - SET_BIT_FOR_OFFSET (mask, offset); - offset += sizeof (void *); - } -} - - -/* Iterates over the types in the structure that represents the class - encoding and sets the bits in mask according to each ivar type. */ -static void -__objc_gc_type_description_from_type (GC_bitmap mask, const char *type) -{ - struct objc_struct_layout layout; - unsigned int offset, align; - const char *ivar_type; - - objc_layout_structure (type, &layout); - - while (objc_layout_structure_next_member (&layout)) - { - BOOL gc_invisible = NO; - - objc_layout_structure_get_info (&layout, &offset, &align, &ivar_type); - - /* Skip the variable name */ - if (*ivar_type == '"') - { - for (ivar_type++; *ivar_type++ != '"';) - /* do nothing */; - } - - if (*ivar_type == _C_GCINVISIBLE) - { - gc_invisible = YES; - ivar_type++; - } - - switch (*ivar_type) { - case _C_ID: - case _C_CLASS: - case _C_SEL: - case _C_PTR: - case _C_CHARPTR: - if (! gc_invisible) - SET_BIT_FOR_OFFSET (mask, offset); - break; - - case _C_ARY_B: - __objc_gc_setup_array (mask, ivar_type, offset); - break; - - case _C_STRUCT_B: - __objc_gc_setup_struct (mask, ivar_type, offset); - break; - - case _C_UNION_B: - __objc_gc_setup_union (mask, ivar_type, offset); - break; - - default: - break; - } - } -} - -/* Computes in *type the full type encoding of this class including - its super classes. '*size' gives the total number of bytes allocated - into *type, '*current' the number of bytes used so far by the - encoding. */ -static void -__objc_class_structure_encoding (Class class, char **type, int *size, - int *current) -{ - int i, ivar_count; - struct objc_ivar_list *ivars; - - if (! class) - { - strcat (*type, "{"); - (*current)++; - return; - } - - /* Add the type encodings of the super classes */ - __objc_class_structure_encoding (class->super_class, type, size, current); - - ivars = class->ivars; - if (! ivars) - return; - - ivar_count = ivars->ivar_count; - - for (i = 0; i < ivar_count; i++) - { - struct objc_ivar *ivar = &(ivars->ivar_list[i]); - const char *ivar_type = ivar->ivar_type; - int len = strlen (ivar_type); - - if (*current + len + 1 >= *size) - { - /* Increase the size of the encoding string so that it - contains this ivar's type. */ - *size = ROUND (*current + len + 1, 10); - *type = objc_realloc (*type, *size); - } - strcat (*type + *current, ivar_type); - *current += len; - } -} - - -/* Allocates the memory that will hold the type description for class - and calls the __objc_class_structure_encoding that generates this - value. */ -void -__objc_generate_gc_type_description (Class class) -{ - GC_bitmap mask; - int bits_no, size; - int type_size = 10, current; - char *class_structure_type; - - if (! CLS_ISCLASS (class)) - return; - - /* We have to create a mask in which each bit counts for a pointer member. - We take into consideration all the non-pointer instance variables and we - round them up to the alignment. */ - - /* The number of bits in the mask is the size of an instance in bytes divided - by the size of a pointer. */ - bits_no = (ROUND (class_get_instance_size (class), sizeof (void *)) - / sizeof (void *)); - size = ROUND (bits_no, BITS_PER_WORD) / BITS_PER_WORD; - mask = objc_atomic_malloc (size * sizeof (int)); - memset (mask, 0, size * sizeof (int)); - - class_structure_type = objc_atomic_malloc (type_size); - *class_structure_type = current = 0; - __objc_class_structure_encoding (class, &class_structure_type, - &type_size, ¤t); - if (current + 1 == type_size) - class_structure_type = objc_realloc (class_structure_type, ++type_size); - strcat (class_structure_type + current, "}"); -#ifdef DEBUG - printf ("type description for '%s' is %s\n", class->name, class_structure_type); -#endif - - __objc_gc_type_description_from_type (mask, class_structure_type); - objc_free (class_structure_type); - -#ifdef DEBUG - printf (" mask for '%s', type '%s' (bits %d, mask size %d) is:", - class_structure_type, class->name, bits_no, size); - { - int i; - for (i = 0; i < size; i++) - printf (" %lx", mask[i]); - } - puts (""); -#endif - - class->gc_object_type = (void *) GC_make_descriptor (mask, bits_no); -} - - -/* Returns YES if type denotes a pointer type, NO otherwise */ -static inline BOOL -__objc_ivar_pointer (const char *type) -{ - type = objc_skip_type_qualifiers (type); - - return (*type == _C_ID - || *type == _C_CLASS - || *type == _C_SEL - || *type == _C_PTR - || *type == _C_CHARPTR - || *type == _C_ATOM); -} - - -/* Mark the instance variable whose name is given by ivarname as a - weak pointer (a pointer hidden to the garbage collector) if - gc_invisible is true. If gc_invisible is false it unmarks the - instance variable and makes it a normal pointer, visible to the - garbage collector. - - This operation only makes sense on instance variables that are - pointers. */ -void -class_ivar_set_gcinvisible (Class class, const char *ivarname, - BOOL gc_invisible) -{ - int i, ivar_count; - struct objc_ivar_list *ivars; - - if (! class || ! ivarname) - return; - - ivars = class->ivars; - if (! ivars) - return; - - ivar_count = ivars->ivar_count; - - for (i = 0; i < ivar_count; i++) - { - struct objc_ivar *ivar = &(ivars->ivar_list[i]); - const char *type; - - if (! ivar->ivar_name || strcmp (ivar->ivar_name, ivarname)) - continue; - - assert (ivar->ivar_type); - type = ivar->ivar_type; - - /* Skip the variable name */ - if (*type == '"') - { - for (type++; *type++ != '"';) - /* do nothing */; - } - - if (*type == _C_GCINVISIBLE) - { - char *new_type; - size_t len; - - if (gc_invisible || ! __objc_ivar_pointer (type)) - return; /* The type of the variable already matches the - requested gc_invisible type */ - - /* The variable is gc_invisible so we make it gc visible. */ - new_type = objc_atomic_malloc (strlen(ivar->ivar_type)); - len = (type - ivar->ivar_type); - memcpy (new_type, ivar->ivar_type, len); - new_type[len] = 0; - strcat (new_type, type + 1); - ivar->ivar_type = new_type; - } - else - { - char *new_type; - size_t len; - - if (! gc_invisible || ! __objc_ivar_pointer (type)) - return; /* The type of the variable already matches the - requested gc_invisible type */ - - /* The variable is gc visible so we make it gc_invisible. */ - new_type = objc_malloc (strlen(ivar->ivar_type) + 2); - len = (type - ivar->ivar_type); - memcpy (new_type, ivar->ivar_type, len); - new_type[len] = 0; - strcat (new_type, "!"); - strcat (new_type, type); - ivar->ivar_type = new_type; - } - - __objc_generate_gc_type_description (class); - return; - } - - /* Search the instance variable in the superclasses */ - class_ivar_set_gcinvisible (class->super_class, ivarname, gc_invisible); -} - -#else /* !OBJC_WITH_GC */ - -void -__objc_generate_gc_type_description (Class class __attribute__ ((__unused__))) -{ -} - -void class_ivar_set_gcinvisible (Class class __attribute__ ((__unused__)), - const char *ivarname __attribute__ ((__unused__)), - BOOL gc_invisible __attribute__ ((__unused__))) -{ -} - -#endif /* OBJC_WITH_GC */ diff --git a/linking.m b/linking.m deleted file mode 100644 index fa31bdf..0000000 --- a/linking.m +++ /dev/null @@ -1,39 +0,0 @@ -/* Force linking of classes required by Objective C runtime. - Copyright (C) 1997, 2009 Free Software Foundation, Inc. - Contributed by Ovidiu Predescu (ovidiu@net-community.com). - -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 -#include - -/* Generate references to Object and NXConstanstString classes since they are - needed by the runtime system to run correctly. */ - - -void __objc_linking (void) -{ - [Object name]; - [NXConstantString name]; -} - diff --git a/nil_method.c b/nil_method.c deleted file mode 100644 index 1de6e0d..0000000 --- a/nil_method.c +++ /dev/null @@ -1,54 +0,0 @@ -/* GNU Objective C Runtime nil receiver function - Copyright (C) 1993, 1995, 1996, 2002, 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 -. */ - - -/* This is the nil method, the function that is called when the receiver - of a method is nil */ - -#include "objc/runtime-legacy.h" - -/* When the receiver of a method invocation is nil, the runtime - returns nil_method() as the method implementation. This function - will be casted to whatever function was supposed to be executed to - execute that method (that function will take an id, followed by a - SEL, followed by who knows what arguments, depends on the method), - and executed. - - For this reason, nil_method() should be a function which can be - called in place of any function taking an 'id' argument followed by - a 'SEL' argument, followed by zero, or one, or any number of - arguments (both a fixed number, or a variable number !). - - There is no "proper" implementation of such a nil_method function - in C, however in all existing implementations it does not matter - when extra arguments are present, so we can simply create a function - taking a receiver and a selector, and all other arguments will be - ignored. :-) -*/ - -id -nil_method (id receiver, SEL op __attribute__ ((__unused__))) -{ - return 0; -} diff --git a/objc/hooks.h b/objc/hooks.h index e071049..b8abc61 100644 --- a/objc/hooks.h +++ b/objc/hooks.h @@ -22,3 +22,19 @@ OBJC_HOOK Class (*_objc_lookup_class)(const char *name); * Class load callback. */ OBJC_HOOK void (*_objc_load_callback)(Class class, struct objc_category *category); +/** + * The hook used for fast proxy lookups. This takes an object and a selector + * and returns the instance that the message should be forwarded to. + */ +OBJC_HOOK id (*objc_proxy_lookup)(id receiver, SEL op); +/** + * New runtime forwarding hook. This might be removed in future - it's + * actually no more expressive than the forward2 hook and forces Foundation to + * do some stuff that the runtime is better suited to. + */ +OBJC_HOOK struct objc_slot *(*__objc_msg_forward3)(id, SEL); +/** + * Forwarding hook. Takes an object and a selector and returns a method that + * handles the forwarding. + */ +OBJC_HOOK IMP (*__objc_msg_forward2)(id, SEL); diff --git a/runtime.c b/runtime.c index e3ce5ec..7b4b8d3 100644 --- a/runtime.c +++ b/runtime.c @@ -64,11 +64,6 @@ * Private runtime function for updating a dtable. */ void __objc_update_dispatch_table_for_class(Class); -/** - * Private runtime function for determining whether an object responds to a - * selector. - */ -BOOL __objc_responds_to(id, SEL); /** * Runtime library constant for uninitialized dispatch table. */ @@ -454,15 +449,6 @@ IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types) } -BOOL -class_respondsToSelector(Class cls, SEL sel) -{ - /* Warning the __objc_responds_to() function expects an id argument and - * dereferences the initial ivar (the 'isa' pointer) to find the class. - */ - return __objc_responds_to((id)&cls, sel); -} - void class_setIvarLayout(Class cls, const char *layout) { struct objc_ivar_list *list = (struct objc_ivar_list*)layout; diff --git a/sarray2.h b/sarray2.h index 5c99969..43ba6e7 100644 --- a/sarray2.h +++ b/sarray2.h @@ -11,6 +11,7 @@ #define _SARRAY_H_INCLUDED_ #include #include +#include /** * Sparse arrays, used to implement dispatch tables. Current implementation is diff --git a/selector.h b/selector.h index fc9eec6..e2685ff 100644 --- a/selector.h +++ b/selector.h @@ -1,3 +1,5 @@ +#ifndef OBJC_SELECTOR_H_INCLUDED +#define OBJC_SELECTOR_H_INCLUDED /** * Structure used to store the types for a selector. This allows for a quick * test to see whether a selector is polymorphic and allows enumeration of all @@ -24,3 +26,4 @@ struct objc_selector const char * types; }; +#endif // OBJC_SELECTOR_H_INCLUDED diff --git a/sendmsg.c b/sendmsg.c deleted file mode 100644 index 93c10e5..0000000 --- a/sendmsg.c +++ /dev/null @@ -1,499 +0,0 @@ -/* GNU Objective C Runtime message lookup - Copyright (C) 1993, 1995, 1996, 1997, 1998, - 2001, 2002, 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 -. */ - - -#include -#include "objc/runtime-legacy.h" -#include "objc/slot.h" -#include "objc/encoding.h" -#include "lock.h" -#include "slot_pool.h" - -/* Mutex protecting the pre-initialize dtable */ -static mutex_t initialize_lock; - -void objc_resolve_class(Class); - -/* 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 - * that of __objc_msg_forward. If both return NULL or are unset, - * the libgcc based functions (__builtin_apply and friends) are - * used. - */ -IMP (*__objc_msg_forward) (SEL) = NULL; -IMP (*__objc_msg_forward2) (id, SEL) = NULL; - -/* Send +initialize to class */ -static void __objc_send_initialize (Class); - -static void __objc_install_dispatch_table_for_class (Class); - - -#include "dtable.c" - -/* Forward declare some functions */ -static void __objc_init_install_dtable (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); - -/* Given a selector, return the proper forwarding implementation. */ -inline static -IMP -__objc_get_forward_imp (id rcv, SEL sel) -{ - /* If a custom forwarding hook was registered, try getting a forwarding - function from it. There are two forward routine hooks, one that - takes the receiver as an argument and one that does not. */ - if (__objc_msg_forward2) - { - IMP result; - if ((result = __objc_msg_forward2 (rcv, sel)) != NULL) - return result; - } - if (__objc_msg_forward) - { - IMP result; - if ((result = __objc_msg_forward (sel)) != NULL) - return result; - } - fprintf(stderr, "Object forwarding not available"); - abort(); -} - - -static inline IMP sarray_get_imp (void *dtable, size_t key) -{ - struct objc_slot *slot = sarray_get_safe (dtable, key); - return (NULL != slot) ? slot->method : (IMP)0; -} - - -/* Given a class and selector, return the selector's implementation. */ -inline -IMP -get_imp (Class class, SEL sel) -{ - /* In a vanilla implementation we would first check if the dispatch - table is installed. Here instead, to get more speed in the - standard case (that the dispatch table is installed) we first try - to get the imp using brute force. Only if that fails, we do what - we should have been doing from the very beginning, that is, check - if the dispatch table needs to be installed, install it if it's - not installed, and retrieve the imp from the table if it's - installed. */ - IMP res = sarray_get_imp (class->dtable, (size_t) sel->sel_id); - if (res == 0) - { - /* This will block if calling +initialize from another thread. */ - void *dtable = dtable_for_class(class); - /* Not a valid method */ - if (dtable == __objc_uninstalled_dtable) - { - /* The dispatch table needs to be installed. */ - objc_mutex_lock (__objc_runtime_mutex); - - /* Double-checked locking pattern: Check - __objc_uninstalled_dtable again in case another thread - installed the dtable while we were waiting for the lock - to be released. */ - if (dtable_for_class(class) == __objc_uninstalled_dtable) - { - __objc_install_dispatch_table_for_class (class); - } - - objc_mutex_unlock (__objc_runtime_mutex); - /* Call ourselves with the installed dispatch table - and get the real method */ - res = get_imp (class, sel); - } - else - { - /* The dispatch table has been installed. */ - - /* Get the method from the dispatch table (we try to get it - again in case another thread has installed the dtable just - after we invoked sarray_get_safe, but before we checked - class->dtable == __objc_uninstalled_dtable). - */ - res = sarray_get_imp (dtable, (size_t) sel->sel_id); - if (res == 0) - { - /* The dispatch table has been installed, and the method - is not in the dispatch table. So the method just - doesn't exist for the class. Return the forwarding - implementation. */ - res = __objc_get_forward_imp ((id)class, sel); - } - } - } - return res; -} - -/* Query if an object can respond to a selector, returns YES if the -object implements the selector otherwise NO. Does not check if the -method can be forwarded. */ -inline -BOOL -__objc_responds_to (id object, SEL sel) -{ - void *res; - - /* Install dispatch table if need be */ - if (dtable_for_class(object->class_pointer) == __objc_uninstalled_dtable) - { - objc_mutex_lock (__objc_runtime_mutex); - if (dtable_for_class(object->class_pointer) == __objc_uninstalled_dtable) - { - __objc_install_dispatch_table_for_class (object->class_pointer); - } - objc_mutex_unlock (__objc_runtime_mutex); - } - - /* Get the method from the dispatch table */ - res = sarray_get_safe (dtable_for_class(object->class_pointer), - (size_t) sel->sel_id); - return (res != 0); -} - -extern id (*objc_proxy_lookup)(id receiver, SEL op); -/* This is the lookup function. All entries in the table are either a - valid method *or* zero. If zero then either the dispatch table - needs to be installed or it doesn't exist and forwarding is attempted. */ -inline -IMP -objc_msg_lookup (id receiver, SEL op) -{ - IMP result; - if (receiver) - { - result = sarray_get_imp (receiver->class_pointer->dtable, - PTR_TO_IDX(op->sel_id)); - if (result == 0) - { - /** Get the dtable that we should be using for lookup. This will - * block if we are in the middle of running +initialize in another - * thread. */ - void *dtable = dtable_for_class(receiver->class_pointer); - /* Not a valid method */ - if (dtable == __objc_uninstalled_dtable) - { - /* The dispatch table needs to be installed. - This happens on the very first method call to the class. */ - __objc_init_install_dtable (receiver, op); - - /* Get real method for this in newly installed dtable */ - result = get_imp (receiver->class_pointer, op); - } - else - { - /* The dispatch table has been installed. Check again - if the method exists (just in case the dispatch table - has been installed by another thread after we did the - previous check that the method exists). - */ - result = sarray_get_imp (dtable, PTR_TO_IDX(op->sel_id)); - if (result == 0) - { - /* Try again after giving the code a chance to install new - * methods. This lookup mechanism doesn't support forwarding - * to other objects, so only call the lookup recursively if - * the receiver is not changed. - */ - id newReceiver = objc_proxy_lookup (receiver, op); - if (newReceiver == receiver) - { - return objc_msg_lookup(receiver, op); - } - /* If the method still just doesn't exist for the - class, attempt to forward the method. */ - result = __objc_get_forward_imp (receiver, 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 *); - -/* - * TODO: This never worked properly. Delete it after checking no one is - * misguided enough to be using it. - */ -retval_t -objc_msg_sendv (id object, SEL op, arglist_t arg_frame) -{ - fprintf(stderr, "objc_msg_sendv() never worked correctly. Don't use it.\n"); - abort(); -} - - -/* Send +initialize to class if not already done */ -static void -__objc_send_initialize (Class class) -{ - /* This *must* be a class object */ - assert (CLS_ISCLASS (class)); - assert (! CLS_ISMETA (class)); - - if (! CLS_ISINITIALIZED (class)) - { - /* This is always called with the runtime lock, which guarantees - * atomicity, but we also need to make sure that the initialize lock is - * held so that we can create the premature dtable. */ - LOCK(&initialize_lock); - if (! CLS_ISRESOLV (class)) - objc_resolve_class(class); - - - /* Create the garbage collector type memory description */ - __objc_generate_gc_type_description (class); - - if (class->super_class) - __objc_send_initialize (class->super_class); - // Superclass +initialize might possibly send a message to this class, in - // which case this method would be called again. See NSObject and - // NSAutoreleasePool +initialize interaction in GNUstep. - if (CLS_ISINITIALIZED (class)) - { - UNLOCK(&initialize_lock); - return; - } - CLS_SETINITIALIZED (class); - CLS_SETINITIALIZED (class->class_pointer); - /* Create the dtable, but don't install it on the class quite yet. */ - - void *dtable = create_dtable_for_class(class); - /* Taking a pointer to an on-stack object and storing it in a global is - * usually a silly idea. It is safe here, because we invert this - * transform before we return, and we use initialize_lock to make sure no - * other threads have access to this pointer. */ - InitializingDtable buffer = { class, dtable, temporary_dtables }; - temporary_dtables = &buffer; - - { - 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); - - } - class->dtable = dtable; - /* Note: We don't free the cache entry; it was allocated on the stack. */ - if (temporary_dtables == &buffer) - { - temporary_dtables = temporary_dtables->next; - } - else - { - InitializingDtable *prev = temporary_dtables; - while (prev->next->class != class) - { - prev = prev->next; - } - prev->next = buffer.next; - } - UNLOCK(&initialize_lock); - } -} - -/* 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. - - This one is only called for categories. Class objects have their - methods installed right away, and their selectors are made into - SEL's by the function __objc_register_selectors_from_class. */ -void -class_add_method_list (Class class, MethodList_t list) -{ - /* Passing of a linked list is not allowed. Do multiple calls. */ - assert (! list->method_next); - - __objc_register_selectors_from_list(list); - - /* Add the methods to the class's method list. */ - list->method_next = class->methods; - class->methods = list; - - /* Update the dispatch table of class */ - __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); -} - - -/* Search for a method starting from the current class up its hierarchy. - Return a pointer to the method's method structure if found. NULL - otherwise. */ - -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; - - /* Scan the method list of the class. If the method isn't found in the - list then step to its super class. */ - for (class = cls; ((! method) && class); class = class->super_class) - method = search_for_method_in_list (class->methods, sel); - - return method; -} - - - -/* Given a linked list of method and a method's name. Search for the named - method's method structure. Return a pointer to the method's method - structure if found. NULL otherwise. */ -Method_t -search_for_method_in_list (MethodList_t list, SEL op) -{ - MethodList_t method_list = list; - - if (! sel_is_mapped (op)) - return NULL; - - /* If not found then we'll search the list. */ - while (method_list) - { - int i; - - /* Search the method list. */ - 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; - } - - /* The method wasn't found. Follow the link to the next list of - methods. */ - method_list = method_list->method_next; - } - - return NULL; -} - -/* 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. */ -inline -struct sarray * -objc_get_uninstalled_dtable () -{ - return (void*)__objc_uninstalled_dtable; -} - -// This is an ugly hack to make sure that the compiler can do inlining into -// sendmsg2.c from here. It should be removed and the two compiled separately -// once we drop support for compilers that are too primitive to do cross-module -// inlining. -#include "sendmsg2.c" diff --git a/sendmsg2.c b/sendmsg2.c index f205854..c7b30d2 100644 --- a/sendmsg2.c +++ b/sendmsg2.c @@ -1,10 +1,19 @@ +#include "objc/runtime.h" #include "lock.h" +#include "dtable.h" +#include "selector.h" +#include "loader.h" +#include "objc/hooks.h" #include #include +#include + +void objc_send_initialize(id object); -#define PROFILE __thread id objc_msg_sender; +static id nil_method(id self, SEL _cmd) { return nil; } + static struct objc_slot nil_slot = { Nil, Nil, "", 1, (IMP)nil_method }; typedef struct objc_slot *Slot_t; @@ -18,39 +27,28 @@ static Slot_t objc_msg_forward3_null(id receiver, SEL op) { return &nil_slot; } id (*objc_proxy_lookup)(id receiver, SEL op) = objc_proxy_lookup_null; Slot_t (*objc_msg_forward3)(id receiver, SEL op) = objc_msg_forward3_null; -static inline -Slot_t objc_msg_lookup_internal(id *receiver, SEL selector, id sender) +static inline Slot_t objc_msg_lookup_internal(id *receiver, + SEL selector, + id sender) { - Slot_t result = sarray_get_safe((*receiver)->class_pointer->dtable, - PTR_TO_IDX(selector->sel_id)); + Slot_t result = SparseArrayLookup((*receiver)->isa->dtable, + PTR_TO_IDX(selector->name)); if (0 == result) { - Class class = (*receiver)->class_pointer; + Class class = (*receiver)->isa; void *dtable = dtable_for_class(class); /* Install the dtable if it hasn't already been initialized. */ if (dtable == __objc_uninstalled_dtable) { - __objc_init_install_dtable (*receiver, selector); + objc_send_initialize(*receiver); dtable = dtable_for_class(class); - result = sarray_get_safe(dtable, PTR_TO_IDX(selector->sel_id)); - if (0 == result) - { - objc_mutex_lock(__objc_runtime_mutex); - dtable = dtable_for_class(class); - if (dtable == __objc_uninstalled_dtable) - { - __objc_install_dispatch_table_for_class(class); - dtable = dtable_for_class(class); - } - objc_mutex_unlock(__objc_runtime_mutex); - result = sarray_get_safe(dtable, PTR_TO_IDX(selector->sel_id)); - } + result = SparseArrayLookup(dtable, PTR_TO_IDX(selector->name)); } else { // Check again incase another thread updated the dtable while we // weren't looking - result = sarray_get_safe(dtable, PTR_TO_IDX(selector->sel_id)); + result = SparseArrayLookup(dtable, PTR_TO_IDX(selector->name)); } if (0 == result) { @@ -95,7 +93,7 @@ Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender) * we can guarantee that it is not (e.g. with GCKit) if (__builtin_expect(sender == nil || - (sender->class_pointer->info & (*receiver)->class_pointer->info & _CLS_PLANE_AWARE),1)) + (sender->isa->info & (*receiver)->isa->info & _CLS_PLANE_AWARE),1)) */ { return objc_msg_lookup_internal(receiver, selector, sender); @@ -111,14 +109,14 @@ Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender) return objc_plane_lookup(receiver, selector, sender); } -Slot_t objc_slot_lookup_super(Super_t super, SEL selector) +Slot_t objc_slot_lookup_super(struct objc_super *super, SEL selector) { - id receiver = super->self; + id receiver = super->receiver; if (receiver) { Class class = super->class; - Slot_t result = sarray_get_safe(dtable_for_class(class), - PTR_TO_IDX(selector->sel_id)); + Slot_t result = SparseArrayLookup(dtable_for_class(class), + PTR_TO_IDX(selector->name)); if (0 == result) { // Dtable should always be installed in the superclass @@ -133,7 +131,10 @@ Slot_t objc_slot_lookup_super(Super_t super, SEL selector) } } -#ifdef PROFILE +//////////////////////////////////////////////////////////////////////////////// +// Profiling +//////////////////////////////////////////////////////////////////////////////// + /** * Mutex used to protect non-thread-safe parts of the profiling subsystem. */ @@ -211,4 +212,87 @@ void objc_msg_profile(id receiver, IMP method, struct profile_info profile_data = { module, callsite, method }; fwrite(&profile_data, sizeof(profile_data), 1, profileData); } -#endif + +/** + * Looks up a slot without invoking any forwarding mechanisms + */ +Slot_t objc_get_slot(Class cls, SEL selector) +{ + Slot_t result = SparseArrayLookup(cls->dtable, PTR_TO_IDX(selector->name)); + if (0 == result) + { + void *dtable = dtable_for_class(cls); + /* Install the dtable if it hasn't already been initialized. */ + if (dtable == __objc_uninstalled_dtable) + { + //objc_send_initialize((id)cls); + dtable = dtable_for_class(cls); + result = SparseArrayLookup(dtable, PTR_TO_IDX(selector->name)); + } + else + { + // Check again incase another thread updated the dtable while we + // weren't looking + result = SparseArrayLookup(dtable, PTR_TO_IDX(selector->name)); + } + } + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +// Public API +//////////////////////////////////////////////////////////////////////////////// + +BOOL class_respondsToSelector(Class cls, SEL selector) +{ + return NULL != objc_get_slot(cls, selector); +} + +//////////////////////////////////////////////////////////////////////////////// +// Legacy compatibility +//////////////////////////////////////////////////////////////////////////////// + +/** + * Legacy message lookup function. + */ +BOOL __objc_responds_to(id object, SEL sel) +{ + return class_respondsToSelector(object->isa, sel); +} + +IMP get_imp(Class cls, SEL selector) +{ + Slot_t slot = objc_get_slot(cls, selector); + return NULL != slot ? slot->method : NULL; +} + +/** + * Legacy message lookup function. Does not support fast proxies or safe IMP + * caching. + */ +IMP objc_msg_lookup(id receiver, SEL selector) +{ + if (nil == receiver) { return (IMP)nil_method; } + + id self = receiver; + Slot_t slot = objc_msg_lookup_internal(&self, selector, nil); + if (self != receiver) + { + return __objc_msg_forward2(receiver, selector); + } + return slot->method; +} + +IMP objc_msg_lookup_super(struct objc_super *super, SEL selector) +{ + return objc_slot_lookup_super(super, selector)->method; +} +/** + * Message send function that only ever worked on a small subset of compiler / + * architecture combinations. + */ +void *objc_msg_sendv(void) +{ + fprintf(stderr, "objc_msg_sendv() never worked correctly. Don't use it.\n"); + abort(); +} diff --git a/slot_pool.h b/slot_pool.h index dbacd52..3af4ac5 100644 --- a/slot_pool.h +++ b/slot_pool.h @@ -2,13 +2,13 @@ #define POOL_TYPE struct objc_slot #include "pool.h" -static inline struct objc_slot *new_slot_for_method_in_class(Method *method, +static inline struct objc_slot *new_slot_for_method_in_class(Method method, Class class) { struct objc_slot *slot = slot_pool_alloc(); slot->owner = class; - slot->types = method->method_types; - slot->method = method->method_imp; + slot->types = method->types; + slot->method = method->imp; slot->version = 1; return slot; }