Skip to content

Commit

Permalink
teach class_setSuperclass about metaclasses, subclass lists, and dtables
Browse files Browse the repository at this point in the history
  • Loading branch information
DHowett committed Jan 22, 2018
1 parent 14bfb02 commit aa58f6f
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
4 changes: 2 additions & 2 deletions dtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ PRIVATE void init_dispatch_tables ()
Class class_getSuperclass(Class);


static dtable_t create_dtable_for_class(Class class, dtable_t root_dtable)
PRIVATE dtable_t create_dtable_for_class(Class class, dtable_t root_dtable)
{
// Don't create a dtable for a class that already has one
if (classHasDtable(class)) { return dtable_for_class(class); }
Expand Down Expand Up @@ -629,7 +629,7 @@ PRIVATE void add_method_list_to_class(Class cls,
checkARCAccessors(cls);
}

static dtable_t create_dtable_for_class(Class class, dtable_t root_dtable)
PRIVATE dtable_t create_dtable_for_class(Class class, dtable_t root_dtable)
{
// Don't create a dtable for a class that already has one
if (classHasDtable(class)) { return dtable_for_class(class); }
Expand Down
38 changes: 38 additions & 0 deletions runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
struct objc_slot *objc_get_slot(Class cls, SEL selector);
#define CHECK_ARG(arg) if (0 == arg) { return 0; }

static inline void safe_remove_from_subclass_list(Class cls);

/**
* Calls C++ destructors in the correct order.
*/
Expand Down Expand Up @@ -513,8 +515,44 @@ Class class_setSuperclass(Class cls, Class newSuper)
CHECK_ARG(cls);
CHECK_ARG(newSuper);
if (Nil == cls) { return Nil; }

LOCK_RUNTIME_FOR_SCOPE();

safe_remove_from_subclass_list(cls);

Class oldSuper = cls->super_class;
cls->super_class = newSuper;

// The super class's subclass list is used in certain method resolution scenarios.
cls->sibling_class = cls->super_class->subclass_list;
cls->super_class->subclass_list = cls;

if (!class_isMetaClass(cls))
{
// Update the metaclass's superclass.
class_setSuperclass(cls->isa, newSuper->isa);
}
else
{
// newSuper is presumably a metaclass. Its isa will therefore be the appropriate root metaclass.
cls->isa = newSuper->isa;
}

// Make sure the superclass is initialized if we're initialized.
if (objc_test_class_flag(cls, objc_class_flag_initialized))
{
objc_send_initialize(newSuper);
// Update the class's dtable to reflect its new superclass's dtable.
if (cls->dtable != uninstalled_dtable)
{
// we can't use objc_update_dtable_for_class here, as it doesn't take into account
// superclasses. It only walks downward.
free_dtable(cls->dtable);
cls->dtable = uninstalled_dtable;
cls->dtable = create_dtable_for_class(cls, uninstalled_dtable);
}
}

return oldSuper;
}

Expand Down

0 comments on commit aa58f6f

Please sign in to comment.