Tag v3-virtual-dispatch. Suite 143/143; fixpoint OK
(image 2,310,300 bytes).
VIRTUAL methods now dispatch dynamically: a base-class pointer
holding a derived object calls the derived method.
TYPE
CLASS Shape; VIRTUAL PROCEDURE Draw() : INTEGER; END Shape;
CLASS Circle (Shape); VIRTUAL PROCEDURE Draw() : INTEGER; END Circle;
...
VAR b : POINTER TO Shape; c : POINTER TO Circle;
BEGIN
NEW(c); b := c; (* subtype pointer assignment *)
ExitCode := b^.Draw() (* -> Circle.Draw, decided at run time *)
END
SymTab.BuildVTable): the parent's slots are inherited
first, and a same-named virtual method overrides in place; new
virtual methods append. Each method node records its slot
(vslot).VptrOffset): at offset 0 when the class has no
parent (or the parent already has one), otherwise right after the
parent's fields. Subclasses share the inherited slot, so a derived
object's vptr identifies its dynamic class.QbeGen.EmitVTables writes one
data $vt_<typeindex> = { l $Method_<uid>, … } per class; a method
declared but never implemented is l 0.DeclRec) and
NEW (InitHeap) both store $vt_<typeindex> in the vptr field.QbeGen.VirtCallBegin, reusing the existing indirect-call path).
The receiver is passed as the hidden first argument, as for any
method.POINTER TO Derived assigns to
POINTER TO Base when Derived inherits Base (SymTab.IsSubclass),
which is what makes a base pointer able to hold a derived object.t_virtual.mod (3): a Shape pointer holding a Circle then a
Square dispatches to each override.vt_<Shape> = { Draw_0 }, vt_<Circle> = { Draw_1 } (same slot,
overridden).VIRTUAL-with-static-only usage, and the
whole existing suite (143) still pass; fixpoint byte-identical.Add(a) rather
than obj.Add(a)); a class BEGIN … END init body; multiple
parents. VIRTUAL coupled with VAR/value formals is covered by
the ordinary method path.compiler/src/SymTab.def/.mod (vtBase/nVirt/vtName/vtUid/
tvptr, BuildVTable, HasVTable, VirtSlot, VptrOffset,
VtCount/VtName/VtUid/VtHasBody, VtClassCount/VtClassAt,
IsSubclass), compiler/src/QbeGen.def/.mod (VtRef,
EmitVTables, VirtCallBegin, vptr init in DeclRec/InitHeap),
compiler/src/M2.atg (ArgList virtual dispatch),
compiler/tests/t_virtual.mod, compiler/run_tests.sh,
docs/features.md, docs/OOP.txt.