[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: GC puzzler...
- From: Mark Hamburg <mhamburg@...>
- Date: Thu, 17 Feb 2005 12:12:35 -0800
on 2/15/05 12:44 PM, Mark Hamburg at mhamburg@adobe.com wrote:
> * A metatable entry __assoc that would lead to a fully weak table. When
> marking an object, the GC would also mark obj.mt.__assoc[ obj ] (where
> obj.mt is the object metatable). This could be made reasonably efficient by
> using the same logic as the other fast metamethods.
I've got a prototype implementation in Lua 5.1w4. It was pretty simple.
The semantics are as follows:
* If a table or userdata has a metatable and that metatable has an entry
under the key __assoc and that entry is a table, then when we mark the table
or userdata, we also mark the value found by indirecting through the __assoc
table.
Usage
=====
Proxy tables to shield hidden implementations
---------------------------------------------
local proxy2imp = setmetatable( {}, { __mode = "kv" } )
-- fully weak so no fear of semi-weak cycle issues
local proxyMethods = {}
local proxyMetatable = {
__index = proxyMethods,
__metatable = "< protected >",
__assoc = proxy2imp
}
function proxyMethods:setName( name )
local imp = assert( proxy2imp[ self ] )
-- This gets us type-checking as well!
imp.name = name
end
function proxyMethods:printName()
local imp = assert( proxy2imp[ self ] )
print( imp.name )
end
function makeObject( initialName )
local imp = { name = initialName }
local proxy = setmetatable( {}, proxyMetatable )
proxy2imp[ proxy ] = imp
return proxy
end
Lua data associated with userdata
----------------------------------
In the metatable for the userdata include an __assoc field and use it to map
from the userdata to the Lua data. This could probably benefit from some C
API support.
Implementation
==============
I'll see if I can figure out what I need to do to build a patch diff, but
here's a summary:
* Added a fast metatable entry TM_ASSOC ("__assoc") (ltm.h, ltm.c)
* In lgc.c:
Added (with a forward declaration):
static void markassociated
(global_State *g, const TValue *assoc, const TValue *obj) {
if (ttistable(assoc)) {
const TValue *associated = luaH_get(hvalue(assoc), obj);
if (!ttisnil(associated))
markvalue(g, associated);
}
}
Modified the LUA_TUSERDATA case of reallymarkobject so that instead of just
marking the metatable it does:
if (mt) {
const TValue* assoc = gfasttm(g, mt, TM_ASSOC);
markobject(g, mt);
if (assoc) {
TValue key;
key.tt = LUA_TUSERDATA;
key.value.gc = o;
markassociated(g, assoc, &key);
}
}
Modified the metatable handling in traversetable so that it does:
Table *mt = h->metatable;
if (mt) {
const TValue *assoc = gfasttm(g, mt, TM_ASSOC);
markobject(g, mt);
if (assoc) {
TValue key;
/* We could use sethvalue if it took the global state. It doesn't. */
key.tt = LUA_TTABLE;
key.value.gc=cast(GCObject *, (h));
markassociated(g, assoc, &key);
}
}
This could probably be tweaked slightly to share more code.
The cost of these changes is that for tables with metatables, the mark pass
has to check a flag bit in the metatable. It does more if the metatable has
an __assoc entry but we want it to do so there.
Mark