-
Notifications
You must be signed in to change notification settings - Fork 16
Patch
重归混沌 edited this page Oct 29, 2021
·
8 revisions
Silly并不直接提供热修复功能, 但是提供了sys.patch模块来为热修复做了一些辅助工作。
sys.patch一共有三个接口:
-
sys.patch.create
用于创建一个热修复上下文, 以便在随后的修复操作中做一些必要的缓存。 -
sys.patch.collectupval(f_or_t)
用于收集一个或一组函数的上值信息, 该函数会递归遍历所有上值为函数的上值。 -
sys.patch.join(f1, f2)/sys.patch.join(f1, up1, f2, up2)
用于将f1函数的上值以上值名字为关联信息引用f2的上值, 如果f1的某个上值名字不存在于f2的上值列表中,则这个上值的路径将会被存储到路径列表中,sys.patch.join
在执行完之后, 总是会返回一个路径列表, 即使这个列表为空。
在console模块中提供了inject命令,使用该命令可以在沙盒中运行一段指定的代码。同样可以使用该指令来运行修复脚本, 以达到热修复的目的。
注意事项
- 热修复脚本应该只用于修复局部性bug, 如果使用此功能来进行功能热更新,需要三思而行。
- 如果某个函数引用了一个Table, 而这个Table又引用了另外的函数, 则被Table引用的函数及其上值不会被
sys.patch.collectupval
收集到, 需要热修复脚本在拿到Table之后再次调用sys.patch.collectupval
来进行收集。 - 对于
sys.patch.join
返回的上值路径列表, 必须仔细检查, 以确保上值引用的正确性。
在下面的例子中, 使用M2
来修复M1
。 由于M1.foo
中不含有上值b
, 因此sys.patch.join
不能正确处理M2.foo
中上值b
的引用。
这时sys.patch.join
会在路径列表中, 返回$.foo.b
来表示未能正确匹配M2.foo
中的上值b
。
我们需要手动调用debug.upvaluejoin
来将M2.foo
中的上值b
引用到M2.bar
中的上值b
。
--M1.lua
local M1 = {}
local a,b
function M1.foo()
return a
end
function M1.foo2()
return b
end
return M1
--M2.lua
local M2 = {}
local a,b
function M2.foo()
return a,b
end
function M2.foo2()
return b
end
- 在某些定时器场景下, 我们同样要需要使用
debug.setupvalue
来修正被修复函数的一些上值。比如下面代码, 当我们使用M2来修复M1时, 由于M1中的timer在循环执行。这时不能简单的在M2中使用新的timer再开一个定时器, 否则会有两个timer在同时运行。这里我们需要在热复脚本的最后调用debug.setupvalue
来将M1.timer_foo的上值timer修正为M2.timer_foo的上值timer, 这样在下一次定时器开始时, 就会自动切换到新的timer运行。
local M1 = load([[
local core = require "sys.core"
local M = {}
local timer
function timer()
print("timer old")
core.timeout(100, timer)
end
function M.timer_foo()
timer()
end
return M
]], nil, "t", _ENV)()
local ENV = setmetatable({}, {__index = _ENV})
local M2 = load([[
local core = require "sys.core"
local M = {}
local timer
function timer()
print("timer new")
core.timeout(500, timer)
end
function M.timer_foo()
timer()
end
return M
]], nil, "t", ENV)()
- 将“修复函数”重置为运行时状态时,依赖于上值的名字,因此在写修复代码时必须要注意:不得改变已有变量名的含义。例如下面代码就不可以用来热修复。在这种情况下,fix code是不可能被重置到run code当时的运行时状态,因为上值foo的含义已经改变了。这种情况下会引发一些诡异bug.
--run code
local M = {}
local foo = "foo"
function M.bar()
return foo .. "hello"
end
return M
--fix code
local M = {}
local foo1 = "foo"
local foo = "hello"
function M.bar()
return foo1 .. foo
end
return M