|
2016年2月14日 下午2:24,"Dirk Laurie" <dirk.laurie@gmail.com>写道:
>
> 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!
>
The OP_TAILCALL doesn't use C field, so it's possible to make a patch to support this usage