Skip to content

Commit aa58f6f

Browse files
committed
teach class_setSuperclass about metaclasses, subclass lists, and dtables
1 parent 14bfb02 commit aa58f6f

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

dtable.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ PRIVATE void init_dispatch_tables ()
179179
Class class_getSuperclass(Class);
180180

181181

182-
static dtable_t create_dtable_for_class(Class class, dtable_t root_dtable)
182+
PRIVATE dtable_t create_dtable_for_class(Class class, dtable_t root_dtable)
183183
{
184184
// Don't create a dtable for a class that already has one
185185
if (classHasDtable(class)) { return dtable_for_class(class); }
@@ -629,7 +629,7 @@ PRIVATE void add_method_list_to_class(Class cls,
629629
checkARCAccessors(cls);
630630
}
631631

632-
static dtable_t create_dtable_for_class(Class class, dtable_t root_dtable)
632+
PRIVATE dtable_t create_dtable_for_class(Class class, dtable_t root_dtable)
633633
{
634634
// Don't create a dtable for a class that already has one
635635
if (classHasDtable(class)) { return dtable_for_class(class); }

runtime.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
struct objc_slot *objc_get_slot(Class cls, SEL selector);
2323
#define CHECK_ARG(arg) if (0 == arg) { return 0; }
2424

25+
static inline void safe_remove_from_subclass_list(Class cls);
26+
2527
/**
2628
* Calls C++ destructors in the correct order.
2729
*/
@@ -513,8 +515,44 @@ Class class_setSuperclass(Class cls, Class newSuper)
513515
CHECK_ARG(cls);
514516
CHECK_ARG(newSuper);
515517
if (Nil == cls) { return Nil; }
518+
519+
LOCK_RUNTIME_FOR_SCOPE();
520+
521+
safe_remove_from_subclass_list(cls);
522+
516523
Class oldSuper = cls->super_class;
517524
cls->super_class = newSuper;
525+
526+
// The super class's subclass list is used in certain method resolution scenarios.
527+
cls->sibling_class = cls->super_class->subclass_list;
528+
cls->super_class->subclass_list = cls;
529+
530+
if (!class_isMetaClass(cls))
531+
{
532+
// Update the metaclass's superclass.
533+
class_setSuperclass(cls->isa, newSuper->isa);
534+
}
535+
else
536+
{
537+
// newSuper is presumably a metaclass. Its isa will therefore be the appropriate root metaclass.
538+
cls->isa = newSuper->isa;
539+
}
540+
541+
// Make sure the superclass is initialized if we're initialized.
542+
if (objc_test_class_flag(cls, objc_class_flag_initialized))
543+
{
544+
objc_send_initialize(newSuper);
545+
// Update the class's dtable to reflect its new superclass's dtable.
546+
if (cls->dtable != uninstalled_dtable)
547+
{
548+
// we can't use objc_update_dtable_for_class here, as it doesn't take into account
549+
// superclasses. It only walks downward.
550+
free_dtable(cls->dtable);
551+
cls->dtable = uninstalled_dtable;
552+
cls->dtable = create_dtable_for_class(cls, uninstalled_dtable);
553+
}
554+
}
555+
518556
return oldSuper;
519557
}
520558

0 commit comments

Comments
 (0)