Skip to content

Commit d74f3d0

Browse files
authored
Merge pull request #97 from rjmccall/member-pointers
[Editorial] Rewrite the section on member pointers
2 parents b359d28 + e484295 commit d74f3d0

File tree

1 file changed

+157
-23
lines changed

1 file changed

+157
-23
lines changed

abi.html

Lines changed: 157 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@ <h3><a href="#definitions"> 1.1 Definitions </a></h3>
151151
A function that runs the destructors for non-static data members of T and
152152
non-virtual direct base classes of T.
153153

154+
<p>
155+
<dt> <i>basic ABI properties</i> of a type T</dt>
156+
<dd>
157+
The basic representational properties of a type decided by the base C ABI,
158+
including its size, its alignment, its treatment by calling conventions,
159+
and the representation of pointers to it.
160+
154161
<p>
155162
<dt> <i>complete object destructor</i> of a class T</dt>
156163
<dd>
@@ -686,40 +693,167 @@ <h3><a href="#pod"> 2.2 POD Data Types </a></h3>
686693
<a name="member-pointers"></a>
687694
<h3><a href="#member-pointers"> 2.3 Member Pointers </a></h3>
688695

696+
<a name="data-member-pointers"></a>
697+
<h4><a href="#data-member-pointers"> 2.3.1 Data Member Pointers </a></h4>
698+
689699
<p>
690-
A pointer to data member is an offset from the base
691-
address of the class object containing it,
692-
represented as a <code>ptrdiff_t</code>.
693-
It has the size and alignment attributes of a <code>ptrdiff_t</code>.
694-
A NULL pointer is represented as -1.
700+
The basic ABI properties of data member pointer types are those
701+
of <code>ptrdiff_t</code>.
695702

696703
<p>
697-
A pointer to member function is a pair <ptr, adj> as follows:
704+
A data member pointer is represented as the data member's offset in bytes
705+
from the address point of an object of the base type, as a
706+
<code>ptrdiff_t</code>.
698707

699-
<dl>
700708
<p>
701-
<dt> <code>ptr</code>:
702-
<dd> For a non-virtual function, this field is a simple function pointer.
703-
(Under current base Itanium psABI conventions,
704-
that is a pointer to a GP/function address pair.)
705-
For a virtual function,
706-
it is 1 plus the virtual table offset (in bytes) of the function,
707-
represented as a <code>ptrdiff_t</code>.
708-
The value zero represents a NULL pointer,
709-
independent of the adjustment field value below.
709+
A null data member pointer is represented as an offset of <code>-1</code>.
710+
Unfortunately, it is possible to generate a data member pointer with an
711+
offset of <code>-1</code> using explicit derived-to-base conversions.
712+
If this is done, implementations following this ABI may misbehave.
713+
<span class="future-abi">Recommendation for new platforms: consider using
714+
a different representation for data member pointers, such as left-shifting
715+
the offset by one and using a non-zero low bit to indicate a non-null
716+
value.</span>
710717

711718
<p>
712-
<dt> <code>adj</code>:
713-
<dd> The required adjustment to <i>this</i>,
714-
represented as a <code>ptrdiff_t</code>.
715-
</dl>
719+
Note that by <code>[dcl.init]</code>, "zero initialization" of a data
720+
member pointer object stores a null pointer value into it. Under this
721+
representation, that value has a non-zero bit representation. On most
722+
modern platforms, data member pointers are the only type with this
723+
property.
724+
725+
<p>
726+
Base-to-derived and derived-to-base conversions of a non-null data member
727+
pointer can be performed by adding or subtracting (respectively) the static
728+
offset of the base within the derived class. The C++ standard does not
729+
permit base-to-derived and derived-to-base conversions of member pointers
730+
to cross a <code>virtual</code> base relationship, and so a static offset
731+
is always known.
732+
733+
<a name="member-function-pointers"></a>
734+
<h4><a href="#member-function-pointers"> 2.3.2 Member Function Pointers </a></h4>
735+
736+
<p>
737+
Several different representions of member function pointers are in use.
738+
The standard representation relies on several assumptions about the
739+
platform, such as that the low bit of a function pointer to a non-virtual
740+
member function is always zero. For platforms where this is not reasonable
741+
to guarantee, an alternate representation must be used. One such
742+
representation, used on the 32-bit ARM architecture, is also described here.
743+
744+
<p>
745+
In all representations, the basic ABI properties of member function
746+
pointer types are those of the following class, where <code>fnptr_t</code>
747+
is the appropriate function-pointer type for a member function of this type:
748+
749+
<pre>
750+
struct {
751+
fnptr_t ptr;
752+
ptrdiff_t adj;
753+
};
754+
</pre>
716755

