diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp index 6f32f8fd1..ee2922754 100644 --- a/Source/Engine/Scripting/Scripting.cpp +++ b/Source/Engine/Scripting/Scripting.cpp @@ -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 _objectsDictionary(1024 * 16); +#else Dictionary _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}", (uint32)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 @@ -683,10 +726,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 +769,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 +813,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}", (uint32)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 +860,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}", (uint32)obj, String(ScriptingObjectData(obj).TypeName)); +#endif _objectsDictionary.Add(obj->GetID(), obj); } @@ -826,6 +888,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}", (uint32)obj, String(ScriptingObjectData(obj).TypeName)); +#endif _objectsDictionary.Remove(obj->GetID()); } diff --git a/Source/Engine/Scripting/ScriptingObject.cpp b/Source/Engine/Scripting/ScriptingObject.cpp index 11d6e43e0..9d2320d7f 100644 --- a/Source/Engine/Scripting/ScriptingObject.cpp +++ b/Source/Engine/Scripting/ScriptingObject.cpp @@ -276,6 +276,10 @@ void PersistentScriptingObject::OnManagedInstanceDeleted() _gcHandle = 0; } + // Unregister object + if (IsRegistered()) + UnregisterObject(); + // But do not delete itself } @@ -501,11 +505,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?) @@ -544,7 +543,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);