Skip to content

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

Description

@Yiklek

您好,首先十分感谢作者,这本书对帮助我理解虚拟机底层运行机制帮助很大。目前看到第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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions