Merge branch 'master' into 1.1

# Conflicts:
#	Source/Engine/Content/JsonAsset.h
#	Source/Engine/Core/Config/Settings.h
This commit is contained in:
Wojtek Figat
2021-02-15 10:40:59 +01:00
77 changed files with 1111 additions and 531 deletions

View File

@@ -56,7 +56,45 @@ namespace
MDomain* _monoRootDomain = nullptr;
MDomain* _monoScriptsDomain = nullptr;
CriticalSection _objectsLocker;
#define USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING 0
#if USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING
struct ScriptingObjectData
{
ScriptingObject* Ptr;
StringAnsi TypeName;
ScriptingObjectData()
{
Ptr = nullptr;
}
ScriptingObjectData(ScriptingObject* ptr)
{
Ptr = ptr;
if (ptr && ptr->GetTypeHandle() && ptr->GetTypeHandle().TypeIndex < ptr->GetTypeHandle().Module->Types.Count())
TypeName = ptr->GetType().Fullname;
}
ScriptingObject* operator->() const
{
return Ptr;
}
explicit operator ScriptingObject*()
{
return Ptr;
}
operator ScriptingObject*() const
{
return Ptr;
}
};
Dictionary<Guid, ScriptingObjectData> _objectsDictionary(1024 * 16);
#else
Dictionary<Guid, ScriptingObject*> _objectsDictionary(1024 * 16);
#endif
bool _isEngineAssemblyLoaded = false;
bool _hasGameModulesLoaded = false;
MMethod* _method_Update = nullptr;
@@ -456,6 +494,9 @@ void Scripting::Release()
for (auto i = _objectsDictionary.Begin(); i.IsNotEnd(); ++i)
{
auto obj = i->Value;
#if USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING
LOG(Info, "[OnScriptingDispose] obj = 0x{0:x}, {1}", (uint64)obj.Ptr, String(obj.TypeName));
#endif
obj->OnScriptingDispose();
}
}
@@ -498,7 +539,9 @@ void Scripting::Release()
}
}
#if !USE_SINGLE_DOMAIN
MCore::Instance()->UnloadDomain("Scripts Domain");
#endif
}
#if USE_EDITOR
@@ -546,6 +589,24 @@ void Scripting::Reload(bool canTriggerSceneReload)
MCore::GC::Collect();
MCore::GC::WaitForPendingFinalizers();
// Destroy objects from game assemblies (eg. not released objects that might crash if persist in memory after reload)
_objectsLocker.Lock();
{
const auto flaxModule = GetBinaryModuleFlaxEngine();
for (auto i = _objectsDictionary.Begin(); i.IsNotEnd(); ++i)
{
auto obj = i->Value;
if (obj->GetTypeHandle().Module == flaxModule)
continue;
#if USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING
LOG(Info, "[OnScriptingDispose] obj = 0x{0:x}, {1}", (uint64)obj.Ptr, String(obj.TypeName));
#endif
obj->OnScriptingDispose();
}
}
_objectsLocker.Unlock();
// Unload all game modules
LOG(Info, "Unloading game binary modules");
auto modules = BinaryModule::GetModules();
@@ -683,10 +744,18 @@ ScriptingObject* Scripting::FindObject(Guid id, MClass* type)
}
// Try to find it
#if USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING
ScriptingObjectData data;
_objectsLocker.Lock();
_objectsDictionary.TryGet(id, data);
_objectsLocker.Unlock();
auto result = data.Ptr;
#else
ScriptingObject* result = nullptr;
_objectsLocker.Lock();
_objectsDictionary.TryGet(id, result);
_objectsLocker.Unlock();
#endif
if (result)
{
// Check type
@@ -718,11 +787,20 @@ ScriptingObject* Scripting::TryFindObject(Guid id, MClass* type)
}
// Try to find it
#if USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING
ScriptingObjectData data;
_objectsLocker.Lock();
_objectsDictionary.TryGet(id, data);
_objectsLocker.Unlock();
auto result = data.Ptr;
#else
ScriptingObject* result = nullptr;
_objectsLocker.Lock();
_objectsDictionary.TryGet(id, result);
_objectsLocker.Unlock();
#endif
// Check type
if (result && !result->Is(type))
{
result = nullptr;
@@ -753,28 +831,23 @@ ScriptingObject* Scripting::FindObject(const MonoObject* managedInstance)
void Scripting::OnManagedInstanceDeleted(ScriptingObject* obj)
{
PROFILE_CPU_NAMED("OnManagedInstanceDeleted");
ASSERT(obj);
PROFILE_CPU_NAMED("OnManagedInstanceDeleted");
// This is sometimes crashing, probably rawPtr field is not cleared in some cases
// TODO: use faster callback without crashing
//obj->OnManagedInstanceDeleted();
// Validate if object still exists
bool isValid;
{
ScopeLock lock(_objectsLocker);
isValid = _objectsDictionary.ContainsValue(obj);
}
if (isValid)
_objectsLocker.Lock();
if (_objectsDictionary.ContainsValue(obj))
{
#if USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING
LOG(Info, "[OnManagedInstanceDeleted] obj = 0x{0:x}, {1}", (uint64)obj, String(ScriptingObjectData(obj).TypeName));
#endif
obj->OnManagedInstanceDeleted();
}
else
{
//LOG(Warning, "Object finalization called for already removed object (address={0:x})", (uint64)obj);
}
_objectsLocker.Unlock();
}
bool Scripting::HasGameModulesLoaded()
@@ -805,18 +878,25 @@ void Scripting::RegisterObject(ScriptingObject* obj)
//ASSERT(!_objectsDictionary.ContainsValue(obj));
#if ENABLE_ASSERTION
ScriptingObject* other = nullptr;
#if USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING
ScriptingObjectData other;
if (_objectsDictionary.TryGet(obj->GetID(), other))
#else
ScriptingObject* other;
if (_objectsDictionary.TryGet(obj->GetID(), other))
#endif
{
// Something went wrong...
LOG(Error, "Objects registry already contains object with ID={0}! Trying to register object {1} (type '{2}').", obj->GetID(), obj->ToString(), String(obj->GetClass()->GetFullName()));
LOG(Error, "Objects registry already contains object with ID={0} (type '{3}')! Trying to register object {1} (type '{2}').", obj->GetID(), obj->ToString(), String(obj->GetClass()->GetFullName()), String(other->GetClass()->GetFullName()));
_objectsDictionary.Remove(obj->GetID());
}
#else
ASSERT(!_objectsDictionary.ContainsKey(obj->_id));
#endif
#if USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING
LOG(Info, "[RegisterObject] obj = 0x{0:x}, {1}", (uint64)obj, String(ScriptingObjectData(obj).TypeName));
#endif
_objectsDictionary.Add(obj->GetID(), obj);
}
@@ -826,6 +906,9 @@ void Scripting::UnregisterObject(ScriptingObject* obj)
//ASSERT(!obj->_id.IsValid() || _objectsDictionary.ContainsValue(obj));
#if USE_OBJECTS_DISPOSE_CRASHES_DEBUGGING
LOG(Info, "[UnregisterObject] obj = 0x{0:x}, {1}", (uint64)obj, String(ScriptingObjectData(obj).TypeName));
#endif
_objectsDictionary.Remove(obj->GetID());
}

