class A { a: Int <- 0; d: Int <- 1; f(): Int { a <- a + d }; }; class B inherits A { b: Int <- 2; f(): Int { a }; g(): Int { a <- a - b }; }; class C inherits A { c: Int <- 3; h(): Int { a <- a*c }; };
For A methods to work correctly in A, B and C objects, attribute a
must be in the same "place" in each object.
this
points to the start offset of the object, and a
is at offset 10 in all objects of type A, B, C
this
and the fields are the object's attributes
Example layout
Offset Information stored 0 Class tag 4 Object size 8 Dispatch ptr 12 Attribute 1 16 Attribute 2 ...
Observation: Given a layout for class A
, a layout for subclass B
can be defined by extending the layout of A
with additional slots for the additional attributes of B
.
Leaves the layout of A
unchanged (B
is an extension).
Looking at our example:
Class A: {0: Atag, 4: 5, 8: *, 12: a, 16: d} Class B: {0: Btag, 4: 6, 8: *, 12: a, 16: d, 20: b} Class C: {0: Ctag, 4: 6, 8: *, 12: a, 16: d, 20: c}
The offset of an attribute is the same in a class and all of its subclasses
Consider layout for An < ... A3 < A2 < A1
Header |A1 object | | A1 attrs | |A2 object | A2 attrs | |A3 object A3 attrs | ... An attrs
e.g()
e.f()
e
is type A: invoke A's f
e
is type B: invoke B's f
e
is type C: invoke A's f
Every class has a fixed set of methods
A dispatch table indexes these methods
f
lives at a fixed offset in the dispatch table for a class and all of its subclasses
Dispatch table layout
Class A: {0: fA} Class B: {0: fB, 4: g} class C: {0: fA, 4: h}
A
contains only one method
B
and C
extend the table for A
to the right
f
is not the same in every class, but is always at the same offset
The dispatch pointer in an object of class X
points to the dispatch table for class X
. Every method f
of class X
is assigned an offset Of
in the dispatch table at compile time
To implement a dynamic dispatch e.f()
, we
e
, giving an object x
D
is the dispatch table for x
this
is bound to x
C
is a subclass of two independent classes A
and B
simultaneously (C
inherits from both A
and B
), then:
this
points to C's header and the object layout
this
to A's this
(by adding an offset to reach A's header), and then using the code generation for A.
this
to B's this
(by adding an offset to reach B's header), and then using the code generation for B.
C
overrides a method of A
, we appropriately modify A
's dispatch table.
C
overrides a method of B
, we appropriately modify B
's dispatch table.
C
is expected, if it is an overriding method, then index into the appropriate class (e.g., A or B)