Fix inefficient InvalidateObjects

This commit is contained in:
Rochet2
2018-04-25 21:54:18 +03:00
parent 476cdcd2c3
commit 00ba8e518c
3 changed files with 23 additions and 52 deletions

View File

@@ -67,7 +67,7 @@ public:
// Get wrapped object pointer
void* GetObj() const { return object; }
// Returns whether the object is valid or not
bool IsValid() const { return _isvalid; }
bool IsValid() const { return !callstackid || callstackid == sEluna->GetCallstackId(); }
// Returns whether the object can be invalidated or not
bool CanInvalidate() const { return _invalidate; }
// Returns pointer to the wrapped object's type name
@@ -84,7 +84,13 @@ public:
void SetValid(bool valid)
{
ASSERT(!valid || (valid && object));
_isvalid = valid;
if (valid)
if (CanInvalidate())
callstackid = sEluna->GetCallstackId();
else
callstackid = 0;
else
callstackid = 1;
}
// Sets whether the pointer will be invalidated at end of calls
void SetValidation(bool invalidate)
@@ -95,11 +101,11 @@ public:
void Invalidate()
{
if (CanInvalidate())
_isvalid = false;
callstackid = 1;
}
private:
bool _isvalid;
uint64 callstackid;
bool _invalidate;
void* object;
const char* type_name;
@@ -253,31 +259,11 @@ public:
return 1;
}
void* obj_voidptr = static_cast<void*>(const_cast<T*>(obj));
lua_pushstring(L, ELUNA_OBJECT_STORE);
lua_rawget(L, LUA_REGISTRYINDEX);
ASSERT(lua_istable(L, -1));
lua_pushlightuserdata(L, obj_voidptr);
lua_rawget(L, -2);
if (ElunaObject* elunaObj = Eluna::CHECKTYPE(L, -1, tname, false))
{
// set userdata valid
elunaObj->SetValid(true);
// remove userdata_table, leave userdata
lua_remove(L, -2);
return 1;
}
lua_pop(L, 1);
// left userdata_table in stack
// Create new userdata
ElunaObject** ptrHold = static_cast<ElunaObject**>(lua_newuserdata(L, sizeof(ElunaObject*)));
if (!ptrHold)
{
ELUNA_LOG_ERROR("%s could not create new userdata", tname);
lua_pop(L, 2);
lua_pushnil(L);
return 1;
}
@@ -289,16 +275,11 @@ public:
if (!lua_istable(L, -1))
{
ELUNA_LOG_ERROR("%s missing metatable", tname);
lua_pop(L, 3);
lua_pop(L, 2);
lua_pushnil(L);
return 1;
}
lua_setmetatable(L, -2);
lua_pushlightuserdata(L, obj_voidptr);
lua_pushvalue(L, -2);
lua_rawset(L, -4);
lua_remove(L, -2);
return 1;
}
@@ -396,7 +377,7 @@ public:
};
template<typename T>
ElunaObject::ElunaObject(T * obj, bool manageMemory) : _isvalid(false), _invalidate(!manageMemory), object(obj), type_name(ElunaTemplate<T>::tname)
ElunaObject::ElunaObject(T * obj, bool manageMemory) : callstackid(1), _invalidate(!manageMemory), object(obj), type_name(ElunaTemplate<T>::tname)
{
SetValid(true);
}

View File

@@ -232,14 +232,6 @@ void Eluna::OpenLua()
// Register methods and functions
RegisterFunctions(this);
// Create hidden table with weak values
lua_newtable(L);
lua_newtable(L);
lua_pushstring(L, "v");
lua_setfield(L, -2, "__mode");
lua_setmetatable(L, -2);
lua_setfield(L, LUA_REGISTRYINDEX, ELUNA_OBJECT_STORE);
// Set lua require folder paths (scripts folder structure)
lua_getglobal(L, "package");
lua_pushstring(L, lua_requirepath.c_str());
@@ -526,18 +518,8 @@ void Eluna::RunScripts()
void Eluna::InvalidateObjects()
{
lua_pushstring(L, ELUNA_OBJECT_STORE);
lua_rawget(L, LUA_REGISTRYINDEX);
ASSERT(lua_istable(L, -1));
lua_pushnil(L);
while (lua_next(L, -2))
{
if (ElunaObject* elunaObj = CHECKOBJ<ElunaObject>(L, -1, false))
elunaObj->Invalidate();
lua_pop(L, 1);
}
lua_pop(L, 1);
++callstackid;
ASSERT(callstackid, "Callstackid overflow");
}
void Eluna::Report(lua_State* _L)

View File

@@ -111,7 +111,6 @@ struct LuaScript
std::string modulepath;
};
#define ELUNA_OBJECT_STORE "Eluna Object Store"
#define ELUNA_STATE_PTR "Eluna State Ptr"
#define LOCK_ELUNA Eluna::Guard __guard(Eluna::GetLock())
@@ -140,6 +139,14 @@ private:
// lua path variable for require() function
static std::string lua_requirepath;
// A counter for lua event stacks that occur (see event_level).
// This is used to determine whether an object belongs to the current call stack or not.
// 0 is reserved for always belonging to the call stack
// 1 is reserved for a non valid callstackid
uint64 callstackid = 2;
// A counter for the amount of nested events. When the event_level
// reaches 0 we are about to return back to C++. At this point the
// objects used during the event stack are invalidated.
uint32 event_level;
// When a hook pushes arguments to be passed to event handlers,
// this is used to keep track of how many arguments were pushed.
@@ -312,6 +319,7 @@ public:
bool ShouldReload() const { return reload; }
bool IsEnabled() const { return enabled && IsInitialized(); }
bool HasLuaState() const { return L != NULL; }
uint64 GetCallstackId() const { return callstackid; }
int Register(lua_State* L, uint8 reg, uint32 entry, uint64 guid, uint32 instanceId, uint32 event_id, int functionRef, uint32 shots);
// Checks