Skip to content

Test that newer libobjcs let the Swift runtime set up a class's layout #21942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 18, 2019

Conversation

jrose-apple
Copy link
Contributor

Specifically, when the class is referenced from Objective-C first, before being referenced from Swift in any way. This is important for resilience, since up until now Objective-C isn't used to the size of a class changing based on anything other than a superclass's size changing.

This is basically the test that would have gone with #19944 had there been a build of libobjc to test it with.

rdar://problem/45718008

@jrose-apple
Copy link
Contributor Author

Either of you see anything else worth testing while I'm here?

@jrose-apple jrose-apple force-pushed the layout-is-french-for-exit branch from 52fb1a4 to 8e1a60e Compare January 17, 2019 02:08
@jrose-apple
Copy link
Contributor Author

@swift-ci Please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 52fb1a4917228a0f6ee52cba61223c756236af5f

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 52fb1a4917228a0f6ee52cba61223c756236af5f

@objc var first: Int = 0
var forceUnalignment: Int8 = 0
var middle = GrowsToInt64()
@objc var last: Int = 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these (non-public) ivars @objc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the ones I'm testing the ivar offsets of. It doesn't really matter if they're public or not; Swift never exposes direct compile-time ivar access to Objective-C.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we not emit those records for non-@objc ivars too? I thought we had to so the objc runtime can slide them. In any case I'm fine with the @objc being here, just wondering if there was a specific reason

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we ever don't emit them for non-@objc ivars, I don't want the test to change. I think it's appropriate for something accessed through the ObjC runtime. (Besides, the non-@objc ivars aren't representable in Objective-C, and it feels weird to rely on them being there.)


size_t offsetOfLast = ivar_getOffset(class_getInstanceVariable(c, "last"));
NSLog(@"offset of 'last' %zd", offsetOfLast);
assert(offsetOfLast == actualSize - sizeof(intptr_t));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth creating an instance and checking anything there as well, maybe calling a Swift method too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't think of anything that wouldn't go through a Swift entry point except class_createInstance, and I think that's superfluous with checking the instance size.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the case I thought we could test is calling Swift code after Objective-C had already initialized the class metadata

Copy link
Contributor Author

@jrose-apple jrose-apple Jan 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we call static methods. Think an instance method is interesting enough to also be worth doing?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not.


size_t offsetOfFirst = ivar_getOffset(class_getInstanceVariable(c, "first"));
NSLog(@"offset of 'first' %zd", offsetOfFirst);
assert(offsetOfFirst == sizeof(Class) + (isPureSwift ? sizeof(void*) : 0));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this still hold on 32-bit? (I guess we'll find out)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is "non-pointer isa" or "isa + refcount". I checked on a 32-bit simulator.

}
}

public class DynamicClass: NSObject {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also test a subclass of an Objective-C class that is not NSObject (and has ivars)? We've had bugs with ivar layout in this case in the past.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, will add.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, if I do that I can give all three classes the same layout, which would be nice for maintenance purposes.

@slavapestov
Copy link
Contributor

This looks good. Thanks for doing this!

Copy link
Contributor

@mikeash mikeash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

#elseif BIG
var value: Int64
#else
#error("Must define OLD or NEW")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should say SMALL or BIG?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, thanks!

@jrose-apple jrose-apple force-pushed the layout-is-french-for-exit branch from 8e1a60e to 60e07aa Compare January 17, 2019 19:11
@jrose-apple
Copy link
Contributor Author

@swift-ci Please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 8e1a60ebfb7df6b9aa68f16cab22e9c40e155f11

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 8e1a60ebfb7df6b9aa68f16cab22e9c40e155f11

@jrose-apple
Copy link
Contributor Author

Looks like I got the 32-bit stuff wrong after my second version. Fortunately my 32-bit simulator is working now…!

Specifically, when the class is referenced from Objective-C first,
before being referenced from Swift in any way. This is important for
resilience, since up until now Objective-C isn't used to the size of a
class changing based on anything other than a superclass's size
changing.

This is basically the test that would have gone with 9024768 had
there been a build of libobjc to test it with.

rdar://problem/45718008
@jrose-apple jrose-apple force-pushed the layout-is-french-for-exit branch from 60e07aa to cd00a8c Compare January 17, 2019 22:57
@jrose-apple
Copy link
Contributor Author

@swift-ci Please test macOS

@jrose-apple
Copy link
Contributor Author

@swift-ci Please smoke test Linux

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 60e07aad973999d76b2e4fa936bbdea234a08cb1

@jrose-apple jrose-apple merged commit 7629253 into swiftlang:master Jan 18, 2019
@jrose-apple jrose-apple deleted the layout-is-french-for-exit branch January 18, 2019 01:39
jrose-apple added a commit to jrose-apple/swift that referenced this pull request Jan 18, 2019
swiftlang#21942)

Specifically, when the class is referenced from Objective-C first,
before being referenced from Swift in any way. This is important for
resilience, since up until now Objective-C isn't used to the size of a
class changing based on anything other than a superclass's size
changing.

This is basically the test that would have gone with 9024768 had
there been a build of libobjc to test it with.

rdar://problem/45718008
(cherry picked from commit 7629253)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants