-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Annotate Foundation overlay with __shared/__owned #19143
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
Annotate Foundation overlay with __shared/__owned #19143
Conversation
@swift-ci Please test macOS |
@swift-ci Please smoke test Linux |
@eeckstein As far as I'm aware, our actual
Is my understanding here correct? |
Sorry, why is this specific to reference types? cc @airspeedswift |
@jrose-apple Sorry, have I missed something here? Is this not inherently related to values which require reference counting? |
"Values which require reference counting" isn't quite the same as "reference types". String and Array and Data all require reference counting too, right? |
Ah, therein lies my misunderstanding about what was necessary here. I'll re-audit for those types as well. |
Closing for now. |
Build failed |
Made another pass here to add annotations to cover other non-trivial types. Will be doing another pass to confirm there's nothing I missed. |
@swift-ci Please test macOS |
@swift-ci Please smoke test Linux |
Build failed |
@jrose-apple @eeckstein Do the changes here look correct? Does anything stand out as being out of place? |
@@ -156,7 +156,7 @@ public struct IndexPath : ReferenceConvertible, Equatable, Hashable, MutableColl | |||
} | |||
} | |||
|
|||
mutating func append(contentsOf other: [Int]) { | |||
mutating func append(contentsOf other: __owned [Int]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this probably isn't necessary since it's just [Int]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, Array of Int is not a trivial type, i.e. involves reference counting of the array buffer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but IndexPath doesn't gain anything by taking the array owned, since it's not going to be able to use that buffer for storage, and the type isn't generic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, assuming that the case where self is empty and size of other > 2 is not the common case, it's better to pass other as guaranteed.
(I misread airspeedswift's comment: I though he meant that it's not worth annotating because of the parameter type).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain what the principles are for what is and isn't annotated? Since you're explicitly writing both __shared
and __owned
, I'd expect it to be
- every (non-trivial) parameter
- of all
public
/@usableFromInline
functions and initializers
and perhaps some of the non-public stuff as optimization hints. But I see public
functions where that hasn't been done, such as https://github.com/apple/swift/blob/9f042bc7c3452307b7929f5b76db5261b623d79a/stdlib/public/SDK/Foundation/Calendar.swift#L507.
@@ -106,7 +106,7 @@ public struct Calendar : Hashable, Equatable, ReferenceConvertible, _MutableBoxi | |||
// MARK: - | |||
// MARK: Bridging | |||
|
|||
fileprivate init(reference : NSCalendar) { | |||
fileprivate init(reference : __shared NSCalendar) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one should be owned
, no? Since you're immediately going to store it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although it's not a public entry point anyway, so it doesn't really matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_MutableHandle
makes a copy of the reference given to it so we never store the original — I've propagated __shared
out to every init(reference:)
which uses this, per @eeckstein's recommendation.
@@ -961,7 +961,7 @@ fileprivate class _JSONReferencingEncoder : _JSONEncoder { | |||
|
|||
/// Initializes `self` by referencing the given dictionary container in the given encoder. | |||
fileprivate init(referencing encoder: _JSONEncoder, | |||
key: CodingKey, convertedKey: CodingKey, wrapping dictionary: NSMutableDictionary) { | |||
key: CodingKey, convertedKey: __shared CodingKey, wrapping dictionary: NSMutableDictionary) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why only the one parameter changed here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This parameter is not stored; all others are. Based on your comments, it sounds to me like I've misunderstood something critical here. Let me start an email thread so we can sort this out.
@@ -156,7 +156,7 @@ public struct IndexPath : ReferenceConvertible, Equatable, Hashable, MutableColl | |||
} | |||
} | |||
|
|||
mutating func append(contentsOf other: [Int]) { | |||
mutating func append(contentsOf other: __owned [Int]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but IndexPath doesn't gain anything by taking the array owned, since it's not going to be able to use that buffer for storage, and the type isn't generic.
@@ -1178,7 +1178,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl | |||
/// - parameter url: The `URL` to read. | |||
/// - parameter options: Options for the read operation. Default value is `[]`. | |||
/// - throws: An error in the Cocoa domain, if `url` cannot be read. | |||
public init(contentsOf url: URL, options: Data.ReadingOptions = []) throws { | |||
public init(contentsOf url: __shared URL, options: __shared Data.ReadingOptions = []) throws { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Data.ReadingOptions is an ObjC enum, right? So it shouldn't matter what ownership you use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure — some of the changes here were mechanical, so I can pull this one out. I'm surprised the compiler didn't produce a warning/error in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We haven't really talked about what form that'll take yet, but yeah, that's a reasonable idea. (You wouldn't necessarily want to do it to everything that's trivial, because a new version of the library might make it non-trivial, but that's not going to happen to an @objc
enum.)
@jrose-apple Sure — based on the guidelines I was given, I went ahead and annotated every function parameter which deviated from the default rules that I understand are in place ( If it would be more helpful (or even necessary) to annotate all parameters regardless of the default, then I'm willing to go through and do that. Similarly, if I've misunderstood the guidelines (see rdar://problem/34989766 for discussion between between me and @eeckstein), happy to be corrected. |
No, that's not necessary |
I feel silly now. I didn't realize you were just annotating divergences from the default. Sorry for jumping in! |
@swift-ci Please test macOS |
@swift-ci Please smoke test Linux |
Build failed |
Latest commit removes the unnecessary |
@jrose-apple No worries at all, BTW — thanks for taking the time to review! Thanks @eeckstein for the help, too. |
What's in this pull request?
Annotates portions of the Foundation overlay with the appropriate
__shared
/__owned
annotations following the patterns we use (resolving rdar://problem/34989766). I looked at every declaredfunc
andinit
within our overlay and annotated all methods as appropriate. ~~~A search of all storedvar
s shows no necessary changes AFAICT as we don't expose reference types from our Swift APIs.~~~ (Sincevar
types cannot be annotated for ownership, there's nothing for us to do in the cases wherevar
s should be__shared
.)Overall the changes mostly revolve around bridging:
copy()
the passedNS
type before holding onto it as a reference to preserve value semantics, and in those cases, the parameter should be__shared
as we don't hold on to the original. (AFAIK,copy()
should help enforce the right refcounting in the case wherecopy()
returnsself
.)NS
type out of the Swift type via bridging (which copies as well) and hold on to theNS
typeThere are a few cases where
init
parameters go unused (such as inString.init?(contentsOf:)
), and some cases aroundKeyPath
where we appear to not store the givenKeyPath
but it actually ends up stored in a global table.