[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Lua 5 and tags
- From: Mike Pall <mikelu-0407@...>
- Date: Sun, 25 Jul 2004 21:31:46 +0200
Hi,
Mark Hamburg wrote:
> Only between two Lua strings. If one of the strings is coming from C, it
> needs to at least go through strcmp if not being actually converted to a Lua
> string.
In fact when I was profiling Diego's Luasocket, I noticed that one of my
test cases was spending 12% of its time in luaS_newlstr() (due to the
specific way Luasocket checks its userdata arguments). Converting C strings
to Lua strings all the time is pretty expensive.
I think the fastest solution is to register all methods with an upvalue
that holds a reference to the metatable. Storing and retrieving the
metatable to/from the registry is not necessary. And you don't have to
provide a unique name or a unique memory address for all of your userdata
types.
The performance sensitive code path is then:
void *luaL_checkudata_upval(lua_State *L, int ud, int uv, char *msg)
{
void *u;
if (lua_getmetatable(L, ud) &&
lua_rawequal(L, -1, lua_upvalueindex(uv)) &&
(u = lua_touserdata(L, ud))) {
lua_pop(L, 1);
return u;
}
luaL_argerror(L, 0, msg); /* Never returns. */
return NULL;
}
lua_rawequal() is certainly a lot faster than lua_rawget() + lua_tostring() +
strcmp() (the lauxlib string key solution) or just lua_rawget() (the
lightuserdata plus fixed pointer solution). Making the check an inline
function or macro will save a few more cycles.
The standard usage is:
#define foo_checkudata(L) \
((foo_t *)luaL_checkudata_upval((L), 1, 1, "foo expected"))
int foo_method(lua_State *L)
{
foo_t *foo = foo_checkudata(L);
...
}
Adding the following to lapi.c would allow for an even faster solution:
void *lua_touserdata_mc(lua_State *L, int indexu, int indexm)
{
StkId uo = luaA_index(L, indexu);
StkId mo = luaA_index(L, indexm);
if (!ttisuserdata(uo) || !ttistable(mo) ||
uvalue(uo)->metatable != hvalue(mo)) return NULL;
return rawuvalue(uo) + 1;
}
[untested]
Bye,
Mike