717756
<p>
718-
It has the size, data size, and alignment
719-
of a class containing those two members, in that order.
720-
(For 64-bit Itanium, that will be 16, 16, and 8 bytes respectively.)
757+
A member function pointer for a non-virtual member function is represented
758+
with <code>ptr</code> set to a pointer to the function, using the base
759+
ABI's representation of function pointers.
721760

761+
<p>
762+
In the standard representation, a member function pointer for a virtual
763+
function is represented with <code>ptr</code> set to 1 plus the function's
764+
v-table entry offset (in bytes), converted to a function pointer as if by
765+
<code>reinterpret_cast&lt;fnptr_t&gt;(uintfnptr_t(1 + offset))</code>,
766+
where <code>uintfnptr_t</code> is an unsigned integer of the same
767+
size as <code>fnptr_t</code>.
768+
769+
<p>
770+
In both of these cases, <code>adj</code> stores the offset (in bytes)
771+
which must be added to the <code>this</code> pointer before the call.
722772

773+
<p>
774+
In the standard representation, a null member function pointer is
775+
represented with <code>ptr</code> set to a null pointer. The value
776+
of <code>adj</code> is unspecified for null member function pointers.
777+
778+
<p>
779+
The standard representation relies on some assumptions which are
780+
true for most platforms:
781+
782+
<ul compact>
783+
<li>The low bit of a function pointer to a non-static member function
784+
is never set. On most platforms, this is either always true or
785+
can be made true at little cost. For example, on platforms where
786+
a function pointer is just the address of the first instruction in the
787+
function, the implementation can ensure that this addresss is always
788+
sufficiently aligned to make the low bit zero for non-static member
789+
functions; often this is required by the underlying architecture.</li>
790+
791+
<li>A null function pointer can be distinguished from a virtual
792+
offset value. On most platforms, this is always true because the
793+
null function pointer is the zero value.</li>
794+
795+
<li>The offset to a v-table entry is never odd. On most platforms,
796+
the size of a v-table entry is even because the architecture is
797+
byte-addressed and pointers are even-sized.</li>
798+
799+
<li>A virtual call can be performed knowing only the addresss of a
800+
v-table entry and the type of the virtual function. On most
801+
platforms, a v-table entry is equivalent to a function pointer,
802+
and the type of that function pointer can be determined from the
803+
member pointer type.</li>
804+
</ul>
805+
806+
<p>
807+
However, there are exceptions. For example, on the 32-bit ARM
808+
architecture, the low bit of a function pointer determines whether
809+
the function begins in THUMB mode. Such platforms must use an
810+
alternate representation.
811+
812+
<p>
813+
In the 32-bit ARM representation, the <code>this</code>-adjustment
814+
stored in <code>adj</code> is left-shifted by one, and the low bit
815+
of <code>adj</code> indicates whether <code>ptr</code> is a function
816+
pointer (including null) or the offset of a v-table entry. A virtual
817+
member function pointer sets <code>ptr</code> to the v-table entry
818+
offset as if by
819+
<code>reinterpret_cast&lt;fnptr_t&gt;(uintfnptr_t(offset))</code>.
820+
A null member function pointer sets <code>ptr</code> to a null
821+
function pointer and must ensure that the low bit of <code>adj</code>
822+
is clear; the upper bits of <code>adj</code> remain unspecified.
823+
824+
<p>A member function pointer is null if <code>ptr</code> is equal
825+
to a null function pointer and (only when using the 32-bit ARM
826+
representation) the low bit of <code>adj</code> is clear.
827+
828+
<p>Two member function pointers are equal if they are both null or
829+
if their corresponding values of <code>ptr</code> and <code>adj</code>
830+
are equal. Note that the C++ standard does not require member pointers
831+
to the same virtual member function to compare equal; implementations
832+
using this ABI will do so, but only if the member pointers are built
833+
using the same v-table offset, which they may not be in the presence
834+
of multiple inheritance or overrides with covariant return types.
835+
836+
<p>
837+
Base-to-derived and derived-to-base conversions of a member function
838+
pointer can be performed by adding or subtracting (respectively) the
839+
static offset of the base within the derived class to the stored
840+
<code>this</code>-adjustment value. In the standard representation,
841+
this simply means adding it to <code>adj</code>; in the 32-bit ARM
842+
representation, the addend must be left-shifted by one. Because the
843+
adjustment does not factor into whether a member function pointer is
844+
null, this addition can be done unconditionally when performing a
845+
conversion.
846+
847+
<p>
848+
A call is performed as follows:
849+
850+
<ol>
851+
<li>Add the stored adjustment to the <code>this</code> address.</li>
852+
<li>If the member pointer stores a v-table entry offset, load the
853+
v-table from the adjusted <code>this</code> address and call
854+
the v-table entry at the stored offset.</li>
855+
<li>Otherwise, call the stored function pointer.</li>
856+
</ol>
723857

724858
<p> <hr> <p>
725859
<a name="class-types">

0 commit comments

Comments
 (0)