lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


2016-02-14 7:01 GMT+02:00 Derek Bailey <dbaileychess@gmail.com>:
> If func(x) returns multiple values and you do
>
> return func(x), something_else()
>
> it is going to adjust the func(x) it to a single value.
>
> I am curious if this adjustment happens before or after the call to
> "something_else". If it gets resolved before, the something_else can be a
> proper tail call, otherwise it won't be a true tail call because the
> arguments have to get adjusted and therefore the stack frame must be
> preserved.

For that sort of question, I don't bother reading manuals or  C source[1],
I just use luac.

$ luac -l -p -
return func(x), something_else()

main <stdin:0,0> (5 instructions at 0x1091780)
0+ params, 2 slots, 1 upvalue, 0 locals, 2 constants, 0 functions
    1    [1]    GETTABUP     0 0 -1    ; _ENV "func"
    2    [1]    GETTABUP     1 0 -2    ; _ENV "x"
    3    [1]    CALL         0 2 2
    4    [1]    GETTABUP     1 0 -3    ; _ENV "something_else"
    5    [1]    CALL         1 1 0
    6    [1]    RETURN       0 0
    7    [1]    RETURN       0 1

The adjustment of func(x) happens at the moment that the
preparation for calling something_else() is made, when Slot 1
is clobbered by GETTABUP 1 but Slot 0 stays intact. It's
beautiful. The slot into which the function went is the one
that keeps the single value. The stack is balanced with no
need to know the number of return parameters.

But that does not imply that you can have a tail call
to something_else because one return value is on the
stack below it. Even if func(x) returns nothing, there is nil.
Tail call means that the return values of the called routine
are precisely those of the tail-called routine.

Compare with

$ luac -l -p -
return something_else(func(x))

main <stdin:0,0> (7 instructions at 0x1c4d780)
0+ params, 3 slots, 1 upvalue, 0 locals, 3 constants, 0 functions
    1    [1]    GETTABUP     0 0 -1    ; _ENV "something_else"
    2    [1]    GETTABUP     1 0 -2    ; _ENV "func"
    3    [1]    GETTABUP     2 0 -3    ; _ENV "x"
    4    [1]    CALL         1 2 0
    5    [1]    TAILCALL     0 0 0
    6    [1]    RETURN       0 0
    7    [1]    RETURN       0 1

[1] Of course, you need to have read the comments in lopcodes.h
at some stage!