<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Oct 10, 2016, at 8:05 PM, Chris Lattner <<a href="mailto:clattner@apple.com" class="">clattner@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=us-ascii" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Oct 7, 2016, at 2:38 PM, Michael Gottesman via swift-dev <<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=us-ascii" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Attached below is an updated version of the proposal. Again a rendered version is located at:</div><div class=""><br class=""></div><div class=""><a href="https://gottesmm.github.io/proposals/high-level-arc-memory-operations.html" class="">https://gottesmm.github.io/proposals/high-level-arc-memory-operations.html</a></div><div class=""><br class=""></div><div class="">Michael</div></div></div></blockquote><br class=""></div><div class="">This looks great Michael, a couple of comments/questions:</div><div class=""><br class=""></div><div class="">typo: affects -> effects.</div><div class=""><br class=""></div><div class=""><br class=""></div>><span style="font-family: -webkit-standard;" class="">If ARC Code Motion wishes to move the ARC semantics of ownership qualified</span><span style="font-family: -webkit-standard;" class=""> </span><code class="highlighter-rouge">load</code><span style="font-family: -webkit-standard;" class="">,</span><span style="font-family: -webkit-standard;" class=""> </span><code class="highlighter-rouge">store</code><span style="font-family: -webkit-standard;" class=""> </span><span style="font-family: -webkit-standard;" class="">instructions, it must now consider read/write effects. On the other hand, it will be able to now not consider the side-effects of destructors when moving retain/release operations.</span><div class=""><div class=""><br class=""></div><div class="">Can you elaborate on what you mean by this? Does this mean the ARC optimizer has additional freedom somehow to ignore side effects in deinits? What grants that ability?</div></div></div></div></blockquote><div><br class=""></div><div>Sorry for not being clear.</div><div><br class=""></div><div>deinits in ARC are not sequenced with respect to memory operations in normal control flow, but if ARC performs any code motion, we must ensure that memory safety is respected. Such semantics are not new.</div><div><br class=""></div><div>The main change here is that previously there were situations where we would split up the load/retain in a load [copy] operation. Then if the right things occured, we could cause the object to be deallocated before we use the value or took full ownership of the value.</div><div><br class=""></div><div>Consider the following example:</div><div><br class=""></div><div>----</div><div>class D {}</div><div>class D1 : D {}</div><div>class D2 : D {}</div><div><br class=""></div><div>var GLOBAL_D : D = D1()</div><div><br class=""></div><div>class C { deinit { GLOBAL_D = D2 } }</div><div><br class=""></div><div>func main() {</div><div> let c = C()</div><div> let d = GLOBAL_D</div><div> useC(c)</div><div> useD(d)</div><div>}</div><div><br class=""></div><div>main()</div><div>----</div><div><br class=""></div><div>Assume that useC does not directly in any way touch an instance of class D except via the destructor .</div><div><br class=""></div><div>Since memory operations are not sequenced with respect to deinits, there are two correct programs here that the optimizer can produce: the original and the one where useC(c) and GLOBAL_D are swapped, i.e.:</div><div><br class=""></div><div>----</div><div><div>func main() {</div><div> let c = C()</div><div> useC(c)</div><div> let d = GLOBAL_D</div><div> useD(d)</div><div>}</div></div><div>----</div><div><br class=""></div><div>In the first program, d would be an instance of class D1. In the second, it would be an instance of class D2. Notice how in both programs though, no deinitialized object is accessed. On the other hand, imagine if we had split main like so:</div><div><br class=""></div><div>----</div><div><div>func main() {</div><div> let c = C()</div><div> let d = unsafe_unowned_load(GLOBAL_D)</div><div> useC(c)</div><div> let owned_d = retain(d)</div><div> useD(owned_d)</div><div>}</div></div><div>----</div><div><br class=""></div><div>In this case, we would be passing off to useD a deallocated instance of class D1 which would be undefined behavior.</div><div><br class=""></div><div>So as long as for these load [copy] operations, we move the load/retain fused together, we can guarantee that an object is produced instantaneously in a safe way without any worry.</div><div><br class=""></div><div>Was this helpful?</div><div>Michael</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""></div><div class="">-Chris</div></div></div></blockquote></div><br class=""></body></html>