<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">On Jul 29, 2013, at 3:43 AM, Timur Iskhodzhanov <<a href="mailto:timurrrr@google.com">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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">2013/7/26 John McCall <<a href="mailto:rjmccall@gmail.com">rjmccall@gmail.com</a>>:<br><blockquote type="cite"><br>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><br><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><br><br>I think it’s worth it, thanks.<br><br>I’ll wait to review that unless there’s something intermediate about<br>the current patch you’d like me to check out.<br></blockquote><br>Nope, it didn't work well.<br>It turns out we should actually append slots to the vftable of a<br>non-primary subobject if we have a covariant-return override. As a<br>result, we have to visit the more-derived classes after we enumerate<br>all the methods of the primary sub objects.<br></div></blockquote><div><br></div>That’s really interesting!  Also I feel like that cannot possibly work in the</div><div>presence of virtual inheritance.  What does MSVC do if you have:</div><div><br></div><div>struct C0 { int x; };</div><div>struct C1 : C0 { virtual void f(); int y; }; // converting C0* to C1* is non-trivial</div><div><br></div><div>struct A {</div><div>  virtual C0 *foo();</div><div>  virtual C0 *bar();</div><div>};</div><div><br></div><div>struct B : virtual A {</div><div>  virtual C1 *foo(); // added to the A subobject’s vf-table?</div><div>};</div><div><div>struct C : virtual A {</div><div>  virtual C1 *bar(); // added to the A subobject’s vf-table?</div><div>};</div><div><br></div><div>strruct D : B, C {} // What’s at the end of the A subobject’s vf-table?</div><div><br></div><div>John.</div></div></body></html>