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
[SR-13438] Many uses of existentials should optimize much better. #55879
Comments
Moreover, even the hacks are incredibly sensitive to the shape of code. For example, just replacing the private func pointer<T>(toStored: T.Type) -> UnsafeMutablePointer<T> {
withUnsafePointer(to: storage) { Handle<T>($0) }.pointer // "storage" was "self"
} Produces much worse code for /// Returns a pointer to the `T` which is assumed to be stored in `self`.
private func pointer<T>(toStored: T.Type) -> UnsafeMutablePointer<T> {
typealias Box = (metadata: UnsafeRawPointer, refCounts: Int, value: T)
typealias BoxPointer = UnsafeMutablePointer<Box>
typealias BoxedLayout = (boxAddress: BoxPointer, Int, Int, storedType: Any.Type)
let address = withUnsafePointer(to: storage) { UnsafeMutableRawPointer(mutating: $0) }
if MemoryLayout<(T, Any.Type)>.size <= MemoryLayout<Any>.size
&& MemoryLayout<T>.alignment <= MemoryLayout<Any>.alignment {
return address.assumingMemoryBound(to: T.self)
}
else {
return withUnsafeMutablePointer(
to: &address.assumingMemoryBound(to: BoxedLayout.self)[0].boxAddress[0].value
) { $0 }
}
} |
@swift-ci create |
Can't remember whether the sync system handles edits to existing comments, so moving my edit here. Sorry for the radar noise. as does eliminating /// Returns a pointer to the `T` which is assumed to be stored in `self`.
private func pointer<T>(toStored: T.Type) -> UnsafeMutablePointer<T> {
typealias Box = (metadata: UnsafeRawPointer, refCounts: Int, value: T)
typealias BoxPointer = UnsafeMutablePointer<Box>
typealias BoxedLayout = (boxAddress: BoxPointer, Int, Int, storedType: Any.Type)
let address = withUnsafePointer(to: storage) { UnsafeMutableRawPointer(mutating: $0) }
if MemoryLayout<(T, Any.Type)>.size <= MemoryLayout<Any>.size
&& MemoryLayout<T>.alignment <= MemoryLayout<Any>.alignment {
return address.assumingMemoryBound(to: T.self)
}
else {
return withUnsafeMutablePointer(
to: &address.assumingMemoryBound(to: BoxedLayout.self)[0].boxAddress[0].value
) { $0 }
}
} |
Unfortunately, `Any is Int` cannot be simplified quite this far. In particular, `Any` might contain:
None of these would be handled correctly by simply comparing the metatype reference from the `Any` to see if it matched `Int.self`. While we can't reduce this quite as far as you're suggesting, we could certainly improve cases like this:
|
Additional Detail from JIRA
md5: 19fe883fffc5d9d7a6619f88d2dbb8a1
Issue Description:
Take for example:
which generates the following x86:
It should simply be checking the type metadata pointer in the any to see if it matches `Int`'s.
Another example:
which generates:
but should actually unsafely pull the `Int` from the Any's inline storage.
I've created this gist, which crawls around in Any's storage layout to avoid these overheads, but such hackery should be unnecessary for the majority of cases.
I realize that even after these performance issues are addressed, we'll still need my hackery to enable efficient in-place mutation; features to enable that to be expressed cleanly in the language are topics for a different bug report.
/cc @eeckstein
The text was updated successfully, but these errors were encountered: