[M3devel] returning record by value vs. by ref?

Tony Hosking hosking at cs.purdue.edu
Sat Dec 1 17:03:44 CET 2007


I am assuming 's' here is an open array (REF ARRAY OF item) in which  
case it is allocated in the GC'd heap.  There is certainly no way of  
safely getting an interior pointer to items in the stack in Modula-3  
-- at least not one that you can upward expose (to callers) via  
return from a procedure.  The difficulty in doing this is that the GC  
moves objects around and would need to know where your manufactured  
interior pointer is being held and to which *object* (ie, the open  
array in this case) it refers so that it can 'fix' the pointer when  
the array object moves.  Modula-3 provides a small concession to  
obtaining downward exposed interior pointers using the VAR parameter  
mode.  For example you can pass 's[i]' as an actual parameter to a  
VAR mode formal, effectively passing a pointer to the callee.  GC can  
cope with this in one of two possible ways: 1) "Pin" the array so  
that it cannot be moved while the interior pointer is held on the  
stack or registers of any thread (this is the approach that CM3's  
conservative collector uses for now); or 2) track the creation of  
such interior pointers and how they are derived from base object  
references for use during GC.  2) requires much more co-operation  
from the compiler than the current gcc-based backend (with all of its  
lovely optimizations and register allocation) is capable of doing.   
1) is very cheap and does not impede optimizations and register  
allocation.

On Dec 1, 2007, at 8:15 AM, Jay wrote:

> This is a language question based on the x86 code gen.
> It isn't a code gen question at all, just related to m3 constructs  
> the code gen happens to use.
>
> The code gen has a stack of operands, I've said many times.
>
> This is partly made up.
>
>  type loc_t = [ imm, reg, mvar ] (* location: variable in memory,  
> register, immediate/constant  *)
>  type reg_t = [ eax, esi, edi, ...]  (* register *)
>
>   type operand_t = record
>    loc : loc_t;
>    reg : reg_t;
>    imm : integer; (* immediate or constant *)
>    (* some data associated with mvar... *)
>  end;
>
> The type is a bit bigger than this, and that is relevant.
>
> interface stack allows access both to entire operands, or their  
> fields, based on an index into the stack.
>
> The stack is not fixed size. I think this becomes important.
>
>  Pardon my mix of M3, C, C++ and made up syntax.
>
>  interface and module stack;
>
>  private s: array of operand;
>
>  procedure getloc(n: integer) : loc_t =
>  begin
>    return s[n].loc;
>  end getloc;
>
>  procedure getimm(n: integer) : INTEGER =
>  begin
>    return s[n].imm;
>  end getimm;
>
>  procedure getreg(n: integer) : reg_t =
>  begin
>    return s[n].reg;
>  end getreg;
>
>  procedure getop(n: integer) : operand_t = (* get entire operand *)
>  begin
>    return s[n];
>  end getop;
>
>  A cursory read of the source code, not yet of the object code,  
> from the point of view of a C/C++ programmer
> says to me that this last function getop returns a copy of an  
> entire record. Again, the record is a bit larger
> than this. I made it still larger, and I started getting warnings  
> about that.
>
>  What I would really like is for getop to return the operands by  
> pointer.
>
>  procedure getop(n: integer) : REF operand_t = (* get entire  
> operand *)
>  begin
>    return s[n];
>  end getop;
>
>  From my point of view, this is very natural. And far more efficient.
>  But I couldn't get anything to compile along these lines.
>
>  Now, as I said, the stack does grow sometimes, so the array could  
> get realloced, and outstanding
>  pointers invalidated. I guess that is the point? You can't  
> "safely" get a pointer?
>  I could make it an array of REFs I guess, heap-fragmentation- 
> unfriendly, but given that it grows
>  rarely, probably ok.
>
> I guess maybe gcc does a good job with this stuff? Optimzing away  
> the copies, inlining the array access, etc.?
>
>  Thoughts?
>  One just needs to get over worrying about the perf at this level  
> for one's sanity
>  to survive programming in Modula-3?
>
>  Safe languages are simply stuck with either a lot of garbage  
> collected separate heap allocations
>  or a lot of copying? Pointers as I think about them exude "danger"  
> all over the place?
>  (Yes, I know that "safely" and "danger" are technical terms and I  
> know what they mean,
>  at least roughly, no dangling pointers to stack, no double frees,  
> no unbounded
>  array access, no unchecked type conversions, the system remains  
> type safe and
>  the rules of the language remain unbroken, however I live and  
> breathe C/C++ so it
>  is hard to adjust my mindset, even if I understand the issues  
> fairly deeply.)
>
>  The problem one runs into, is that of the pretty darn good C and C+ 
> + programmers who, while
> not perfect, are pretty darn good. A "safe" language throws you to  
> quite an extreme
> of perf compromise to nail the last little bit of guaranteed  
> safety, when you really weren't doing such
> a bad job in the first place through brute force of careful  
> coding.. You pay a lot for a little.
> Lesser programmers, sure, they need the hand holding...
>
> I've been experimenting lately, and C just isn't actually all that  
> bad.
> Ok, actually most recently I'm writing more Perl, also not bad.
> See, there's another extreme. Traditional and semi-traditional  
> language
> and compilation systems like C and Modula-3 and even Java and C#  
> actually
> obsess far more about performance than many many problems need.
> Perl (Python, Ruby presumably, but Perl is the only one available  
> to me,
> that has cleared legal/licensing hurdles) is plenty adequate for  
> tons of tasks.
> If my task requires some i/o, then i/o cost might dominate the  
> overall perf cost...
>
> I realize I'm all over the place here, arguing for and against  
> optimizing.
>
> I don't like Perl's funny characters, or lack of a standard OO  
> approach,
> (using hash tables for everything really is bad..) but it's still  
> surprisingly good.
> I noticed some job descriptions lately for Perl programmers that  
> specifically
> said they were not "scripting" jobs but, like, real industrial  
> strength software engineering.
> I think those people get it.
> You get to a certain point of general purposeness and performance  
> and hopefully
> static checking, and a lot things don't matter as much as people  
> think....
>
> Anyway.
>  - Jay
>
>
> Share life as it happens with the new Windows Live. Share now!




More information about the M3devel mailing list