diff --git a/Source/Engine/Content/Asset.cpp b/Source/Engine/Content/Asset.cpp index 7e994270f..bf6a4216f 100644 --- a/Source/Engine/Content/Asset.cpp +++ b/Source/Engine/Content/Asset.cpp @@ -175,13 +175,16 @@ void Asset::OnDeleteObject() #endif } -void Asset::CreateManaged() +bool Asset::CreateManaged() { // Base - ManagedScriptingObject::CreateManaged(); + if (ManagedScriptingObject::CreateManaged()) + return true; // Managed objects holds a reference to this asset until it will be removed by GC AddReference(); + + return false; } void Asset::DestroyManaged() diff --git a/Source/Engine/Content/Asset.h b/Source/Engine/Content/Asset.h index 3d4ca2789..5267c3afe 100644 --- a/Source/Engine/Content/Asset.h +++ b/Source/Engine/Content/Asset.h @@ -241,7 +241,7 @@ public: // [ManagedScriptingObject] String ToString() const override; void OnDeleteObject() override; - void CreateManaged() override; + bool CreateManaged() override; void DestroyManaged() override; void OnManagedInstanceDeleted() override; void OnScriptingDispose() override; diff --git a/Source/Engine/Scripting/ScriptingObject.cpp b/Source/Engine/Scripting/ScriptingObject.cpp index 8090c529f..c5c6b9dab 100644 --- a/Source/Engine/Scripting/ScriptingObject.cpp +++ b/Source/Engine/Scripting/ScriptingObject.cpp @@ -59,7 +59,8 @@ ScriptingObject::~ScriptingObject() MObject* ScriptingObject::GetManagedInstance() const { #if USE_MONO - return _gcHandle ? mono_gchandle_get_target(_gcHandle) : nullptr; + const int32 handle = Platform::AtomicRead((int32*)&_gcHandle); + return handle ? mono_gchandle_get_target(handle) : nullptr; #else return nullptr; #endif @@ -226,10 +227,6 @@ void ScriptingObject::OnScriptingDispose() MonoObject* ScriptingObject::CreateManagedInternal() { -#if BUILD_DEBUG - ASSERT(!HasManagedInstance()); -#endif - // Get class MClass* monoClass = GetClass(); if (monoClass == nullptr) @@ -302,7 +299,6 @@ void ScriptingObject::DestroyManaged() void ScriptingObject::RegisterObject() { ASSERT(!IsRegistered()); - Flags |= ObjectFlags::IsRegistered; Scripting::RegisterObject(this); } @@ -310,7 +306,6 @@ void ScriptingObject::RegisterObject() void ScriptingObject::UnregisterObject() { ASSERT(IsRegistered()); - Flags &= ~ObjectFlags::IsRegistered; Scripting::UnregisterObject(this); } @@ -378,24 +373,39 @@ ManagedScriptingObject::ManagedScriptingObject(const SpawnParams& params) { } -void ManagedScriptingObject::CreateManaged() +bool ManagedScriptingObject::CreateManaged() { #if USE_MONO MonoObject* managedInstance = CreateManagedInternal(); - if (managedInstance) - { - // Cache the GC handle to the object (used to track the target object because it can be moved in a memory) - _gcHandle = mono_gchandle_new_weakref(managedInstance, false); + if (!managedInstance) + return true; - // Ensure to be registered - if (!IsRegistered()) - RegisterObject(); + // Cache the GC handle to the object (used to track the target object because it can be moved in a memory) + auto handle = mono_gchandle_new_weakref(managedInstance, false); + auto oldHandle = Platform::InterlockedCompareExchange((int32*)&_gcHandle, *(int32*)&handle, 0); + if (*(uint32*)&oldHandle != 0) + { + // Other thread already created the object before + if (const auto monoClass = GetClass()) + { + // Reset managed to unmanaged pointer + const MField* monoUnmanagedPtrField = monoClass->GetField(ScriptingObject_unmanagedPtr); + if (monoUnmanagedPtrField) + { + void* param = nullptr; + monoUnmanagedPtrField->SetValue(managedInstance, ¶m); + } + } + mono_gchandle_free(handle); + return true; } -#else +#endif + // Ensure to be registered if (!IsRegistered()) RegisterObject(); -#endif + + return false; } PersistentScriptingObject::PersistentScriptingObject(const SpawnParams& params) @@ -432,30 +442,44 @@ void PersistentScriptingObject::OnScriptingDispose() // Don't delete C++ object } -void PersistentScriptingObject::CreateManaged() +bool PersistentScriptingObject::CreateManaged() { #if USE_MONO MonoObject* managedInstance = CreateManagedInternal(); - if (managedInstance) - { - // Prevent form object GC destruction and moving - _gcHandle = mono_gchandle_new(managedInstance, false); + if (!managedInstance) + return true; - // Ensure to be registered - if (!IsRegistered()) - RegisterObject(); + // Prevent form object GC destruction + auto handle = mono_gchandle_new(managedInstance, false); + auto oldHandle = Platform::InterlockedCompareExchange((int32*)&_gcHandle, *(int32*)&handle, 0); + if (*(uint32*)&oldHandle != 0) + { + // Other thread already created the object before + if (const auto monoClass = GetClass()) + { + // Reset managed to unmanaged pointer + const MField* monoUnmanagedPtrField = monoClass->GetField(ScriptingObject_unmanagedPtr); + if (monoUnmanagedPtrField) + { + void* param = nullptr; + monoUnmanagedPtrField->SetValue(managedInstance, ¶m); + } + } + mono_gchandle_free(handle); + return true; } -#else +#endif + // Ensure to be registered if (!IsRegistered()) RegisterObject(); -#endif + + return false; } class ScriptingObjectInternal { public: - #if !COMPILE_WITHOUT_CSHARP static MonoObject* Create1(MonoReflectionType* type) diff --git a/Source/Engine/Scripting/ScriptingObject.h b/Source/Engine/Scripting/ScriptingObject.h index 9846b05fe..b29078d45 100644 --- a/Source/Engine/Scripting/ScriptingObject.h +++ b/Source/Engine/Scripting/ScriptingObject.h @@ -182,7 +182,7 @@ public: virtual void OnManagedInstanceDeleted(); virtual void OnScriptingDispose(); - virtual void CreateManaged() = 0; + virtual bool CreateManaged() = 0; virtual void DestroyManaged(); public: @@ -239,7 +239,7 @@ public: public: // [ScriptingObject] - void CreateManaged() override; + bool CreateManaged() override; }; /// @@ -266,5 +266,5 @@ public: // [ManagedScriptingObject] void OnManagedInstanceDeleted() override; void OnScriptingDispose() override; - void CreateManaged() override; + bool CreateManaged() override; };