Efficient C implementation of expanded (Draft 2)

General Idea

Instead of having expanded objects within normal objects, we decide to flatten the hierarchy of attributes. This has the following advantage of removing almost all knowledge about expanded types in the C generated code. It means that we can get rid of the EO_COMP and EO_EXP flags as they become useless.

Structure

Expanded structure

We generate for every expanded types three structures. 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 two structures:

struct ex_A {
	EIF_TYPE_ID type_id;	// Optional field. Only inserted
				// when there are a references
	EIF_REFERENCE s;
	EIF_INTEGER i;
	EIF_INTEGER b_i;
}
struct ex_A_for_call {
	EIF_TYPE_ID type_id;	// Optional field. Only inserted
				// when there are a references
	EIF_REFERENCE *s;
	EIF_INTEGER *i;
	EIF_INTEGER *b_i;
}

The first structure `ex_A' describes object content. It is used when A is used as as locals, Result or arguments of type A. The first field `type_id' is optional. It is only used when the expanded type contains a reference to other object. So when it is a local, then the GC is not smart enough to find out which expanded we are storing, therefore the added `type_id' to help the GC to mark the structure.

The last structure is used when doing a call on an expanded target. Because the expanded is either part of a normal object or a local/Result/argument (which have different layout), we have a common layout used only for calls. It might not be efficient but calls being quite rare it should not be too damaging. Keep in mind that we are trying to improve the access speed of attribute.

Composite structure

For a composite object, we flatten completely the object and at the end we have no notion of sub-object. This makes the GC implementation much easier as it only needs to know about local expanded with only a special marking, otherwise nothing needs to be done.

Updating a reference from an expanded object

Let's say we have in expanded class A (above) the following code:

set_s (a_s: like s) is
	do
		s := a_s
	end

And somewhere we have:

a: A
a.set_s ("Fdsfds")

Here is what would be generated:

set_s (EIF_REFERENCE parent, struct ex_A_for_call * Current, EIF_REFERENCE a_s) {
	*(Current->s) = a_s;
	RTAR(parent, a_s);
} 

As you notice we generate an extra argument compared to the usual case. This is the reference to the object, if any. that contains Current. When `Current' is actually a local variable, then it is NULL, otherwise it is a reference to the parent object.

Note:
We could also generate a second variant for `set_s' which signature is only:
    set_s (struct ex_A *Current, EIF_REFERENCE a_s)
to be used with calls of local/arguments/expanded which will be more efficient. But for simplification we will not do it yet.

Calling feature on expanded object

When you do:

a: A
...
a.f (x)

If a is a local

struct Tex_A a;
struct ex_A_for_call a_call;

a_call.attrib_1 = &(a.item.attrib_1)
...
a_call.attrib_n = &(a.item.attrib_n)
f(NULL, &a_call, x);

If a is an attribute

EIF_REFERENCE Current;
struct ex_A_for_call a_call;

a_call.attrib_1 = Current + offsets (Current, attrib_1)
...
a_call.attrib_n = Current + offsets (Current, attrib_n)
f(Current, &a_call, x);

Note:
When `a' is an attribute of an object X, we pass X as first argument of `f'.

Note:
When an expanded as no attribute, then we do not pass anything.

Assigning expanded attributes or locals

From a local to an attribute

struct ex_A a;
EIF_REFERENCE obj;

*(XX *) (obj + offset_to_attrib_1) = a.attrib_1
...
*(XX *) (obj + offset_to_attrib_n) = a.attrib_n

From an attribute to a local

struct ex_A a;
EIF_REFERENCE obj;

a.type_id = YYY;	// If necessary
a.attrib_n = *(XX *) (obj + offset_to_attrib_1)
...
a.attrib_n = *(XX *) (obj + offset_to_attrib_n)