2010-06-03 15:17:12 +00:00
|
|
|
#include "lock.h"
|
|
|
|
#include "class.h"
|
|
|
|
#include "sarray2.h"
|
2010-08-15 22:30:32 +00:00
|
|
|
#include "objc/slot.h"
|
|
|
|
#include <stdint.h>
|
2010-08-15 11:17:00 +00:00
|
|
|
|
2010-08-15 22:30:32 +00:00
|
|
|
#ifdef __OBJC_LOW_MEMORY__
|
|
|
|
typedef struct objc_dtable* dtable_t;
|
|
|
|
struct objc_slot* objc_dtable_lookup(dtable_t dtable, uint32_t uid);
|
2010-08-15 11:17:00 +00:00
|
|
|
#else
|
|
|
|
typedef SparseArray* dtable_t;
|
|
|
|
# define objc_dtable_lookup SparseArrayLookup
|
|
|
|
#endif
|
|
|
|
|
2010-06-03 15:17:12 +00:00
|
|
|
/**
|
|
|
|
* Pointer to the sparse array representing the pretend (uninstalled) dtable.
|
|
|
|
*/
|
2010-08-15 11:17:00 +00:00
|
|
|
extern dtable_t __objc_uninstalled_dtable;
|
2010-06-03 15:17:12 +00:00
|
|
|
/**
|
|
|
|
* 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. */
|
2010-08-15 11:17:00 +00:00
|
|
|
dtable_t dtable;
|
2010-06-03 15:17:12 +00:00
|
|
|
/** 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;
|
2010-08-15 11:17:00 +00:00
|
|
|
extern mutex_t initialize_lock;
|
2010-06-03 15:17:12 +00:00
|
|
|
|
2010-06-06 21:11:25 +00:00
|
|
|
/**
|
|
|
|
* Returns whether a class has an installed dtable.
|
|
|
|
*/
|
2010-06-03 15:17:12 +00:00
|
|
|
static inline int classHasInstalledDtable(struct objc_class *cls)
|
|
|
|
{
|
2010-08-15 11:17:00 +00:00
|
|
|
return (cls->dtable != __objc_uninstalled_dtable);
|
2010-06-03 15:17:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2010-08-15 11:17:00 +00:00
|
|
|
static inline dtable_t dtable_for_class(Class cls)
|
2010-06-03 15:17:12 +00:00
|
|
|
{
|
|
|
|
if (classHasInstalledDtable(cls))
|
|
|
|
{
|
2010-08-15 11:17:00 +00:00
|
|
|
return cls->dtable;
|
2010-06-03 15:17:12 +00:00
|
|
|
}
|
|
|
|
LOCK_UNTIL_RETURN(&initialize_lock);
|
|
|
|
if (classHasInstalledDtable(cls))
|
|
|
|
{
|
2010-08-15 11:17:00 +00:00
|
|
|
return cls->dtable;
|
2010-06-03 15:17:12 +00:00
|
|
|
}
|
|
|
|
/* 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. */
|
2010-08-15 11:17:00 +00:00
|
|
|
dtable_t dtable = __objc_uninstalled_dtable;
|
2010-06-03 15:17:12 +00:00
|
|
|
InitializingDtable *buffer = temporary_dtables;
|
|
|
|
while (NULL != buffer)
|
|
|
|
{
|
|
|
|
if (buffer->class == cls)
|
|
|
|
{
|
2010-08-15 22:30:32 +00:00
|
|
|
dtable = buffer->dtable;
|
2010-06-03 15:17:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
buffer = buffer->next;
|
|
|
|
}
|
|
|
|
UNLOCK(&initialize_lock);
|
|
|
|
if (dtable == 0)
|
|
|
|
{
|
|
|
|
dtable = __objc_uninstalled_dtable;
|
|
|
|
}
|
|
|
|
return dtable;
|
|
|
|
}
|
|
|
|
|
2010-06-06 21:11:25 +00:00
|
|
|
/**
|
|
|
|
* Returns whether a class has had a dtable created. The dtable may be
|
|
|
|
* installed, or stored in the look-aside buffer.
|
|
|
|
*/
|
2010-06-03 15:17:12 +00:00
|
|
|
static inline int classHasDtable(struct objc_class *cls)
|
|
|
|
{
|
|
|
|
return (dtable_for_class(cls) != __objc_uninstalled_dtable);
|
|
|
|
}
|
2010-08-15 22:30:32 +00:00
|
|
|
|
2010-06-06 21:11:25 +00:00
|
|
|
/**
|
|
|
|
* Updates the dtable for a class and its subclasses. Must be called after
|
|
|
|
* modifying a class's method list.
|
|
|
|
*/
|
|
|
|
void objc_update_dtable_for_class(Class);
|