Suggestion: use lua_objlen to get size of userdata for __lanesclone
jjvbsag opened this issue · comments
In our project we have diffent userdata with different sizes, which share the same metatable. By this and the current approach of __lanesclone metamethod it is not possible to implement lanesclone, because the function only gets lightuserdata without size information.
Now lua_objlen always returns the size of an allocated userdata, so we changed and simplified the implementation.
Our change to tools.c:
Index: lanes-3.15.1/src/tools.c
===================================================================
--- lanes-3.15.1/src/tools.c (Revision 449609)
+++ lanes-3.15.1/src/tools.c (Arbeitskopie)
@@ -1473,6 +1473,7 @@
static bool_t copyclone( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, LookupMode mode_, char const* upName_)
{
+ int const sourceidx = lua_absindex( L, i);
void* const source = lua_touserdata( L, i);
STACK_CHECK( L, 0);
@@ -1512,13 +1513,7 @@
int const mt = lua_absindex( L, -2);
size_t userdata_size = 0;
void* clone = NULL;
- lua_pushvalue( L, -1); // ... mt __lanesclone __lanesclone
- // call the cloning function with 1 argument, should return the number of bytes to allocate for the clone
- lua_pushlightuserdata( L, source); // ... mt __lanesclone __lanesclone source
- lua_call( L, 1, 1); // ... mt __lanesclone size
- STACK_MID( L, 3);
- userdata_size = (size_t) lua_tointeger( L, -1); // ... mt __lanesclone size
- lua_pop( L, 1); // ... mt __lanesclone
+ userdata_size = lua_objlen(L,sourceidx);
// we need to copy over the uservalues of the userdata as well
{
// extract all the uservalues, but don't transfer them yet
@@ -1582,7 +1577,8 @@
// call cloning function in source state to perform the actual memory cloning
lua_pushlightuserdata( L, clone); // ... mt __lanesclone clone
lua_pushlightuserdata( L, source); // ... mt __lanesclone clone source
- lua_call( L, 2, 0); // ... mt
+ lua_pushinteger(L,userdata_size);
+ lua_call( L, 3, 0); // ... mt
STACK_MID( L, 1);
}
}
@@ -1677,15 +1673,11 @@
lookup_table( L2, L, i, mode_, upName_); // ... mt
// __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with
lua_getfield( L2, -1, "__lanesclone"); // ... mt __lanesclone
- lua_pushvalue( L2, -1); // ... mt __lanesclone __lanesclone
// 'i' slot is the closure, but from now on it is the actual userdata
i = lua_gettop( L);
source = lua_touserdata( L, -1);
// call the cloning function with 1 argument, should return the number of bytes to allocate for the clone
- lua_pushlightuserdata( L2, source); // ... mt __lanesclone __lanesclone source
- lua_call( L2, 1, 1); // ... mt __lanesclone size
- userdata_size = (size_t) lua_tointeger( L2, -1); // ... mt __lanesclone size
- lua_pop( L2, 1); // ... mt __lanesclone
+ userdata_size = lua_objlen(L,-1);
{
// extract uservalues (don't transfer them yet)
int uvi = 0;
@@ -1723,7 +1715,8 @@
lua_replace( L2, -3); // ... u __lanesclone
lua_pushlightuserdata( L2, clone); // ... u __lanesclone clone
lua_pushlightuserdata( L2, source); // ... u __lanesclone clone source
- lua_call( L2, 2, 0); // ... u
+ lua_pushinteger( L2, userdata_size); // ... u __lanesclone clone source
+ lua_call( L2, 3, 0); // ... u
}
else
{
By doing this there is no need to call __lanesclone to get userdata_size and we can pass userdata_size as third argument to __lanesclone, so a generic __lanesclone implementation could be:
int luaU_lanesclone( lua_State* L)
{
switch( lua_gettop( L))
{
case 3:
{
void*self = lua_touserdata( L, 1);
void*from = lua_touserdata( L, 2);
int userdata_size=lua_tointeger(L,3);
memcpy(self,from,userdata_size);
return 0;
}
default:
(void) luaL_error( L, "Lanes called luaU_lanesclone with unexpected parameters");
}
return 0;
}
Of course this can be specializes, if memcpy is not good enough for the data inside the userdata object, but for plain old c struchtures, this is more than sufficient.
Please review the change, your feedback is welcome
Looks good to me, I'll give it a try. But we agree that this is an API-breaking change.
Looks good to me, I'll give it a try. But we agree that this is an API-breaking change. However, since lua_objlen was renamed lua_rawlen in Lua 5.2 I have to take care to keep compatibility with all current supported versions.
FYI: We are using lanes on an embedded arm-system (ARMv7) with LuaJIT 2.0.5 and the patched lanes-3.15.1 works like a charm
Give a try to 2c0000d.
I'm quite busy on the job, will try next week. Thanks & Regards
I've fixed more little things related to the way I use the memory allocator in conjunction with LuaJIT. Hopefully it should run fine now. I've tested a few of the test scripts with LuaJIT 2.0.5 and 2.1.0-beta3 as well as PUC-Lua, all seems fine now.