[M3devel] Modula-3 object model details? more type improvements in m3cc/parse.c?

Rodney M. Bates rodney_bates at lcwb.coop
Sun Sep 5 21:03:50 CEST 2010



Jay K wrote:
> more type improvements in m3cc/parse.c?
> 
> 
> So, the initial goal of fixing SPARC64_SOLARIS
> without breaking anything seems to have worked.
>  I have to check all the platforms still.
> 
> 
> And debugging of records is much much better in gdb.
>   (again, needs testing..)
> 
> 
> Now I'd like to continue:
>  enums
>  packed
>  objects
>  function pointer types
>  arrays
>  open arrays
>  
>  
> This requires a fairly complete understanding of the "object model".
> Basically what Modula-3 looks like in C.
>   Yes, this dovetails into generating C.

Because of the much stronger type system, much of the code written will
not be dependent on this stuff, the exception being unsafe code.
So, the language specifies very little of it.

The below is what I understand about our compiler.  There may be some
target dependencies here.

> 
> 
> Stuff like:
>  Are enums always 32 bits?
>  Or are they chosen among 8, 16, 32 bits, as needed to fit their values?

    ^Yes.  Except when packed, see below.

There is nothing in the language that requires this, but the binary values
are equal to the ORD function.  It is hard to imagine a perverse enough machine
for which it would make sense for a compiler to do it any other way.  But
the type system of the language would allow some other encoding.  ORD and VAL
would then require runtime computation.

>  Or are they always integer sized but we limit them to 2^32 values?
>  

>  
> What can/does packed do?
> The language spec was deliberately vague.
> a) It can add arbitrary padding to the end of records?
> b) It removes any possible padding at end of records?
> c) It can shrink enums and subranges to other than 8/16/32/64 bits?
> d) It can grow enums/subranges?

1) BITS ... never changes the legal value set.  An implication is that if the number
    of bits given is too small for the value set, as the compiler has chosen to
    represent it, the compiler must give an error.
2) Packed types have no effect on target layout at all, except when the packed
    type is used for an array element or field of a record or object.  So a
    packed type in a VAR declaration, for example, accomplishes nothing.
    (Although it can make the static rules harder to satisfy.)
3) An element or field of packed type can have no padding added ahead of it.
4) An element or field of packed type must occupy exactly the given number of bits.

The compiler can either satisfy 3) and 4), or it can refuse, with an error message.
These are the only rules.  So the implications for your questions above (I added
letter designations to them) are:

The language makes no statement about a) and b)  The compiler can do what it likes
at the end of a record, regardless of whether it contains packed fields.  Packed
types constrain padding only before a packed field.

I suppose, if there were an inner record that was a packed field of an outer record,
and the compiler had previously laid out the inner record type with trailing padding,
and it considered that padding part of the inner record type, then it would then have
to require the BITS count to be enough to hold the entire inner record, including
its trailing padding.  I don't think our compilers ever add trailing padding to
anything.  Only leading padding ahead of non-packed fields/elements, when needed
for alignment or convenience.

It can do both c) and d) in order to satisfy 3) and/or 4), in fact it must, or else
emit an error message.


>  
>  
>  What do objects look like?
>  I assume they are something like C++ classes with single inheritance.
>  A vtable pointer followed by the data.
>  

There are two redundant mechanisms for finding the code body of a dispatching method.
Every traced heap object (M3 object or not) has a word at negative displacement that
is used by the allocator/GC, for TYPECASEing, etc.  You can see its layout in
RT0.RefHeader.

The biggest part of its contents is a subscript into a table of all the reference types.
This is field typecode of RefHeader.  This table is in the runtime
system, initialized partly by compiled code, partly at program startup.  It has one
pointer for every reference type in the complete program, counting all the separate
compilations.  The subscripts to this table are the TYPECODEs.

The pointers point to a record of runtime description of the type.  These records are
of type RT0.Typecell, extended by RT0.ObjectTypecell.  The latter has field
DefaultMethods, which points to the expected array of pointers to method code
bodies for each method of the object, with subscripts laid out statically, in order
of the method declarations.

But this was apparently judged too slow somewhere along the way, so each object
has, at displacement 0, a pointer leading directly to the table of method bodies.

Beyond that, it's just the fields of the object, just like a record.

BTW, reading this stuff in the RTS is a wonderful example of a seldom-mentioned
advantage of static typing.  It's all coded using unsafe techniques.  No doubt
this is necessary for bootstrapping.  But the pointers are often of type ADDRESS,
and figuring out what thing/things they can point to is much harder than if they
were typed.  Comments are called for.

> 
> What do arrays look like?
>  This was answered recently. Including it here for completeness.
>  I should commit what was said.
> 
>  
> What are the ramifications of the ability to do type switching at runtime?
> Maybe another field in objects?
> 

Not sure what you mean.  Do your mean ISTYPE, NARROW, TYPECASE, etc., which all
involve testing the allocated type of an object at runtime?  These use the
typecode/Typecell mechanism.

> 
> What do exceptions look like?
>  Just records?
>  
> 
> Just read m3front to learn all this?
> And look at generated code?
> I can, but I'm lazy.
> 
> 
> If anyone knows all this stuff off the top of their head,
> checking it into doc/notes/objectmodel.txt is roughly
> my preference.
> 
> 
> I will have to put together a bunch of small samples, that
> both RTIO.PrintWhatever their data, and step through in gdb
> and see if things match.
> 
> 
> How much, if any of this is subject to change?
> I suspect none of it.
> Sure, you are supposed to know it when you write Modula-3.
> But parse.c can/should, caveat about making the same decisions as m3front.
> 
> 
> Thanks,
>  - Jay 		 	   		  



More information about the M3devel mailing list