Skip to content
重归混沌 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
Clone this wiki locally