lua-users home
lua-l archive

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


Hi,

why not extend the Lua type system so it allows for user definable and
user allocatable types? Surprisingly little glue logic is needed to
integrate it into the Lua GC.

Completely untested and incomplete pseudo-code follows:

---- lua.h ----
typedef void (*lua_GCTraverse)(void *ud, void *p, void *gcstate);
typedef void (*lua_GCFree)(void *ud, void *p, void *gcstate);
LUA_API int lua_utyperegister(lua_State *L, lua_GCTraverse t, lua_GCFree f, void *ud);

LUA_API void lua_pushutype(lua_State *L, int tag, void *p);
#define lua_toutype(L,idx)	lua_togcref(L, idx)

LUA_API void *lua_togcref(lua_State *L, int idx);
LUA_API void lua_markgcref(void *gcstate, void *gcref);

/* Types must match Utype from lobject.h */
#define LUA_UTHEADER \
  void *_lua_n; unsigned char _lua_t; unsigned char _lua_k; \
  void *_lua_m; void *_lua_g;


---- lobject.h ----

#define LUA_TUTYPE	(NUM_TAGS+3)

#define ttisutype(o)	(ttype(o) >= LUA_TUTYPE)

#define utvalue(o)	check_exp(ttisutype(o), &(o)->value.gc->ut)

#define setutvalue(obj,t,x) \
  { TObject *i_o=(obj); i_o->tt=t; \
    i_o->value.gc=cast(GCObject *, (x)); \
    /* i_o->value.gc->gch.tt=t; ... done by luaC_link ... */ }

typedef union Utype {
  L_Umaxalign dummy;
  struct {
    CommonHeader;
    struct Table *metatable;
    GCObject *gclist;
  } utv;
} Utype;


---- lstate.h ----

#define gcotout(o)	check_exp((o)->gch.tt >= LUA_TUTYPE, &((o)->ut))

union GCObject {
  ...
  union Utype ut;
};


---- lapi.c ----

/* Register your type once and get back a unique tag */
LUA_API int lua_utyperegister(lua_State *L, lua_GCTraverse t, lua_GCFree f, void *ud)
{
  tag = ... assign next free tag number starting after internal tags ...
  ... register traversal and free functions plus ud with this tag ...
  return tag;
}

/* Allocate a specific type and call this function to export it to Lua */
LUA_API void lua_pushutype(lua_State *L, int tag, void *p)
{
  lua_lock(L);
  ... check that the passed tag is valid and registered ...
  setutvalue(L->top, tag, p);
  luaC_link(L, L->top, tag);
  api_incr_top(L);
  lua_unlock(L);
}

/* Get an abstract GC object reference that can be marked upon traversal */
LUA_API void *lua_togcref(lua_State *L, int idx)
{
  StkId o = luaA_indexAcceptable(L, idx);
  if (o == NULL || !iscollectable(o)) return NULL;
  return (void *)o->value;
}

... add metatable support for types >= LUA_UTYPE ...

---- lgc.c ----
/* Mark a GC object reference during traversal */
LUA_API void lua_markgcref(void *gcstate, void *gcref)
{
  markvalue((GCState *)gcstate, gcref);
}

static void reallymarkobject(GCState *st, GCObject *o)
{
  ...
  switch (o->gch.tt) {
  case LUA_TSTRING:
    break;
  default:
    gcotout(o)->gclist = st->tmark;
    st->tmark = o;
    break;
  }
}

static void propagatemarks(GCState *st)
{
  while (st->tmark) {  /* traverse marked objects */
    switch (st->tmark->gch.tt) {
    ...
    default:
      Utype *u = gcotout(st->tmark);
      lua_GCTraverse func;
      st->tmark = ut->gclist;
      markvalue(st, ut->metatable);
      ... get traversal function for this type ...
      func(ud, p, (void *)st);
      break;
    }
  }
}

static void freeobj(lua_State *L, GCObject *o)
{
  switch (o->gch.tt) {
  ...
  default:
    lua_GCFree func;
    ... get free function for this type ...
    func(ud, (void *)o, (void *)st);
    break;
  }
}

... add logic similar to luaC_separateudata for the new types? ...

----

This is for the Lua 5.0 GC. I haven't taken a closer look at the Lua 5.1
incremental GC yet.

The type system could be extended to allow for different types that either
do not need traversal (omit gclist) and/or metatables (omit metatable).
This would reduce the per-object GC overhead.

I'm not sure this whole idea works and/or solves your problems. But maybe
it's a start?

Bye,
     Mike