lua-users home
lua-l archive

Re: Lua 5 and tags

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


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

AltStyle によって変換されたページ (->オリジナル) /