Created
June 13, 2018 17:27
-
-
Save gottesmm/524fca6a4e9fb3d5736a1b9d6686c5e8 to your computer and use it in GitHub Desktop.
Guaranteed vs Owned
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// # Why +0 is a better default than +1 for "normal function arguments". | |
// | |
// My intention here is to show why +0 is better default in a resilient | |
// word. Keep in mind that inside individual modules and with inlinable | |
// declarations, the optimizer can change conventions at will so from a defaults | |
// perspective, these are not interesting. The interesting case is calling | |
// non-inlinable functions in other modules. | |
// | |
// Consider a situation where I have a class Klass and a function foo that calls | |
// a function bar in a different module. | |
class Klass {} | |
func foo(_ k: Klass) { | |
bar(k) | |
bar(k) | |
bar(k) | |
} | |
// Bar is in a different module and it is not inlinable so we can't inline or | |
// analyze its body. It is completely opaque beyond its declaration. | |
func bar(_ k: Klass) { | |
// ... | |
} | |
//------------------------------------------------------------------------------ | |
// Using "pseudo-swift" this lowers to the following retain traffic at +1. | |
class Klass {} | |
// k comes in at +1. | |
func foo(_ k: Klass) { | |
// retain(k) | |
bar(k) // release inside bar | |
// retain(k) | |
bar(k) // release inside bar | |
// retain(k) | |
bar(k) // release inisde bar. | |
// release(k) | |
} | |
// Again bar is in a different module, so we can't see its body. Even so, | |
// convention wise we know that there must be a release at the end. | |
func bar(_ k: Klass) { | |
// ... | |
// release(k) | |
} | |
// Since we can not analyze or inline bar, we can not eliminate the releases | |
// in bar. We /could/ coalesce the retains into one large add to the refcount, | |
// but the releases are not able to be optimized, resulting in slower code. | |
//------------------------------------------------------------------------------ | |
// Now let us consider the +0 world. In that case, we have the following | |
// pseudo-swift. | |
class Klass {} | |
// k comes in at +0. | |
func foo(_ k: Klass) { | |
// retain(k) | |
bar(k) | |
// release(k) | |
// retain(k) | |
bar(k) | |
// release(k) | |
// retain(k) | |
bar(k) | |
// release(k) | |
} | |
func bar(_ k: Klass) { | |
// ... | |
} | |
// Notice how since the retains/releases are all in the caller, the optimizer | |
// can eliminate /all/ the retain/release traffic and we can actually achieve optimal | |
// code without ref counts. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment