We preserve the current layout of expanded and composite object. However instead of doing copy and allocation of expanded when used as local or passed as argument in the GC heap, we do them on the stack
We generate for every expanded types a structure. For example if you have:
expanded class A feature i: INTEGER s: STRING b: expanded class B end expanded class B feature i: INTEGER end
For class A we generate the following structure:
struct ex_A { char data [sizeof_object_of_type_A_with_overhead]; }
We do the way we were doing it before. So the magic is in the RTAR macro which will go back to its parent. However we do not store the temporary address of the expanded attribute as a local controled by the GC. It is not needed. As we are guaranteed that no GC will be triggered while we access the attribute of the expanded attribute.
As a consequence we improve dramatically the access speed to attributes of expanded. In assembly language, we go from 4 instructions down to 2 and only one memory access to the top of the object in which the expanded attribute is located.
When you do:
a: A ... a.f (x)
struct ex_A a; f (a.data + OVERHEAD, x);
EIF_REFERENCE Current; f (Current + offsets_to_a, x);
When you have a local variable A which contains references, then we store it into the normal stack of local variable by doing something like:
struct ex_A object; EIF_REFERENCE a = object.data + OVERHEAD; RTLR(?, a);
Because `a' is expanded for the compiler, then it is not going to be moved, so `a' will always point the the start of the object in `object.data'.
struct ex_A object; EIF_REFRENCE local = object.data + OVERHEAD; EIF_REFERENCE obj; memcpy (obj + offset_to_expanded_attribute, local, sizeofobject);
struct ex_A object EIF_REFERENCE local = object.data + OVERHEAD; EIF_REFERENCE obj; memcpy (local, obj + offset_to_expanded_attribute, sizeofobject);
No need to make space for OVERHEAD in structure that do not have references in them. In which case everything works just fine except that we do not have a reference to the subobject, but the skeleton knows where to find the expanded.
Then every call on the expanded without an overhead must be either inlined or a new body must be generated to take into account the missing header.