<p dir="ltr">OK.<br>
On my way home I realized changing ComputeThisOffset should be much much more trivial than I've tried and now I agree the anticipated version of the code should be much more straightforward to understand.</p>
<div class="gmail_quote">26 июля 2013 г. 22:12 пользователь "John McCall" <<a href="mailto:rjmccall@gmail.com">rjmccall@gmail.com</a>> написал:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div style="word-wrap:break-word">On Jul 26, 2013, at 11:04 AM, Timur Iskhodzhanov <<a href="mailto:timurrrr@google.com" target="_blank">timurrrr@google.com</a>> wrote:<br><div><blockquote type="cite"><div style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">
2013/7/25 John McCall <<a href="mailto:rjmccall@gmail.com" target="_blank">rjmccall@gmail.com</a>>:<br><blockquote type="cite">On Jul 25, 2013, at 10:20 AM, Timur Iskhodzhanov <<a href="mailto:timurrrr@google.com" target="_blank">timurrrr@google.com</a>><br>
wrote:<br><br>2013/7/25 John McCall <<a href="mailto:rjmccall@gmail.com" target="_blank">rjmccall@gmail.com</a>>:<br><br>On Jul 22, 2013, at 6:11 AM, Timur Iskhodzhanov <<a href="mailto:timurrrr@google.com" target="_blank">timurrrr@google.com</a>> wrote:<br>
<br>+// The main differences are:<br>+//  1. Separate vftable and vbtable.<br>+//  2. Each non-primary base class that has new virtual methods gets its<br>+//     own vfptr and vftable, all the address points are zero.<br>
<br>This is not a difference.<br><br><br>As far as I understand, in Itanium ABI each subobject that adds new<br>virtual methods to its bases gets a new *address point* in the shared<br>vtable, but not a new vtable (at least no new sections are generated),<br>
which IS different from the Microsoft ABI.<br><br><br>I’m not sure what it means for a subobject to "add virtual methods to its<br>bases”.<br></blockquote><br>Rephrased to:<br>//  2. Each subobject with a vfptr gets its own vftable rather than an address<br>
//     point in a single vtable shared between all the subobjects.<br><br>Does this make sense now?<br></div></blockquote><div><br></div>Oh, yes, good point..  That fact that distinct vf-tables are allocated as</div><div>
separate symbols is an excellent thing to mention.</div><div><br></div><div><blockquote type="cite" dir="auto"><div style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">
<blockquote type="cite">In both ABIs, the algorithm for performing a virtual function call is to<br>adjust<br>the base pointer to a subobject which contains the method in its primary<br>v-table, load a function pointer from the v-table, and call it.<br>
<br>In your example, the difference is just that, under MSVC, B doesn’t have<br>an entry for f() in its vf-table.  (In fact, it doesn’t have a vf-table.)<br>So the<br>caller has to adjust to something that actually does have an entry for f(),<br>
namely A.<br><br>+  // See if this class expands a vftable of the base we look at, which is<br>either<br>+  // the one defined by the vfptr base path or the primary base.<br><br>Still not sure why you’re not just starting from the right base and then<br>
walking up the primary base chain.<br><br><br>That's not enough even in the simple case of "B: A".<br><br>The vfptr is in the A layout, so the "right base" is A.<br>If we don't go to the most derived class (B) from "the right base"<br>
(A), we forget to add the more derived class's own new methods (and<br>probably return-adjusting thunks).<br><br><br>My point is that you should just start recursing from B instead of this<br>weird<br>combination of walking the path and then falling back on climbing the<br>
primary base chain.<br><br>Finding B (the most-derived subobject that A is in the primary-base chain<br>of)<br>should be really easy — it’s just a depth-first search through the complete<br>object’s layout, stopping at the first thing with the same offset as A.<br>
</blockquote><br>Hm...<br><br>Let's consider<br>--------<br> struct A {<br>   virtual TYPE* f();<br> };<br> struct B {<br>   virtual TYPE* g();<br> };<br> struct C: A, B {  <something>  }<br>--------<br>We'll have two vfptrs: for A at offset 0 and for B at offset 4<br>
(assuming 32-bit arch).<br><br>Currently, for the B's vftable we'll do this:<br> enter AddMethods(C)<br>   enter AddMethods(B)<br>   allocate a vftable slot for B::g<br>   leave AddMethods(B)<br> update the B::g slot with this/return adjustment if C overrides it<br>
 leave AddMethods(C)<br>[this somewhat reflects how Itanium's VTableContext works]<br><br>Basically what you want is<br> enter AddMethods(B)<br> allocate a vftable slot for B::g,<br>   if we have a (final) overrider for g() in C,<br>
     calculate this/return adjustment right here*.<br> leave AddMethods(B)<br><br>Ok, so at the (*) stage we can probably find the FinalOverrider to<br>just write the adjustments immediately...<br>This implies rewriting ComputeThisOffset to just take the final<br>
overrider and return the this offset in a complete object.<br>There were a few minor complexities in rewriting it (e.g. API being<br>not convenient) that have overloaded my brain on Friday evening<br>though.<br><br>Do you think this is important for the first version? If so - I'll<br>
continue trying to do this next week.<br></div></blockquote><div><br></div>I think it’s worth it, thanks.</div><div><br></div><div>I’ll wait to review that unless there’s something intermediate about</div><div>the current patch you’d like me to check out.</div>
<div><br></div><div>John.</div></div></blockquote></div>