|
@@ -93,11 +93,42 @@ static int w__eq(lua_State *L)
|
|
return 1;
|
|
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.
|
|
// For use with the love object pointer -> Proxy pointer registry.
|
|
// Using the pointer directly via lightuserdata would be ideal, but LuaJIT
|
|
// 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
|
|
// love objects should be allocated on the heap, and thus are subject
|
|
// to the alignment rules of operator new / malloc. Lua numbers (doubles)
|
|
// 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;
|
|
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)
|
|
static int w__release(lua_State *L)
|
|
@@ -141,8 +181,8 @@ static int w__release(lua_State *L)
|
|
if (lua_istable(L, -1))
|
|
if (lua_istable(L, -1))
|
|
{
|
|
{
|
|
// loveobjects[object] = nil
|
|
// 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_pushnil(L);
|
|
lua_settable(L, -3);
|
|
lua_settable(L, -3);
|
|
}
|
|
}
|
|
@@ -605,10 +645,10 @@ void luax_pushtype(lua_State *L, love::Type &type, love::Object *object)
|
|
return luax_rawnewtype(L, type, 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.
|
|
// Get the value of loveobjects[object] on the stack.
|
|
- lua_pushnumber(L, objectkey);
|
|
|
|
|
|
+ luax_pushloveobjectkey(L, objectkey);
|
|
lua_gettable(L, -2);
|
|
lua_gettable(L, -2);
|
|
|
|
|
|
// If the Proxy userdata isn't in the instantiated types table yet, add it.
|
|
// If the Proxy userdata isn't in the instantiated types table yet, add it.
|
|
@@ -618,7 +658,7 @@ void luax_pushtype(lua_State *L, love::Type &type, love::Object *object)
|
|
|
|
|
|
luax_rawnewtype(L, type, object);
|
|
luax_rawnewtype(L, type, object);
|
|
|
|
|
|
- lua_pushnumber(L, objectkey);
|
|
|
|
|
|
+ luax_pushloveobjectkey(L, objectkey);
|
|
lua_pushvalue(L, -2);
|
|
lua_pushvalue(L, -2);
|
|
|
|
|
|
// loveobjects[object] = Proxy.
|
|
// loveobjects[object] = Proxy.
|