[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: LuaJIT FFI __gc metamethod?
- From: CrazyButcher <crazybutcher@...>
- Date: Mon, 28 Feb 2011 10:20:24 +0100
Thanks a lot, doing the memory operations on the userdata completely
in lua side is a much better approach.
That way I could allocate a bunch of generic sized userdatas in
advance, so that the regular plugin call doesn't ruin the jit at later
times.
2011/2/28 Robert G. Jakabosky <bobby@sharedrealm.com>:
> On Sunday 27, CrazyButcher wrote:
>> I try to box the content of a cdata in my own userdata via a classic
>> lua plugin function, to which I can hand the metatable for the
>> userdata.
>>
>> lua_topointer -> gives pointer to cdata obj, not the pointer it stores
>> lua_touserdata -> fails on cdata
>>
>> lua_tonumber -> works but it feels weird
>>
>> I create the number in the lua code through
>> tonumber(ffi.cast("uintptr_t",cdata))
>>
>> and on C side
>> const void orig = (const void*)(uintptr_t)lua_tonumber(...)
>
> I do not think this would be 64bit safe. It might work most of the time if
> all your 64bit pointer only use the lower 48bits.
>
> For the FFI-based bindings generated by LuaNativeObjects [1], I exported
> (private to the FFI bindings code) a C function which takes two arguments size
> & a metatable and returns a new userdata object. Then in the FFI bindings
> code the userdata object is cast to a structure pointer.
>
> /* c code. */
> static int nobj_udata_new_ffi(lua_State *L) {
> size_t size = luaL_checkinteger(L, 1);
> void *ud;
> luaL_checktype(L, 2, LUA_TTABLE);
> lua_settop(L, 2);
> /* create userdata. */
> ud = lua_newuserdata(L, size);
> lua_replace(L, 1);
> /* set userdata's metatable. */
> lua_setmetatable(L, 1);
> return 1;
> }
>
> -- lua side FFI code
> ffi.cdef[[
> typedef struct obj_udata {
> void *obj;
> int flags;
> } obj_udata;
> ]]
>
> -- create new userdata wrapped cdata object.
> function new_cdata_obj(cdata, size)
> local meta = {} -- new metatable or use some existing metatable
> if not size then
> local udata = nobj_udata_new_ffi(ffi.sizeof('obj_udata'), meta)
> local obj_data = ffi.cast('obj_udata *')
> obj_data.obj = cdata -- cdata pointer.
> obj_data.flags = 0
> else
> local udata = nobj_udata_new_ffi(size, meta)
> local obj_data = ffi.cast('void *')
> ffi.copy(obj_data, cdata, size)
> end
> -- return userdata
> return udata, meta
> end
>
> Also note that the object's methods will receive the userdata object as the
> 'self' argument and it will need to be cast back to a cdata value and you
> should check the metatable on the userdata to make sure it is the right type
> (someone could pass any other userdata object can cause bad things to happen).
> If you don't do type checking, then your bindings can't be used in a sandbox
> safely.
>
> For performance of the metatable type checking, I use a weak table per object
> type that maps each userdata value to the wrapped cdata value.
>
> local function obj_udata_luacheck_internal(obj, type_mt)
> -- need the debug version of getmetatable, since the metatable might be
> -- hidden (i.e. if '__metatable' is set)
> local obj_mt = debug.getmetatable(obj)
> if obj_mt == type_mt then
> -- convert userdata to cdata.
> local ud = ffi.cast('obj_data *',obj)
> return ud.obj
> end
> error("(expected `" .. type_mt['.name'] .. "`, got " .. type(obj) .. ")", 2)
> end
>
> -- '${object_name}' is replaced with the cdata C typename.
> local ${object_name}_objects[udata] = setmetatable({}, { __mode = "k" })
> local function obj_type_${object_name}_check(udata)
> local c_obj = ${object_name}_objects[udata]
> if c_obj == nil then
> -- cdata object not in cache
> c_obj = obj_udata_luacheck(udata, ${object_name}_mt)
> c_obj = ffi.cast("${object_name} *", c_obj) -- cast from 'void *'
> ${object_name}_objects[udata] = c_obj -- cache object
> end
> return c_obj
> end
>
> 1. https://github.com/Neopallium/LuaNativeObjects
>
> --
> Robert G. Jakabosky
>
>