mirror of
https://github.com/love2d/love.git
synced 2026-08-15 07:41:11 +02:00
Added Object:release. Calling it is the equivalent of removing all Lua-side references to an object and doing a full garbage collection cycle (thus deleting the object from memory if nothing else in LÖVE's code is referencing it).
Any attempt to call a method on the object after it has been released will result in an error. Object:release() returns true if it was successful, or false if not (if it has already been released previously). --HG-- branch : minor
This commit is contained in:
@@ -85,7 +85,8 @@ Variant::Variant(love::Type udatatype, void *userdata)
|
||||
{
|
||||
Proxy *p = (Proxy *) userdata;
|
||||
data.userdata = p->object;
|
||||
p->object->retain();
|
||||
if (p->object)
|
||||
p->object->retain();
|
||||
}
|
||||
else
|
||||
data.userdata = userdata;
|
||||
@@ -105,7 +106,7 @@ Variant::Variant(const Variant &v)
|
||||
{
|
||||
if (type == STRING)
|
||||
data.string->retain();
|
||||
else if (type == FUSERDATA)
|
||||
else if (type == FUSERDATA && data.userdata != nullptr)
|
||||
((love::Object *) data.userdata)->retain();
|
||||
else if (type == TABLE)
|
||||
data.table->retain();
|
||||
@@ -127,7 +128,8 @@ Variant::~Variant()
|
||||
data.string->release();
|
||||
break;
|
||||
case FUSERDATA:
|
||||
((love::Object *) data.userdata)->release();
|
||||
if (data.userdata != nullptr)
|
||||
((love::Object *) data.userdata)->release();
|
||||
break;
|
||||
case TABLE:
|
||||
data.table->release();
|
||||
@@ -141,14 +143,14 @@ Variant &Variant::operator = (const Variant &v)
|
||||
{
|
||||
if (v.type == STRING)
|
||||
v.data.string->retain();
|
||||
else if (v.type == FUSERDATA)
|
||||
else if (v.type == FUSERDATA && v.data.userdata != nullptr)
|
||||
((love::Object *) v.data.userdata)->retain();
|
||||
else if (v.type == TABLE)
|
||||
v.data.table->retain();
|
||||
|
||||
if (type == STRING)
|
||||
data.string->release();
|
||||
else if (type == FUSERDATA)
|
||||
else if (type == FUSERDATA && v.data.userdata != nullptr)
|
||||
((love::Object *) v.data.userdata)->release();
|
||||
else if (type == TABLE)
|
||||
data.table->release();
|
||||
|
||||
+38
-2
@@ -42,7 +42,11 @@ namespace love
|
||||
static int w__gc(lua_State *L)
|
||||
{
|
||||
Proxy *p = (Proxy *) lua_touserdata(L, 1);
|
||||
p->object->release();
|
||||
if (p->object != nullptr)
|
||||
{
|
||||
p->object->release();
|
||||
p->object = nullptr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -72,7 +76,35 @@ static int w__eq(lua_State *L)
|
||||
{
|
||||
Proxy *p1 = (Proxy *)lua_touserdata(L, 1);
|
||||
Proxy *p2 = (Proxy *)lua_touserdata(L, 2);
|
||||
luax_pushboolean(L, p1->object == p2->object);
|
||||
luax_pushboolean(L, p1->object == p2->object && p1->object != nullptr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int w__release(lua_State *L)
|
||||
{
|
||||
Proxy *p = (Proxy *) lua_touserdata(L, 1);
|
||||
Object *object = p->object;
|
||||
|
||||
if (object != nullptr)
|
||||
{
|
||||
p->object = nullptr;
|
||||
object->release();
|
||||
|
||||
// Fetch the registry table of instantiated objects.
|
||||
luax_getregistry(L, REGISTRY_OBJECTS);
|
||||
|
||||
if (lua_istable(L, -1))
|
||||
{
|
||||
// loveobjects[object] = nil
|
||||
lua_pushlightuserdata(L, object);
|
||||
lua_pushnil(L);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
luax_pushboolean(L, object != nullptr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -329,6 +361,10 @@ int luax_register_type(lua_State *L, love::Type type, const char *name, ...)
|
||||
lua_pushcfunction(L, w__typeOf);
|
||||
lua_setfield(L, -2, "typeOf");
|
||||
|
||||
// Add release
|
||||
lua_pushcfunction(L, w__release);
|
||||
lua_setfield(L, -2, "release");
|
||||
|
||||
va_list fs;
|
||||
va_start(fs, name);
|
||||
for (const luaL_Reg *f = va_arg(fs, const luaL_Reg *); f; f = va_arg(fs, const luaL_Reg *))
|
||||
|
||||
@@ -452,6 +452,9 @@ T *luax_checktype(lua_State *L, int idx, love::Type type)
|
||||
luax_typerror(L, idx, name);
|
||||
}
|
||||
|
||||
if (u->object == nullptr)
|
||||
luaL_error(L, "Cannot use object after it has been released.");
|
||||
|
||||
return (T *)u->object;
|
||||
}
|
||||
|
||||
@@ -513,7 +516,12 @@ T *luax_optmodule(lua_State *L, love::Type type)
|
||||
template <typename T>
|
||||
T *luax_totype(lua_State *L, int idx, love::Type /*type*/)
|
||||
{
|
||||
return (T *)(((Proxy *)lua_touserdata(L, idx))->object);
|
||||
T *o = (T *)(((Proxy *)lua_touserdata(L, idx))->object);
|
||||
|
||||
if (o == nullptr)
|
||||
luaL_error(L, "Cannot use object after it has been released.");
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
Type luax_type(lua_State *L, int idx);
|
||||
|
||||
@@ -161,6 +161,7 @@ local _getWidth = ImageData.getWidth
|
||||
local _getHeight = ImageData.getHeight
|
||||
local _getDimensions = ImageData.getDimensions
|
||||
local _getFormat = ImageData.getFormat
|
||||
local _release = ImageData.release
|
||||
|
||||
-- Table which holds ImageData objects as keys, and information about the objects
|
||||
-- as values. Uses weak keys so the ImageData objects can still be GC'd properly.
|
||||
@@ -270,5 +271,10 @@ function ImageData:getFormat()
|
||||
return objectcache[self].format
|
||||
end
|
||||
|
||||
function ImageData:release()
|
||||
objectcache[self] = nil
|
||||
return _release(self)
|
||||
end
|
||||
|
||||
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
|
||||
--)luastring"--"
|
||||
|
||||
@@ -126,7 +126,7 @@ static FFI_RandomGenerator ffifuncs =
|
||||
[](Proxy *p) -> double // random()
|
||||
{
|
||||
// FIXME: We need better type-checking...
|
||||
if (p == nullptr || !typeFlags[p->type][MATH_RANDOM_GENERATOR_ID])
|
||||
if (p == nullptr || p->object == nullptr || !typeFlags[p->type][MATH_RANDOM_GENERATOR_ID])
|
||||
return 0.0;
|
||||
|
||||
RandomGenerator *rng = (RandomGenerator *) p->object;
|
||||
|
||||
@@ -72,6 +72,8 @@ local ffifuncs = ffi.cast("FFI_RandomGenerator *", ffifuncspointer)
|
||||
-- Overwrite some regular love.math functions with FFI implementations.
|
||||
|
||||
function RandomGenerator:random(l, u)
|
||||
-- TODO: This should ideally be handled inside ffifuncs.random
|
||||
if self == nil then error("bad argument #1 to 'random' (RandomGenerator expected, got no value)", 2) end
|
||||
local r = tonumber(ffifuncs.random(self))
|
||||
return getrandom(r, l, u)
|
||||
end
|
||||
|
||||
@@ -46,6 +46,7 @@ local _getSampleCount = SoundData.getSampleCount
|
||||
local _getSampleRate = SoundData.getSampleRate
|
||||
local _getChannels = SoundData.getChannels
|
||||
local _getDuration = SoundData.getDuration
|
||||
local _release = SoundData.release
|
||||
|
||||
-- Table which holds SoundData objects as keys, and information about the objects
|
||||
-- as values. Uses weak keys so the SoundData objects can still be GC'd properly.
|
||||
@@ -133,5 +134,10 @@ function SoundData:getDuration()
|
||||
return objectcache[self].duration
|
||||
end
|
||||
|
||||
function SoundData:release()
|
||||
objectcache[self] = nil
|
||||
return _release(self)
|
||||
end
|
||||
|
||||
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
|
||||
--)luastring"--"
|
||||
|
||||
Reference in New Issue
Block a user