From a4f97f75633044e7fdeab09e0ffbffd1ec2f7db9 Mon Sep 17 00:00:00 2001 From: David Chisnall Date: Wed, 11 Apr 2018 07:43:09 +0100 Subject: [PATCH] Refactor locking in setSuperclass. Now all lock ownership is tied to scopes, so will be released correctly in all return paths. --- runtime.c | 76 ++++++++++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/runtime.c b/runtime.c index 7b0ebd5..41276c0 100644 --- a/runtime.c +++ b/runtime.c @@ -522,58 +522,54 @@ Class class_setSuperclass(Class cls, Class newSuper) { CHECK_ARG(cls); CHECK_ARG(newSuper); + Class oldSuper; if (Nil == cls) { return Nil; } - LOCK_RUNTIME(); + { + LOCK_RUNTIME_FOR_SCOPE(); - if (cls->super_class == newSuper) { - UNLOCK_RUNTIME(); - return newSuper; - } + oldSuper = cls->super_class; - safe_remove_from_subclass_list(cls); - objc_resolve_class(newSuper); + if (oldSuper == newSuper) { return newSuper; } - Class oldSuper = cls->super_class; - cls->super_class = newSuper; + safe_remove_from_subclass_list(cls); + objc_resolve_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; + cls->super_class = newSuper; - if (UNLIKELY(class_isMetaClass(cls))) - { - // newSuper is presumably a metaclass. Its isa will therefore be the appropriate root metaclass. - cls->isa = newSuper->isa; - } - else - { - Class meta = cls->isa, newSuperMeta = newSuper->isa; - // Update the metaclass's superclass. - safe_remove_from_subclass_list(meta); - objc_resolve_class(newSuperMeta); + // 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 (UNLIKELY(class_isMetaClass(cls))) + { + // newSuper is presumably a metaclass. Its isa will therefore be the appropriate root metaclass. + cls->isa = newSuper->isa; + } + else + { + Class meta = cls->isa, newSuperMeta = newSuper->isa; + // Update the metaclass's superclass. + safe_remove_from_subclass_list(meta); + objc_resolve_class(newSuperMeta); - meta->super_class = newSuperMeta; - meta->isa = newSuperMeta->isa; + meta->super_class = newSuperMeta; + meta->isa = newSuperMeta->isa; - // The super class's subclass list is used in certain method resolution scenarios. - meta->sibling_class = newSuperMeta->subclass_list; - newSuperMeta->subclass_list = meta; - } + // The super class's subclass list is used in certain method resolution scenarios. + meta->sibling_class = newSuperMeta->subclass_list; + newSuperMeta->subclass_list = meta; + } - LOCK(&initialize_lock); - if (!objc_test_class_flag(cls, objc_class_flag_initialized)) - { - // Uninitialized classes don't have dtables to update - // and don't need their superclasses initialized. - UNLOCK(&initialize_lock); - UNLOCK_RUNTIME(); - return oldSuper; + LOCK_FOR_SCOPE(&initialize_lock); + if (!objc_test_class_flag(cls, objc_class_flag_initialized)) + { + // Uninitialized classes don't have dtables to update + // and don't need their superclasses initialized. + return oldSuper; + } } - UNLOCK(&initialize_lock); - UNLOCK_RUNTIME(); - objc_send_initialize((id)newSuper); // also initializes the metaclass objc_update_dtable_for_new_superclass(cls->isa, newSuper->isa); objc_update_dtable_for_new_superclass(cls, newSuper);