[M3devel] layout of objects?

Tony Hosking hosking at cs.purdue.edu
Fri Mar 22 22:09:33 CET 2013


From the language spec:


There are two kinds of revelations, partial and complete. A program can contain any number of partial revelations for an opaque type; it must contain exactly one complete revelation.


Are you typing the method table as an array?
Why not simply index the array?

I don’t think there is any C type that natively captures the notion of opaque types.
The whole point is that you don’t know all the parent types.
But you do know that, given the offset of the opaque type’s methods in the method table, you can compute the offset of any given method.

For example:

TYPE T <: U;

Without seeing the revelation of T there is no way to know what methods are inherited from everything between T and U.
But, so long as at run time you are told the method offset of T’s methods in its method table then you can find any method defined in T at a known index from that offset.

On Mar 22, 2013, at 2:18 PM, Jay <jay.krell at cornell.edu> wrote:

> Can it have zero revelations?
> 
> 
> Can you assist lazy me and suggest an accurate way to describe opaque types in a typeful way in C? 
> 
> 
> Ultimate goal would be to get m3front & m3back optionally out of the business of computing offsets, instead using C structs and members and pointers and leave layout to the C compiler.
> Ultimately generating one architecture-independent, pointer-size-independent C.
> 
> 
>  I understand there are multiple challenges here and eventually m3cg and m3front will need changes, to pass down more higher level information.
> 
> 
>  - Jay
> 
> On Mar 22, 2013, at 11:11 AM, Tony Hosking <hosking at cs.purdue.edu> wrote:
> 
>> Every opaque type in a linkage must have only one revelation.
>> 
>> Sent from my iPad
>> 
>> On Mar 22, 2013, at 12:13 PM, Jay K <jay.krell at cornell.edu> wrote:
>> 
>>> Are opaque types always revealed eventually? Or only sometimes?
>>> I'd like to generate structs and member references and not be adding offsets to pointers.
>>> For method calls and record field references.
>>> And, ugh, the GC data needs to be generated using "offsetof". But probably all we get is a bunch
>>> of integers and no indication where the frontend got them from.. :(
>>> 
>>> 
>>> Thanks,
>>>  - Jay
>>> 
>>> 
>>> From: hosking at cs.purdue.edu
>>> Date: Fri, 22 Mar 2013 03:08:04 -0500
>>> To: jay.krell at cornell.edu
>>> CC: m3devel at elegosoft.com
>>> Subject: Re: [M3devel] layout of objects?
>>> 
>>> x>=0 means a known constant method offset at compile time.
>>> Otherwise, offset must be loaded at run time.  This is needed for opaque types, where the offset cannot be computed at run time.  Given TYPE T <: U we can't know at compile time how many methods are defined between U and T so the offset cannot be a compile time constant.
>>> 
>>> On Mar 22, 2013, at 2:01 AM, Jay K <jay.krell at cornell.edu> wrote:
>>> 
>>> Do you understand hereabouts m3front/src/exprs/MethodExpr.m3?
>>> 
>>> 
>>> PROCEDURE Compile (p: P) =
>>>   VAR
>>>     x := ObjectType.MethodOffset (p.holder);
>>>     method: Method.Info;
>>>   BEGIN
>>>     Type.Compile (p.object);
>>>     Method.SplitX (p.method, method);
>>> 
>>>     Type.LoadInfo (p.object, M3RT.OTC_defaultMethods, addr := TRUE);
>>>     IF (x >= 0) THEN
>>>       INC (method.offset, x);
>>>     ELSE (* runtime offset to methods *)
>>>       Type.LoadInfo (p.holder, M3RT.OTC_methodOffset);
>>>       CG.Index_bytes (Target.Byte);
>>>     END;
>>>     CG.Boost_alignment (Target.Address.align);
>>>     CG.Load_indirect (CG.Type.Addr, method.offset, Target.Address.size);
>>>     CG.Boost_alignment (Target.Address.align);
>>>   END Compile;
>>> 
>>> 
>>> "runtime offset to methods"?
>>> 
>>> ObjectType.MethodOffset:
>>> 
>>> PROCEDURE MethodOffset (t: Type.T): INTEGER =
>>>   VAR p := Confirm (t);
>>>   BEGIN
>>>     IF (p = NIL) THEN RETURN Unknown_w_magic END;
>>>     GetOffsets (p, use_magic := TRUE);
>>>     RETURN p.methodOffset;
>>>   END MethodOffset;
>>> 
>>> 
>>> PROCEDURE Confirm (t: Type.T): P =
>>>   VAR info: Type.Info;
>>>   BEGIN
>>>     LOOP
>>>       t := Type.CheckInfo (t, info);
>>>       IF (info.class = Type.Class.Object) THEN
>>>         RETURN t;
>>>       ELSIF (info.class = Type.Class.Opaque) THEN
>>>         t := Revelation.LookUp (t);
>>>       ELSE
>>>         RETURN NIL;
>>>       END;
>>>     END;
>>>   END Confirm;
>>> 
>>> 
>>> ...
>>> 
>>> 
>>> 
>>>  - Jay
>>> 
>>> 
>>> 
>>> 
>>> 
>>> Subject: Re: [M3devel] layout of objects?
>>> From: hosking at cs.purdue.edu
>>> Date: Fri, 22 Mar 2013 01:44:37 -0500
>>> CC: jay.krell at cornell.edu; m3devel at elegosoft.com
>>> To: dragisha at m3w.org
>>> 
>>> Not quite.  I just checked RTAllocator.m3 and it is pointer to methods at offset 0, followed by fields.
>>> Heap header is at -ADRSIZE(Header).
>>> The type information in RT0 is used to initialize the object instances.
>>> 
>>> On Mar 22, 2013, at 1:34 AM, Dragiša Durić <dragisha at m3w.org> wrote:
>>> 
>>> It's not m3front, it's RT0.
>>> 
>>> First data field is at offset 0, and pointer to type information is at -BYTESIZE(POINTER). Type information records are specified in RT0.
>>> 
>>> On Mar 22, 2013, at 5:56 AM, Jay K wrote:
>>> 
>>> layout of objects?
>>> 
>>> 
>>> 
>>> How are Modula-3 objects layed out?
>>> i.e. "OBJECT"/"METHODS"/"OVERRIDES"
>>> I skimmed m3front and it wasn't obvious.
>>> 
>>> 
>>> 
>>> A common way for C++ "objects" to be layed out,
>>> in the face of no RTTI and only single inheritance,
>>> and virtual functions, is that a pointer to a record
>>> of function pointers is first in the record.
>>> 
>>> 
>>> Like this:
>>> 
>>> 
>>> class Type
>>> {
>>> virtual void F1();
>>> virtual void F2();
>>> int data1;
>>> int data2;
>>> };
>>> 
>>> 
>>> ends up lik more this:
>>> 
>>> 
>>> struct TypeFunctions
>>> {
>>>  void (*F1)(Type*);
>>>  void (*F2)(Type*);
>>> };
>>> 
>>> 
>>> struct Type
>>> {
>>> TypeFunctions* Functions; /* always first,
>>> or at least a fixed offset, and located independent
>>> of the size of the data; could also be at "-1" or such */.
>>> int data1;
>>> int data2;
>>> };
>>> 
>>> 
>>> Type* x;
>>> x->F1();
>>> 
>>> 
>>> =>
>>> x->Functions->F1(x);
>>> 
>>> 
>>> Functions added in more derived types go at the end.
>>> Ditto for data.
>>> In the absence of multiple-inheritance and RTTI, it is simple and predictable.
>>> (RTTI makes only small modifications.)
>>> 
>>> 
>>> Looking through m3front, it wasn't at all obvious if it works this way.
>>> 
>>> 
>>> I would like to declare something in C (or possibly C++, but not likely),
>>> such that I might actually recognize the various low level operations
>>> and "uncompile" it back to a typeful/typesafe form, like the above C++
>>> to C transform.
>>> 
>>> 
>>> 
>>> I can't likely uncompile to C++ with virtual functions,
>>> because the actual layout in C++ is not guaranteed.
>>> 
>>> 
>>> 
>>> Granted, I am being lazy.
>>> I should/could compile some small samples.
>>> But I might not get the entire story that way.
>>> 
>>> 
>>> 
>>> Thanks,
>>> - Jay
>>> 
>>> 
>>> 
>>> 
>>> 
>>> Antony Hosking | Associate Professor | Computer Science | Purdue University
>>> 305 N. University Street | West Lafayette | IN 47907 | USA
>>> Mobile +1 765 427 5484
>>> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://m3lists.elegosoft.com/pipermail/m3devel/attachments/20130322/7a375e87/attachment-0002.html>


More information about the M3devel mailing list