View File

@@ -11,7 +11,6 @@
#include "ManagedCLR/MClass.h"
#include "ManagedCLR/MUtils.h"
#include "ManagedCLR/MField.h"
#include "ManagedCLR/MUtils.h"
#if PLATFORM_LINUX
#include "ManagedCLR/MCore.h"
#endif
@@ -515,11 +514,6 @@ public:
obj->RegisterObject();
}
static void ManagedInstanceDeleted(ScriptingObject* obj)
{
Scripting::OnManagedInstanceDeleted(obj);
}
static void Destroy(ManagedScriptingObject* obj, float timeLeft)
{
// Use scaled game time for removing actors/scripts by the user (maybe expose it to the api?)
@@ -558,7 +552,7 @@ public:
ADD_INTERNAL_CALL("FlaxEngine.Object::Internal_Create1", &Create1);
ADD_INTERNAL_CALL("FlaxEngine.Object::Internal_Create2", &Create2);
ADD_INTERNAL_CALL("FlaxEngine.Object::Internal_ManagedInstanceCreated", &ManagedInstanceCreated);
ADD_INTERNAL_CALL("FlaxEngine.Object::Internal_ManagedInstanceDeleted", &ManagedInstanceDeleted);
ADD_INTERNAL_CALL("FlaxEngine.Object::Internal_ManagedInstanceDeleted", &Scripting::OnManagedInstanceDeleted);
ADD_INTERNAL_CALL("FlaxEngine.Object::Internal_Destroy", &Destroy);
ADD_INTERNAL_CALL("FlaxEngine.Object::Internal_GetTypeName", &GetTypeName);
ADD_INTERNAL_CALL("FlaxEngine.Object::Internal_FindObject", &FindObject);