FFI methods for userdata objects

  • From: Simon Cooke <sjcfwd@xxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Fri, 24 Aug 2012 14:01:33 -0400

I have an existing application that uses the standard Lua API to wrap
some simple C++ classes as full userdata objects. Converting entirely
to an FFI-based interface would be significant work so I'd like
instead to improve the performance of a few critical methods &
metamethods by replacing them with FFI functions, having the userdata
as the first (void*) argument. It seems that this works for a simple
method but not for a metamethod. The following example demonstrates
the problem using a userdata that simply holds a number:

/* test.cpp */

#include "lua.hpp"

extern "C" {

// returns a userdata with an empty metatable
int luaopen_testmodule(lua_State * L)
{
    void * ud = lua_newuserdata(L,8);
    * reinterpret_cast<double*>(ud) = 123.456;
    lua_newtable(L);
    lua_setmetatable(L,-2);
    return 1;
}

double get_double(void * ud) { return * reinterpret_cast<double*>(ud);   }

}

------ test.lua

local ffi = require'ffi'

ffi.cdef[[
double get_double(void *);
]]
clib = ffi.load'test'

ud = require'testmodule'

getmetatable(ud).__index = { get = clib.get_double }
print(ud:get()) -- ok

getmetatable(ud).__call = clib.get_double
print(ud()) -- Error

------ outputs:

123.456
    ...test.lua:16: attempt to call global 'ud' (a userdata value)

(Tested using latest git version on Linux x64 & v2.0.0-beta10 on Windows x64)

The simple FFI method call to ud:get() works as expected, but the
metamethod __call fails. I encountered similar behaviour with other
metamethods, but with different errors.

I understand that changing metamethods on cdata objects is disallowed,
but that is not the case here.

Is there a way to get this to work for metamethods, or is this
behaviour not supported?

Thanks,
Simon

Other related posts: