Fix dtable rebase and add a test for a missing case

The dtable rebasing rework in b81df02b broke the inheritance of
superclass methods from a superclass that had already been initialized.
main
Dustin Howett 7 years ago committed by David Chisnall
parent 33cdcd709d
commit f392ff1870

@ -32,6 +32,12 @@ __attribute__((objc_root_class))
@interface InitializesOneClassWhileBeingInitialized: NotInitializedSuperclass2 @end
@interface Subclass3: DefaultSuperclass @end
// test: transitioning an initialized class to an initialized superclass
// Test4Subclass only inherits access to "onlyExistsOnFinalSuperclass" from
// its new superclass's superclass (Test4FinalSuperclass)
@interface Test4Subclass: Root @end
@interface Test4FinalSuperclass: DefaultSuperclass @end
@implementation Root
+ (Class)class { return self; }
+ (BOOL)respondsToSelector:(SEL)selector {
@ -141,6 +147,13 @@ static BOOL _otherInitializedClassInitialized = NO;
@implementation Subclass3
@end
@implementation Test4Subclass
@end
@implementation Test4FinalSuperclass
+ (int)onlyExistsOnFinalSuperclassMeta { return 501; }
- (int)onlyExistsOnFinalSuperclass { return 500; }
@end
static int failures = 0;
#define expect(x) do \
@ -293,5 +306,28 @@ int main(int argc, char **argv) {
expect(13 == [Subclass3 overriddenMeta]);
}
/* Transitioning an initialized class to an initialized superclass. */
{
Class test4subclass = objc_getClass("Test4Subclass");
Class newSuperclass = objc_getClass("Test4FinalSuperclass");
// Make sure every class in the hierarchy is initialized.
[Test4Subclass class];
[Test4FinalSuperclass class];
expect(![test4subclass respondsToSelector:@selector(onlyExistsOnFinalSuperclassMeta)]);
expect(![test4subclass instancesRespondToSelector:@selector(onlyExistsOnFinalSuperclass)]);
class_setSuperclass(test4subclass, newSuperclass);
Test4Subclass *test4instance = class_createInstance(test4subclass, 0);
expect([test4subclass respondsToSelector:@selector(onlyExistsOnFinalSuperclassMeta)]);
expect([test4subclass instancesRespondToSelector:@selector(onlyExistsOnFinalSuperclass)]);
expect(501 == [(id)test4subclass onlyExistsOnFinalSuperclassMeta]);
expect(500 == [(id)test4instance onlyExistsOnFinalSuperclass]);
}
return failures;
}

@ -419,21 +419,24 @@ static void rebaseDtableRecursive(Class cls, Class newSuper)
dtable_t dtable = dtable_for_class(cls);
uint32_t idx = 0;
struct objc_method *method;
// Install all methods in the dtable with the correct ones.
while ((method = SparseArrayNext(temporaryDtable, &idx)))
// Install all methods from the parent that aren't overridden here.
while ((method = SparseArrayNext(parentDtable, &idx)))
{
SparseArrayInsert(dtable, idx, method);
if (SparseArrayLookup(temporaryDtable, idx) == NULL)
{
SparseArrayInsert(dtable, idx, method);
SparseArrayInsert(temporaryDtable, idx, method);
}
}
idx = 0;
// Now look at all of the methods in the dtable. If they're not ones from
// the dtable that we've just created, then they must come from the
// superclass, so replace them with whatever the superclass has (which may
// be NULL).
// the dtable that we've just created, then they must have come from the
// original superclass, so remove them by replacing them with NULL.
while ((method = SparseArrayNext(dtable, &idx)))
{
if (SparseArrayLookup(temporaryDtable, idx) == NULL)
{
SparseArrayInsert(dtable, idx, SparseArrayLookup(parentDtable, idx));
SparseArrayInsert(dtable, idx, NULL);
}
}
SparseArrayDestroy(temporaryDtable);

Loading…
Cancel
Save