lua-users home
lua-l archive

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


Slightly old thread, but...

As noted previously, there are GC issues with just supporting pushing. I had
wanted something similar for userdata and was convinced otherwise. One
could, however, make a variety of extensions to Lua that wouldn't have this
problem. These include:

* Guarantee that lua_topointer is stable -- i.e., the value won't change for
a particular object. For the current implementation, this should be trivial.
A moving collector might have more trouble, but I could also see a moving
collector using some form of double-indirection and beyond that there's a
lot of flexibility since the pointer doesn't mean anything.

* Provide a way to register a pointer. One could just use the registry as
follows:

    lua_pushlightuserdata( L, lua_topointer( L, obj_index ) );
    lua_pushvalue( L, obj_index );  /* assumes obj_index is normalized */
    lua_rawset( L, LUA_REGISTRYINDEX );

Then you can push it back via the value of topointer.

This, of course, doesn't gain one anything relative to refs and costs more
storage space since we now have a key/value pair rather than an array entry.
It's one benefit is that if you potentially register from multiple places,
then you still only get one table entry -- but then you had better not clear
the registration.

But, now consider a somewhat different scheme in which we have a weak valued
table mapping light userdata to objects. Now, we can use the same scheme but
when we go to retrieve the value it may have disappeared. For example:

    int pushweakobject( lua_State *L, void *obj_pointer ) {
        lua_pushliteral( L, "weak_object_table" );
        lua_rawget( L, LUA_REGISTRYINDEX );
        lua_pushlightuserdata( L, obj_pointer );
        lua_rawget( L, -2 );
        if( lua_isnil( L, -1 ) ) {
            lua_pop( L, 1 ); /* If we want getmetatable like behavior */
            return 0;
        }
        return 1;
    }

In an actual implementation, I would probably use a light userdata rather
than the literal.

* Further enhancements/optimizations could come from adding API support for
doing a pushlightuserdata/rawget combination. This could just be an auxlib
thing, but like lua_rawgeti it might offer opportunities for optimization.

* Furthermore, one could create a standard weak valued table with a magic
index like LUA_REGISTRYINDEX. The combination of that and the rawgetud
optimization would make the code while not quite as fast as the proposed
lua_pushtable certainly closer to being competitive.

Finally, this design could also be used to create weak object references for
Lua code. The current weak table code works but needs to be used with a fair
degree of care since it can lead to unexpected object-retention depending on
the structure of the table.

Mark

on 6/3/04 11:47 PM, Nodir Temirhodzhaev at tnodir@land.ru wrote:

> Mark Hamburg:
>> Where did the table come from?
> 
> I use lua_pushtable(L, *p->data);
> in callback functions instead of:
> 
> lua_pushlightuserdata(L, p);
> lua_rawget(L, LUA_REGISTRYINDEX);
> [[
> lua_pushlightuserdata(L, p->win);
> lua_rawget(L, -2);
> ]]
> 
> Some objects stored in registry, others in subtable ([[...]
> ]). I may save the type of object in data or simply point
> to it's table (faster).