luago-book icon indicating copy to clipboard operation
luago-book copied to clipboard

请教一下第10章 关于upvalue的问题

Open Yiklek opened this issue 3 years ago • 1 comments

您好,首先十分感谢作者,这本书对帮助我理解虚拟机底层运行机制帮助很大。目前看到第10章,也参考了这个仓库自己实现了一个Rust版本。 在实现好第10章的内容后对upvalue的一些情况做了测试,但是发现有一种情况不能通过,debug后觉得可能是对于upvalue的引用问题。 用例代码如下:

local step = 1
local start = 0
local function assert(v)
    if not v then
        fail()
    end
end
function newCounter()
    local count = start
    return function()
        count = count + step
        return count
    end
end

c1 = newCounter()
assert(c1() == 1)
assert(c1() == 2)

c2 = newCounter()
assert(c2() == 1)   -- 3
assert(c1() == 3)   -- 4
assert(c2() == 2)  -- 5

似乎是因为newCounter获取到startcount之后,后续对count的更改都会同时反馈在最外层的start上。 我想请教一下,lua对于这种情况闭包获取到的upvalue的生命周期是不是还有其他的处理呢?如果有的话是如何实现的呢,在官方c实现的版本里应该去了解哪部分的代码?

如果您方便的话请您帮忙解答一下,非常感谢!

编译器版本: Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio 操作系统: macOS 11.3.1 附编译后的指令:

main <tests/upvalue.lua:0,0> (52 instructions at 0x7f8d3a406590)
0+ params, 5 slots, 1 upvalue, 3 locals, 7 constants, 2 functions
        1       [1]     LOADK           0 -1    ; 1
        2       [2]     LOADK           1 -2    ; 0
        3       [7]     CLOSURE         2 0     ; 0x7f8d3a406700
        4       [14]    CLOSURE         3 1     ; 0x7f8d3a406b40
        5       [8]     SETTABUP        0 -3 3  ; _ENV "newCounter"
        6       [16]    GETTABUP        3 0 -3  ; _ENV "newCounter"
        7       [16]    CALL            3 1 2
        8       [16]    SETTABUP        0 -4 3  ; _ENV "c1"
        9       [17]    MOVE            3 2
        10      [17]    GETTABUP        4 0 -4  ; _ENV "c1"
        11      [17]    CALL            4 1 2
        12      [17]    EQ              1 4 -1  ; - 1
        13      [17]    JMP             0 1     ; to 15
        14      [17]    LOADBOOL        4 0 1
        15      [17]    LOADBOOL        4 1 0
        16      [17]    CALL            3 2 1
        17      [18]    MOVE            3 2
        18      [18]    GETTABUP        4 0 -4  ; _ENV "c1"
        19      [18]    CALL            4 1 2
        20      [18]    EQ              1 4 -5  ; - 2
        21      [18]    JMP             0 1     ; to 23
        22      [18]    LOADBOOL        4 0 1
        23      [18]    LOADBOOL        4 1 0
        24      [18]    CALL            3 2 1
        25      [20]    GETTABUP        3 0 -3  ; _ENV "newCounter"
        26      [20]    CALL            3 1 2
        27      [20]    SETTABUP        0 -6 3  ; _ENV "c2"
        28      [21]    MOVE            3 2
        29      [21]    GETTABUP        4 0 -6  ; _ENV "c2"
        30      [21]    CALL            4 1 2
        31      [21]    EQ              1 4 -1  ; - 1
        32      [21]    JMP             0 1     ; to 34
        33      [21]    LOADBOOL        4 0 1
        34      [21]    LOADBOOL        4 1 0
        35      [21]    CALL            3 2 1
        36      [22]    MOVE            3 2
        37      [22]    GETTABUP        4 0 -4  ; _ENV "c1"
        38      [22]    CALL            4 1 2
        39      [22]    EQ              1 4 -7  ; - 3
        40      [22]    JMP             0 1     ; to 42
        41      [22]    LOADBOOL        4 0 1
        42      [22]    LOADBOOL        4 1 0
        43      [22]    CALL            3 2 1
        44      [23]    MOVE            3 2
        45      [23]    GETTABUP        4 0 -6  ; _ENV "c2"
        46      [23]    CALL            4 1 2
        47      [23]    EQ              1 4 -5  ; - 2
        48      [23]    JMP             0 1     ; to 50
        49      [23]    LOADBOOL        4 0 1
        50      [23]    LOADBOOL        4 1 0
        51      [23]    CALL            3 2 1
        52      [23]    RETURN          0 1
constants (7) for 0x7f8d3a406590:
        1       1
        2       0
        3       "newCounter"
        4       "c1"
        5       2
        6       "c2"
        7       3
locals (3) for 0x7f8d3a406590:
        0       step    2       53
        1       start   3       53
        2       assert  4       53
upvalues (1) for 0x7f8d3a406590:
        0       _ENV    1       0

function <tests/upvalue.lua:3,7> (5 instructions at 0x7f8d3a406700)
1 param, 2 slots, 1 upvalue, 1 local, 1 constant, 0 functions
        1       [4]     TEST            0 1
        2       [4]     JMP             0 2     ; to 5
        3       [5]     GETTABUP        1 0 -1  ; _ENV "fail"
        4       [5]     CALL            1 1 1
        5       [7]     RETURN          0 1
constants (1) for 0x7f8d3a406700:
        1       "fail"
locals (1) for 0x7f8d3a406700:
        0       v       1       6
upvalues (1) for 0x7f8d3a406700:
        0       _ENV    0       0

function <tests/upvalue.lua:8,14> (4 instructions at 0x7f8d3a406b40)
0 params, 2 slots, 2 upvalues, 1 local, 0 constants, 1 function
        1       [9]     GETUPVAL        0 0     ; start
        2       [13]    CLOSURE         1 0     ; 0x7f8d3a406c40
        3       [13]    RETURN          1 2
        4       [14]    RETURN          0 1
constants (0) for 0x7f8d3a406b40:
locals (1) for 0x7f8d3a406b40:
        0       count   2       5
upvalues (2) for 0x7f8d3a406b40:
        0       start   1       1
        1       step    1       0

function <tests/upvalue.lua:10,13> (7 instructions at 0x7f8d3a406c40)
0 params, 2 slots, 2 upvalues, 0 locals, 0 constants, 0 functions
        1       [11]    GETUPVAL        0 0     ; count
        2       [11]    GETUPVAL        1 1     ; step
        3       [11]    ADD             0 0 1
        4       [11]    SETUPVAL        0 0     ; count
        5       [12]    GETUPVAL        0 0     ; count
        6       [12]    RETURN          0 2
        7       [13]    RETURN          0 1
constants (0) for 0x7f8d3a406c40:
locals (0) for 0x7f8d3a406c40:
upvalues (2) for 0x7f8d3a406c40:
        0       count   1       0
        1       step    0       1

Yiklek avatar Jul 02 '21 10:07 Yiklek

请问一下具体的问题是什么?是说这个测试用书中的代码执行结果和CLua不一致吗?

zxh0 avatar Jul 06 '21 00:07 zxh0