lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

on 2/15/05 12:44 PM, Mark Hamburg at wrote:

> * A metatable entry __assoc that would lead to a fully weak table. When
> marking an object, the GC would also mark[ obj ] (where
> 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


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! = name

    function proxyMethods:printName()
        local imp = assert( proxy2imp[ self ] )
        print( )

    function makeObject( initialName )
        local imp = { name = initialName }
        local proxy = setmetatable( {}, proxyMetatable )
        proxy2imp[ proxy ] = imp
        return proxy

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.


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.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. */ = 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.