Tweak ordering when creating dtables to fix an irritating corner case in +initialize calls.

main
theraven 15 years ago
parent db53012509
commit e11e8dee46

@ -86,11 +86,6 @@ static dtable_t create_dtable_for_class(Class class)
Class super = class_getSuperclass(class); Class super = class_getSuperclass(class);
if (Nil != super && !classHasInstalledDtable(super))
{
super->dtable = create_dtable_for_class(super);
}
/* Allocate dtable if necessary */ /* Allocate dtable if necessary */
dtable_t dtable = calloc(1, sizeof(struct objc_dtable)); dtable_t dtable = calloc(1, sizeof(struct objc_dtable));
dtable->cls = class; dtable->cls = class;
@ -438,22 +433,20 @@ static SparseArray *create_dtable_for_class(Class class)
if (classHasDtable(class)) { return dtable_for_class(class); } if (classHasDtable(class)) { return dtable_for_class(class); }
Class super = class_getSuperclass(class); Class super = class_getSuperclass(class);
dtable_t dtable;
if (Nil != super && !classHasInstalledDtable(super))
{
super->dtable = create_dtable_for_class(super);
}
SparseArray *dtable;
/* Allocate dtable if necessary */
if (Nil == super) if (Nil == super)
{ {
dtable = SparseArrayNewWithDepth(dtable_depth); dtable = SparseArrayNewWithDepth(dtable_depth);
} }
else else
{ {
assert(__objc_uninstalled_dtable != dtable_for_class(super)); dtable_t super_dtable = dtable_for_class(super);
if (super_dtable == __objc_uninstalled_dtable)
{
super_dtable = create_dtable_for_class(super);
}
dtable = SparseArrayCopy(dtable_for_class(super)); dtable = SparseArrayCopy(dtable_for_class(super));
} }
@ -562,21 +555,22 @@ void objc_send_initialize(id object)
// Create a temporary dtable, to be installed later. // Create a temporary dtable, to be installed later.
dtable_t class_dtable = create_dtable_for_class(class); dtable_t class_dtable = create_dtable_for_class(class);
dtable_t dtable = create_dtable_for_class(meta); InitializingDtable buffer = { class, class_dtable, temporary_dtables };
temporary_dtables = &buffer;
// Create an entry in the dtable look-aside buffer for this. When sending // 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 // 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 // buffer if the receiver's dtable is not installed, and block if
// attempting to send a message to this class. // attempting to send a message to this class.
dtable_t dtable = create_dtable_for_class(meta);
InitializingDtable meta_buffer = { meta, dtable, temporary_dtables }; InitializingDtable meta_buffer = { meta, dtable, temporary_dtables };
InitializingDtable buffer = { class, class_dtable, &meta_buffer }; temporary_dtables = &meta_buffer;
// Store the buffer in the temporary dtables list. Note that it is safe to // 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, // insert it into a global list, even though it's a temporary variable,
// because we will clean it up after this function. // because we will clean it up after this function.
// //
// FIXME: This will actually break if +initialize throws an exception... // FIXME: This will actually break if +initialize throws an exception...
temporary_dtables = &buffer;
static SEL initializeSel = 0; static SEL initializeSel = 0;
if (0 == initializeSel) if (0 == initializeSel)
@ -590,14 +584,17 @@ void objc_send_initialize(id object)
{ {
if (Nil != class->super_class) if (Nil != class->super_class)
{ {
// The dtable to use for sending messages to the superclass. This is // The dtable to use for sending messages to the superclass. This
// the superclass's metaclass' dtable. // is the superclass's metaclass' dtable.
dtable_t super_dtable = class->super_class->isa->dtable; dtable_t super_dtable = dtable_for_class(class->super_class->isa);
struct objc_slot *superSlot = objc_dtable_lookup(super_dtable, struct objc_slot *superSlot = objc_dtable_lookup(super_dtable,
PTR_TO_IDX(initializeSel->name)); PTR_TO_IDX(initializeSel->name));
// Check that this IMP comes from the class, not from its superclass. // Check that this IMP comes from the class, not from its
// Note that the superclass dtable is guaranteed to be installed at // superclass. We still have to use dtable_for_class() here
// this point because we sent it a +initialize message already. // because our +initialize call might be in response to a message
// sent from a subclass (e.g. NSObject +initialize sending a
// message to NSAutoreleasePool: NSObject's dtable won't have been
// installed at this point.
if (0 == superSlot || superSlot->method != initializeSlot->method) if (0 == superSlot || superSlot->method != initializeSlot->method)
{ {
initializeSlot->method((id)class, initializeSel); initializeSlot->method((id)class, initializeSel);
@ -614,17 +611,17 @@ void objc_send_initialize(id object)
class->dtable = class_dtable; class->dtable = class_dtable;
// Remove the look-aside buffer entry. // Remove the look-aside buffer entry.
if (temporary_dtables == &buffer) if (temporary_dtables == &meta_buffer)
{ {
temporary_dtables = meta_buffer.next; temporary_dtables = buffer.next;
} }
else else
{ {
InitializingDtable *prev = temporary_dtables; InitializingDtable *prev = temporary_dtables;
while (prev->next->class != class) while (prev->next->class != meta)
{ {
prev = prev->next; prev = prev->next;
} }
prev->next = meta_buffer.next; prev->next = buffer.next;
} }
} }

Loading…
Cancel
Save