<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></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 Feb 4, 2017, at 2:35 AM, Andrew Trick via swift-dev &lt;<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" 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 Feb 3, 2017, at 9:37 PM, John McCall &lt;<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>&gt; wrote:</div><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=""><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=""><blockquote type="cite" class=""><div class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">IV. The function that performs the lookup:</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">&nbsp;IV1) is parameterized by an isa</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">&nbsp;IV2) is not parameterized by an isa</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">IV1 allows the same function to be used for super-dispatch but requires extra work to be inlined at the call site (possibly requiring a chain of resolution function calls).</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div class=""><br class=""></div><div class="">In my first message I was trying to accomplish IV1. But IV2 is simpler</div><div class="">and I can't see a fundamental advantage to IV1.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Well, you can use IV1 to implement super dispatch (+ sibling dispatch, if we add it)</div><div class="">by passing in the isa of either the superclass or the current class. &nbsp;IV2 means</div><div class="">that the dispatch function is always based on the isa from the object, so those</div><div class="">dispatch schemes need something else to implement them.</div><br class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""> Why would it need a lookup chain?</div></div></div></blockquote><div class=""><br class=""></div>Code size, because you might not want to inline the isa load at every call site.</div><div class="">So, for a normal dispatch, you'd have an IV2 function (defined client-side?)</div><div class="">that just loads the isa and calls the IV1 function (defined by the class).</div></div></div></blockquote><div class=""><br class=""></div><div class="">Right. Looks like I wrote the opposite of what I meant. The important thing to me is that the vtable offset load + check is issued in parallel with the isa load. I was originally pushing IV2 for this reason, but now think that optimization could be entirely lazy via a client-side cache.</div></div></div></div></blockquote><div><br class=""></div><div>Is this client-side cache per-image or per-callsite?&nbsp;</div><div><br class=""></div><div><br class=""></div><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=""><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="">So we'd almost certainly want a client-side resolver function that handled</div><div class="">the normal case. &nbsp;Is that what you mean when you say II1+II2? &nbsp;So the local</div><div class="">resolver would be I2; II1; III2; IV2; V1, which leaves us with a three-instruction</div><div class="">call sequence, which I think is equivalent to Objective-C, and that function</div><div class="">would do this sequence:</div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">define @local_resolveMethodAddress(%object, %method_index)</font></div><div class=""><font face="Menlo" class="">&nbsp;&nbsp;%raw_isa = load %object &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 1 instruction</font></div><div class=""><font face="Menlo" class="">&nbsp; %isa_mask = load @swift_isaMask &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 3: 2 to materialize address from GOT (not necessarily with ±1MB), 1 to load from it</font></div><div class=""><font face="Menlo" class="">&nbsp; %isa = and %raw_isa, %isa_mask &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 1</font></div><div class=""><font face="Menlo" class="">&nbsp; %cache_table = @local.A.cache_table &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 2: not necessarily within ±1MB</font></div><div class=""><font face="Menlo" class="">&nbsp; %cache = add %cache_table, %method_index * 8 &nbsp; // 1</font></div><div class=""><font face="Menlo" class="">&nbsp; tailcall @A.resolveMethod</font><span style="font-family: Menlo;" class="">(%isa, %method_index, %cache)</span><span style="font-family: Menlo;" class="">&nbsp;&nbsp;// 1</span></div><div class=""><br class=""></div><div class="">John.</div></div></div></blockquote><br class=""></div><div class="">Yes, exactly, except we haven’t even done any client-side vtable optimization yet.</div><div class=""><br class=""></div><div class="">To me the point of the local cache is to avoid calling @A.resolveMethod in the common case. So we need another load-compare-and-branch, which makes the local helper 12-13 instructions. Then you have the vtable load itself, so that’s 13-14 instructions. You would be saving on dynamic instructions but paying with 4 extra static instructions per class.</div><div class=""><br class=""></div><div class="">It would be lame if we can't force&nbsp;<span style="font-family: Menlo;" class="">@local.A.cache_table to be&nbsp;</span><span style="font-family: Menlo;" class="">±1MB relative to the helper.</span></div></div></div></blockquote><div><br class=""></div>You should assume that code and data are far apart from each other. The linker will optimize two-instruction far loads to a nop and a near load if they are in fact close together, but in full-size apps that is uncommon and in the dyld shared cache it never happens. (The shared cache deliberately separates all code from all data in order to save VM map entries.)</div><div><br class=""></div><div><br class=""></div><div>--&nbsp;</div><div>Greg Parker &nbsp; &nbsp; <a href="mailto:gparker@apple.com" class="">gparker@apple.com</a> &nbsp; &nbsp; Runtime Wrangler</div><div><br class=""></div><div><br class=""></div></body></html>