123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- --- Replace functions of table or upvalue.
- -- Search for the old functions and replace them with new ones.
- local M = {}
- -- Objects whose functions have been replaced already.
- -- Each objects need to be replaced once.
- local replaced_obj = {}
- -- Map old functions to new functions.
- -- Used to replace functions finally.
- -- Set to hotfix.updated_func_map.
- local updated_func_map = {}
- -- Do not update and replace protected objects.
- -- Set to hotfix.protected.
- local protected = {}
- local replace_functions -- forward declare
- -- Replace all updated functions in upvalues of function object.
- local function replace_functions_in_upvalues(function_object)
- local obj = function_object
- assert("function" == type(obj))
- assert(not protected[obj])
- assert(obj ~= updated_func_map)
- for i = 1, math.huge do
- local name, value = debug.getupvalue(obj, i)
- if not name then return end
- local new_func = updated_func_map[value]
- if new_func then
- assert("function" == type(value))
- debug.setupvalue(obj, i, new_func)
- else
- replace_functions(value)
- end
- end -- for
- assert(false, "Can not reach here!")
- end -- replace_functions_in_upvalues()
- -- Replace all updated functions in the table.
- local function replace_functions_in_table(table_object)
- local obj = table_object
- assert("table" == type(obj))
- assert(not protected[obj])
- assert(obj ~= updated_func_map)
-
- replace_functions(debug.getmetatable(obj))
- local new = {} -- to assign new fields
- for k, v in pairs(obj) do
- -- 配置文件不能更新
- if type(k)== "string" and not string.match(k, "../config") then
- local new_k = updated_func_map[k]
- local new_v = updated_func_map[v]
- if new_k then
- obj[k] = nil -- delete field
- new[new_k] = new_v or v
- else
- obj[k] = new_v or v
- replace_functions(k)
- end
- if not new_v then replace_functions(v) end
- end
- end -- for k, v
- for k, v in pairs(new) do obj[k] = v end
- end -- replace_functions_in_table()
- -- Replace all updated functions.
- -- Record all replaced objects in replaced_obj.
- function replace_functions(obj)
- if protected[obj] then return end
- local obj_type = type(obj)
- if "function" ~= obj_type and "table" ~= obj_type then return end
- if replaced_obj[obj] then return end
- replaced_obj[obj] = true
- assert(obj ~= updated_func_map)
- if "function" == obj_type then
- replace_functions_in_upvalues(obj)
- else -- table
- replace_functions_in_table(obj)
- end
- end -- replace_functions(obj)
- --- Replace all old functions with new ones.
- -- Replace in new_obj, _G and debug.getregistry().
- -- a_protected is a list of protected object.
- -- an_updated_func_map is a map from old function to new function.
- -- new_obj is the newly loaded module.
- function M.replace_all(a_protected, an_updated_func_map, new_obj, module_name)
- protected = a_protected
- updated_func_map = an_updated_func_map
- assert(type(protected) == "table")
- assert(type(updated_func_map) == "table")
- if nil == next(updated_func_map) then
- return
- end
- replaced_obj = {}
- replace_functions(new_obj) -- new_obj may be not in _G
- replace_functions(_G)
- replace_functions(debug.getregistry())
- replaced_obj = {}
- end -- M.replace_all()
- return M
|