next up previous contents
Next: Datatypes representation Up: Implementation Notes (aka hacker Previous: Code generation   Contents

Argument passing conventions

Values passed as polymorphic parameters has to be all of the same size. Otherwise we wouldn't be able to generate efficient code. Specially for this purpose `int' Gont type is chosen with the same as size as machine pointer. (This is not the choice of some C compilers on some 64 bit architectures, for example on alpha-*-linux with GCC sizeof(int) = 4, sizeof(long) = sizeof(void*) = 8).

They are few basic types of passing arguments in Gont.

  1. by value. int and bool are passed this way.
  2. by pointer to some location on the heap. structures, unions and tuples are passed this way.
  3. by pointer to location, that is not guaranteed to exists after function terminates (read: this can be pointer to the stack of function that called us). If such value needs to be saved after function return, is has to be copied to the heap. It also has to be copied if calling raise with it. Special functions are provided by the runtime to copy such values. Floats and functional values are passed this way.

[[Functional values are currently always passed as pointers to the heap. I guess some semantic analysis will be done to pass it as pointers to stack when it is safe. Similarly for function closures.]]

Functional values cannot be passed simply as pointers to functions, since they might need closure in some (most?) cases. Here is layout of data structure describing functional value:

        void *fnc;
        void *closure;

closure has to be passed as the first argument to fnc. Closure must not point into the stack.

Pseudocode example:

        foo() 
        {
                int x;
                int y;
                g() 
                {
                        int p;
                        
                        use(p);
                        use(x);
                }

                use(x);
                use(y);
                use(g);
        }

is translated to:

        struct foo_closure {
                int x;
        }

        foo_lambda1(foo_closure *ptr) 
        {
                int p;
                use(p);
                use(ptr->x);
        }

        foo()
        {
                int y;
                foo_closure *cl = make_closure(...);
                void *g = make_lambda(foo_lambda1, cl);

                use(cl->x);
                use(y);
                use(g);
        }

(Examples are given using pseudo-Gont as input, and pseudo-C as output, just to not confuse reader with Ksi syntax).

One might note that it might be impossible to pass regular function this way. We need auxiliary function to be generated.


next up previous contents
Next: Datatypes representation Up: Implementation Notes (aka hacker Previous: Code generation   Contents
Micha³ Moskal 2001-11-27