diff options
Diffstat (limited to 'lib/supple/objects.lua')
-rw-r--r-- | lib/supple/objects.lua | 49 |
1 files changed, 45 insertions, 4 deletions
diff --git a/lib/supple/objects.lua b/lib/supple/objects.lua index 5a5dfca..2f5da79 100644 --- a/lib/supple/objects.lua +++ b/lib/supple/objects.lua @@ -12,18 +12,22 @@ local gc = collectgarbage local capi = require 'supple.capi' +local track = require 'supple.track' local my_objects_by_obj = {} local my_objects_by_tag = {} +local my_objects_expn_by_tag = {} local my_name = "UNSET" local my_counter = 0 local their_objects_by_tag = setmetatable({}, { __mode="v" }) local their_objects_by_obj = setmetatable({}, { __mode="k" }) +local their_objects_refcnt = {} local proc_call = nil local type = capi.rawtype local function clean_down(call_other_end) + track.enter("clean_down") -- And force a full GC gc "collect" gc "collect" @@ -35,6 +39,8 @@ local function clean_down(call_other_end) -- And forget all our local objects my_objects_by_obj = {} my_objects_by_tag = {} + my_objects_expn_by_tag = {} + track.leave("clean_down") end local function set_name(newname) @@ -76,21 +82,26 @@ local function give(obj, special_tag) end -- If the passed object is one of their objects then "unwrap" it by -- returning their tag. + track.enter("give", tostring(obj), tostring(special_tag)) local tag = their_objects_by_obj[obj]; if tag then + track.leave("give", "theirs", tag) return { tag = tag } end -- If it's one of our objects which has already been wrapped, return our -- tag local tag = my_objects_by_obj[obj] if tag then - return { tag = tag } + track.leave("give", "ours", tag) + return my_objects_expn_by_tag[tag] end -- otherwise wrap it freshly for us and return that. local tag = new_tag(special_tag) local expn = capi.explain(obj, tag) my_objects_by_obj[obj] = tag my_objects_by_tag[tag] = obj + my_objects_expn_by_tag[tag] = expn + track.leave("give", "ours, new", tag) return expn end @@ -103,25 +114,28 @@ local function receive(obj) assert(type(obj) == "table") assert(type(obj.tag) == "string") local tag = obj.tag + track.enter("receive", tag) -- First up, is it one of our objects? local ret = my_objects_by_tag[tag] if ret then + track.leave("receive", "ours", tostring(ret)) return ret end -- Now is it a known one of their objects? ret = their_objects_by_tag[tag] if ret then + track.leave("receive", "theirs", tostring(ret)) return ret end -- Okay, prepare a proxy? - assert(type(obj.type) == "string") + assert(type(obj.type) == "string", "Type string expected, got " .. type(obj.type) .. " preparing proxy for " .. obj.tag) local proxy, mt = capi.new_proxy(obj.type) assert(capi.type(proxy) == obj.type) their_objects_by_tag[tag] = proxy their_objects_by_obj[proxy] = tag + their_objects_refcnt[tag] = (their_objects_refcnt[tag] or 0) + 1 -- Fill out the metatable obj.methods = obj.methods or {} - obj.methods[#obj.methods+1] = "__gc" if obj.type == "function" then obj.methods[#obj.methods+1] = "__call" end @@ -133,18 +147,33 @@ local function receive(obj) end for _, name in ipairs(obj.methods or {}) do local function meta_func(mobj, ...) - return proc_call(tag, name, ...) + track.enter("meta_func", tostring(mobj), tag, name) + local ret = {proc_call(tag, name, ...)} + track.leave("meta_func", tostring(mobj), tag, name) + return unpack(ret) end mt[name] = meta_func end + function mt:__gc() + their_objects_refcnt[tag] = their_objects_refcnt[tag] - 1 + if their_objects_refcnt[tag] == 0 then + their_objects_refcnt[tag] = nil + proc_call(tag, "__gc") + end + end -- And return the proxy object + track.leave("receive", "theirs, new", tostring(proxy)) return proxy end local function forget_mine(tag) + track.enter("forget_mine", tag) local obj = my_objects_by_tag[tag] + assert(obj, "Trying to forget nil object: " .. tag) my_objects_by_tag[tag] = nil my_objects_by_obj[obj] = nil + my_objects_expn_by_tag[tag] = nil + track.leave("forget_mine", tag) end local function find_tag(obj) @@ -156,6 +185,17 @@ local function find_tag(obj) end end +local function get_object_anchor() + local ret = {} + for obj in pairs(their_objects_by_obj) do + ret[obj] = true + end + for obj in pairs(my_objects_by_obj) do + ret[obj] = true + end + return ret +end + return { set_name = set_name, get_name = get_name, @@ -165,4 +205,5 @@ return { clean_down = clean_down, forget_mine = forget_mine, find_tag = find_tag, + get_object_anchor = get_object_anchor, } |