mirror of
https://github.com/love2d/love.git
synced 2026-08-16 00:02:12 +02:00
Changed luax_pushtype to retain the pushed object itself, but only if the object isn't in the Lua state already.
Previously, calling e.g. love.graphics.getFont() 10,000 times would retain the object 10,000 times (and release it 10,000 times when the Font object was garbage-collected in the Lua state.) Now it will only retain it once and release it once.
This commit is contained in:
@@ -226,7 +226,6 @@ void Variant::toLua(lua_State *L)
|
||||
{
|
||||
const char *name = NULL;
|
||||
love::types.find(udatatype, name);
|
||||
((love::Object *) data.userdata)->retain();
|
||||
luax_pushtype(L, name, flags, (love::Object *) data.userdata);
|
||||
}
|
||||
else
|
||||
|
||||
+20
-44
@@ -36,8 +36,7 @@
|
||||
namespace love
|
||||
{
|
||||
|
||||
static thread::Mutex *gcmutex = 0;
|
||||
void *_gcmutex = 0;
|
||||
static thread::Mutex *gcmutex = nullptr;
|
||||
|
||||
/**
|
||||
* Called when an object is collected. The object is released
|
||||
@@ -46,25 +45,16 @@ void *_gcmutex = 0;
|
||||
static int w__gc(lua_State *L)
|
||||
{
|
||||
if (!gcmutex)
|
||||
{
|
||||
gcmutex = thread::newMutex();
|
||||
_gcmutex = (void *) gcmutex;
|
||||
}
|
||||
|
||||
Proxy *p = (Proxy *)lua_touserdata(L, 1);
|
||||
Object *t = (Object *)p->data;
|
||||
Proxy *p = (Proxy *) lua_touserdata(L, 1);
|
||||
Object *object = (Object *) p->data;
|
||||
|
||||
thread::Lock lock(gcmutex);
|
||||
|
||||
int numretains = p->retains;
|
||||
if (numretains >= 0)
|
||||
numretains = std::min(numretains, t->getReferenceCount());
|
||||
if (p->own)
|
||||
object->release();
|
||||
|
||||
for (int i = numretains; i > 0; i--)
|
||||
t->release();
|
||||
|
||||
// Signal that this Proxy is dead.
|
||||
p->retains = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -228,7 +218,7 @@ int luax_register_module(lua_State *L, const WrappedModule &m)
|
||||
luax_insistregistry(L, REGISTRY_MODULES);
|
||||
|
||||
Proxy *p = (Proxy *)lua_newuserdata(L, sizeof(Proxy));
|
||||
p->retains = 1;
|
||||
p->own = true;
|
||||
p->data = m.module;
|
||||
p->flags = m.flags;
|
||||
|
||||
@@ -394,20 +384,26 @@ int luax_register_searcher(lua_State *L, lua_CFunction f, int pos)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void luax_rawnewtype(lua_State *L, const char *name, bits flags, love::Object *data, bool own)
|
||||
void luax_rawnewtype(lua_State *L, const char *name, bits flags, love::Object *object, bool own)
|
||||
{
|
||||
Proxy *u = (Proxy *)lua_newuserdata(L, sizeof(Proxy));
|
||||
|
||||
u->data = (void *) data;
|
||||
if (own)
|
||||
object->retain();
|
||||
|
||||
u->data = (void *) object;
|
||||
u->flags = flags;
|
||||
u->retains = own ? 1 : 0;
|
||||
u->own = own;
|
||||
|
||||
luaL_newmetatable(L, name);
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
|
||||
void luax_pushtype(lua_State *L, const char *name, bits flags, love::Object *data, bool own)
|
||||
void luax_pushtype(lua_State *L, const char *name, bits flags, love::Object *object, bool own)
|
||||
{
|
||||
if (object == nullptr)
|
||||
lua_pushnil(L);
|
||||
|
||||
// Fetch the registry table of instantiated types.
|
||||
luax_getregistry(L, REGISTRY_TYPES);
|
||||
|
||||
@@ -415,11 +411,11 @@ void luax_pushtype(lua_State *L, const char *name, bits flags, love::Object *dat
|
||||
if (!lua_istable(L, -1))
|
||||
{
|
||||
lua_pop(L, 1);
|
||||
return luax_rawnewtype(L, name, flags, data, own);
|
||||
return luax_rawnewtype(L, name, flags, object, own);
|
||||
}
|
||||
|
||||
// Get the value of lovetypes[data] on the stack.
|
||||
lua_pushlightuserdata(L, (void *) data);
|
||||
lua_pushlightuserdata(L, (void *) object);
|
||||
lua_gettable(L, -2);
|
||||
|
||||
// If the Proxy userdata isn't in the instantiated types table yet, add it.
|
||||
@@ -427,38 +423,18 @@ void luax_pushtype(lua_State *L, const char *name, bits flags, love::Object *dat
|
||||
{
|
||||
lua_pop(L, 1);
|
||||
|
||||
luax_rawnewtype(L, name, flags, data, own);
|
||||
luax_rawnewtype(L, name, flags, object, own);
|
||||
|
||||
lua_pushlightuserdata(L, (void *) data);
|
||||
lua_pushlightuserdata(L, (void *) object);
|
||||
lua_pushvalue(L, -2);
|
||||
|
||||
// lovetypes[data] = Proxy.
|
||||
lua_settable(L, -4);
|
||||
|
||||
// Remove the lovetypes table from the stack.
|
||||
lua_remove(L, -2);
|
||||
|
||||
// The Proxy userdata remains at the top of the stack.
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the lovetypes table from the stack.
|
||||
lua_remove(L, -2);
|
||||
|
||||
// If the object should be released on GC and we already have a stored
|
||||
// Proxy, we should tell the Proxy that the object was retained again.
|
||||
if (own)
|
||||
{
|
||||
Proxy *p = (Proxy *) lua_touserdata(L, -1);
|
||||
|
||||
thread::EmptyLock lock;
|
||||
if (gcmutex)
|
||||
lock.setLock(gcmutex);
|
||||
|
||||
if (p->retains >= 0)
|
||||
++(p->retains);
|
||||
}
|
||||
|
||||
// Keep the Proxy userdata on the stack.
|
||||
}
|
||||
|
||||
|
||||
+13
-12
@@ -43,9 +43,6 @@ namespace love
|
||||
class Module;
|
||||
class Reference;
|
||||
|
||||
// Exposed mutex of the GC
|
||||
extern void *_gcmutex;
|
||||
|
||||
/**
|
||||
* Registries represent special tables which can be accessed with
|
||||
* luax_insistregistry and luax_getregistry.
|
||||
@@ -71,8 +68,8 @@ struct Proxy
|
||||
// The light userdata (pointer to the love::Object).
|
||||
void *data;
|
||||
|
||||
// The number of times release() should be called on GC.
|
||||
int retains;
|
||||
// Whether release() should be called on GC.
|
||||
bool own;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -271,27 +268,31 @@ int luax_register_searcher(lua_State *L, lua_CFunction f, int pos = -1);
|
||||
/**
|
||||
* Pushes a Lua representation of the given object onto the stack, creating and
|
||||
* storing the Lua representation in a weak table if it doesn't exist yet.
|
||||
* NOTE: If own is true, the object will be retained by Lua.
|
||||
* @param L The Lua state.
|
||||
* @param name The name of the type. This must match the name used with luax_register_type.
|
||||
* @param flags The type information of the object.
|
||||
* @param data The pointer to the actual object.
|
||||
* @param own Set this to true (default) if the object should be released upon garbage collection.
|
||||
* @param object The pointer to the actual object.
|
||||
* @param own Set this to true (default) if the object should be retained by
|
||||
* Lua and released upon garbage collection.
|
||||
**/
|
||||
void luax_pushtype(lua_State *L, const char *name, bits flags, love::Object *data, bool own = true);
|
||||
void luax_pushtype(lua_State *L, const char *name, bits flags, love::Object *object, bool own = true);
|
||||
|
||||
/**
|
||||
* Creates a new Lua representation of the given object *without* checking if it
|
||||
* exists yet, and *without* storing it in a weak table.
|
||||
* This should only be used when performance is an extreme concern and the
|
||||
* object is not ever expected to be pushed to Lua again, as it prevents the
|
||||
* Lua-side objects from working in all cases when used as keys in tables.
|
||||
* Lua-side objects from working in some cases when used as keys in tables.
|
||||
* NOTE: if own is true, the object will be retained by Lua.
|
||||
* @param L The Lua state.
|
||||
* @param name The name of the type. This must match the name used with luax_register_type.
|
||||
* @param flags The type information of the object.
|
||||
* @param data The pointer to the actual object.
|
||||
* @param own Set this to true (default) if the object should be released upon garbage collection.
|
||||
* @param object The pointer to the actual object.
|
||||
* @param own Set this to true (default) if the object should be retained by
|
||||
* Lua and released upon garbage collection.
|
||||
**/
|
||||
void luax_rawnewtype(lua_State *L, const char *name, bits flags, love::Object *data, bool own = true);
|
||||
void luax_rawnewtype(lua_State *L, const char *name, bits flags, love::Object *object, bool own = true);
|
||||
|
||||
/**
|
||||
* Checks whether the value at idx is a certain type.
|
||||
|
||||
Reference in New Issue
Block a user