Merge branch 'master' into 12.0-development

This commit is contained in:
Alex Szpakowski
2021-02-14 14:45:21 -04:00
4 changed files with 523 additions and 34 deletions
+52 -12
View File
@@ -93,11 +93,42 @@ static int w__eq(lua_State *L)
return 1;
}
typedef uint64 ObjectKey;
static bool luax_isfulllightuserdatasupported(lua_State *L)
{
// LuaJIT prior to commit e9af1abec542e6f9851ff2368e7f196b6382a44c doesn't
// support lightuserdata > 48 bits. This is not a problem with Android,
// Windows, macOS, and iOS as they'll use updated LuaJIT or won't use
// pointers > 48 bits, but this is not the case for Linux. So check for
// this capability first!
static bool checked = false;
static bool supported = false;
if (!checked)
{
lua_pushcclosure(L, [](lua_State *L) -> int
{
// Try to push pointer with all bits set.
lua_pushlightuserdata(L, (void *) (~((size_t) 0)));
return 1;
}, 0);
supported = lua_pcall(L, 0, 1, 0) == 0;
checked = true;
lua_pop(L, 1);
}
return supported;
}
// For use with the love object pointer -> Proxy pointer registry.
// Using the pointer directly via lightuserdata would be ideal, but LuaJIT
// cannot use lightuserdata with more than 47 bits whereas some newer arm64
// architectures allow pointers which use more than that.
static lua_Number luax_computeloveobjectkey(lua_State *L, love::Object *object)
// (before a commit to 2.1 in 2020) cannot use lightuserdata with more than 47
// bits whereas some newer arm64 architectures allow pointers which use more
// than that.
static ObjectKey luax_computeloveobjectkey(lua_State *L, love::Object *object)
{
// love objects should be allocated on the heap, and thus are subject
// to the alignment rules of operator new / malloc. Lua numbers (doubles)
@@ -118,11 +149,20 @@ static lua_Number luax_computeloveobjectkey(lua_State *L, love::Object *object)
key >>= shift;
// Make sure our key isn't larger than 2^53.
if (key > 0x20000000000000ULL)
luaL_error(L, "Cannot push love object to Lua: pointer value %p is too large", object);
return (ObjectKey) key;
}
return (lua_Number) key;
static void luax_pushloveobjectkey(lua_State *L, ObjectKey key)
{
// If full 64-bit lightuserdata is supported, always use that. Otherwise,
// if the key is smaller than 2^53 (which is integer precision for double
// datatype), then push number. Otherwise, throw error.
if (luax_isfulllightuserdatasupported(L))
lua_pushlightuserdata(L, (void *) key);
else if (key > 0x20000000000000ULL) // 2^53
luaL_error(L, "Cannot push love object to Lua: pointer value %p is too large", key);
else
lua_pushnumber(L, (lua_Number) key);
}
static int w__release(lua_State *L)
@@ -141,8 +181,8 @@ static int w__release(lua_State *L)
if (lua_istable(L, -1))
{
// loveobjects[object] = nil
lua_Number objectkey = luax_computeloveobjectkey(L, object);
lua_pushnumber(L, objectkey);
ObjectKey objectkey = luax_computeloveobjectkey(L, object);
luax_pushloveobjectkey(L, objectkey);
lua_pushnil(L);
lua_settable(L, -3);
}
@@ -622,10 +662,10 @@ void luax_pushtype(lua_State *L, love::Type &type, love::Object *object)
return luax_rawnewtype(L, type, object);
}
lua_Number objectkey = luax_computeloveobjectkey(L, object);
ObjectKey objectkey = luax_computeloveobjectkey(L, object);
// Get the value of loveobjects[object] on the stack.
lua_pushnumber(L, objectkey);
luax_pushloveobjectkey(L, objectkey);
lua_gettable(L, -2);
// If the Proxy userdata isn't in the instantiated types table yet, add it.
@@ -635,7 +675,7 @@ void luax_pushtype(lua_State *L, love::Type &type, love::Object *object)
luax_rawnewtype(L, type, object);
lua_pushnumber(L, objectkey);
luax_pushloveobjectkey(L, objectkey);
lua_pushvalue(L, -2);
// loveobjects[object] = Proxy.