1. On the todo list for fpc's MacPas mode is a feature that allows local procedures (functions) to be passed a procedural parameters. I tentatively put it on my own todo list, since this is the feature that I like most in Pascal compilers, at the same time making a small contribution to fpc and learning about the compiler. Before doing so, I need agreement on the method followed.


2. The problem with local procedures is that there must be a mechanism to address parameters and local variables of parent procedures. In Section 12.2 of "Grundlagen und Techniken des Compilerbaus" Niklaus Wirth points out we can do that with a static link chain pointer to the stack frame of the parent procedure(s). It is important to note that the static link chain can differ from the dynamic link chain because the latter corresponds to the calling chain and that calling chain can differ from the static parent-sub-procedure relation, i.e. if there is more than one local procedure at the same level.

3. FPC passes the static link chain frame pointer as an extra invisible parameter to local procedures (Section 6.4 of the fpc Programmer’s Manual).

4. So, when passing a local procedure (function) as procedural parameter, the static link chain frame pointer must be passed along with the entry point of the local procedure. However, this raises concerns about calling conventions and compatibility with existing code and the current compiler.

5. To solve this dilemma, gnu C, Pascal and Ada (and also MetroWerks CodeWarrior Pascal) use a technique called trampolines. The idea is outlined in <http://people.debian.org/~aaronl/Usenix88-lexic.pdf> and the gnu implementation is discussed at <http://gcc.gnu.org/onlinedocs/gccint/Trampolines.html>. In short, a transition vector is set up temporarily for the local procedure that contains code from which the static link frame pointer can be obtained.

6. Although conventional wisdom dictates that we always follow the latest fashion in programming without further thinking, I believe that with some analysis we can do better than trampolines. There are two strong arguments that speak against the use of trampolines:

(a) trampolines must be setup at runtime and this involves flushing the instruction/data cache of the processor, a grave (and stupid) slowdown
(b) trampolines are very tricky to implement and quite platform-dependent (see e.g. <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=10900>).


7. Consider the following program:

        program func;

        type tfun = function( x: real): real;

        procedure iso_fun( function f( x: real): real);
        begin
        end;

        procedure typ_fun( pf: tfun);
        begin
        end;

        procedure somefun;

                function f( x: real): real;
                begin
                        f:= x
                end;

        begin
                iso_fun( f);
                typ_fun( f); {procedural variable can't get nested routiine}
        end;

        begin
        end.

MetroWerks CodeWarrior Pascal allows passing local procedures (functions) as procedural parameter, but there is an interesting point. It allows passing the local function f to iso_fun, but it doesn't allow passing it to typ_fun. The reason is clear - the value of the static link chain frame pointer is valid only within a specific activation of the parent procedure. So, it should not be allowed that the procedural parameter f somehow propagates out of the surrounding parent procedure and this can be guaranteed only if assignment to a typed procedural variable or (typed procedural value parameter) is forbidden.

So, we need to allow local procedures as actual parameters only for the "iso" notation. So, I suggest to change "iso" style procedural parameters only, i.e.

(a) change them from a pointer to a record: the record has two pointer fields, one for the routine's entry point and one for the optional static link chain frame pointer, or
(b) pass the static link chain frame pointer as an extra invisible parameter for each "iso" style procedural parameter.


Something similar has been implemented in fpc already, namely for methods that are passed as parameter. Here, an extra "self" pointer is needed.

The effect on current software should be minimal, because (currently) only MacPas mode allows "iso" style procedural parameters. This eliminates any concerns about calling conventions and compatibility with existing code and the current compiler.

Note that, with this solution, typed procedural variables can be passed as actual procedural parameters to "iso" style formal parameters, but not the other way round.

9. Conclusion.

With the above method, it should be relatively simple to implement local procedures (functions) as procedural parameters, without affecting the code generation of the current compiler.

Regards,

Adriaan van Os


_______________________________________________ fpc-devel maillist - fpc-devel@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply via email to