summaryrefslogtreecommitdiff
path: root/lib/supple/objects.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lib/supple/objects.lua')
-rw-r--r--lib/supple/objects.lua49
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,
}