lua-users home
lua-l archive

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


On Sat, Nov 6, 2010 at 11:03 AM, Stefan Behnel <stefan_ml@behnel.de> wrote:
> Duncan Cross, 06.11.2010 11:04:
>>
>> On Sat, Nov 6, 2010 at 9:05 AM, Stefan Behnel wrote:
>>>
>>> I'm currently optimising an iteration wrapper that I have written for
>>> Lupa
>>> [1]. It basically maps Python's iterator protocol to the one in Lua, so
>>> that
>>> Lua programs can efficiently iterate over Python objects.
>>>
>>> To this end, I need to keep a reference to the Python iterator around,
>>> which
>>> I store as userdata in the Lua iterator state object (->  iterator,
>>> state,
>>> control variable) so that Lua garbage collects the Python iterator when
>>> the
>>> state object goes out of scope. To get the reference back at each
>>> iteration
>>> step, I use luaL_checkudata().
>>>
>>> Now, the callgrind profiler tells me that almost 25% of the time to
>>> advance
>>> the iterator is spent in the call to luaL_checkudata().  [...]
>>>
>>> Any ideas what I could try to improve this?
>>
>> It's not LuaJIT specific, but you could try holding the metatable you
>> want to check as an upvalue of the function that's doing the check
>> (see lua_pushcclosure, or the equivalent in Lupa) and then check it
>> with something like this:
>>
>>  // check argument 1 has 'MyType' metatable in upvalue 1
>>  lua_getmetatable(L, 1);
>>  luaL_argcheck(L, 1,
>>    lua_rawequal(L, -1, lua_upvalueindex(1)),
>>    "expecting a 'MyType' value");
>>  lua_pop(L, 1);
>
> *me slaps forehead* -- Thanks!
>
> Sure, the upvalues. I'm building the cclosure anyway. So all I really have
> to do is put the wrapped iterator userdata into the cclosure and read it
> from there using a plain lua_touserdata().
>
> Doing that makes the iterator almost 3x as fast as before.
>
> Is this considered safe, in the sense that it can't be misused from Lua
> code? For example, can you extract the underlying C function from its
> closure and call it with a new closure?
>
> Stefan
>
>
>

I don't believe there's any way to create a new closure from an
existing function "prototype" in Lua code (you probably can with the C
API, though). With the debug library available, you can get and set
upvalues for an existing closure, but that's kind of the nature of the
debug library: it will *let* you do unsafe things, and screw yourself
over, in many ways. Users that don't know what they're doing should be
avoiding it and untrusted code shouldn't have access to it anyway.

Also, I just realised my sample code will have a false-positive in one
scenario: if value 1 on the stack has no metatable, and the top value
on the stack is the metatable we are trying to check for. As I always
forget, lua_getmetatable() does not push nil if there is no metatable
- it doesn't push anything, but returns 0 instead of the usual 1. So a
safer version might be something like:

 // check argument 1 has 'MyType' metatable in upvalue 1
 luaL_argcheck(L, 1,
  lua_getmetatable(L, 1) && lua_rawequal(L, -1, lua_upvalueindex(1)),
  "expecting a 'MyType' value");
 lua_pop(L, 1);

-Duncan