Merge branch 'alc_reload_fix' of https://github.com/GoaLitiuM/FlaxEngine into GoaLitiuM-alc_reload_fix

This commit is contained in:
Wojtek Figat
2023-08-10 11:56:17 +02:00
6 changed files with 33 additions and 26 deletions

View File

@@ -903,11 +903,25 @@ namespace FlaxEngine.Interop
AssemblyLocations.Remove(assembly.FullName); AssemblyLocations.Remove(assembly.FullName);
// Clear all caches which might hold references to closing assembly // Unload native library handles associated for this assembly
string nativeLibraryName = assemblyOwnedNativeLibraries.GetValueOrDefault(assembly);
if (nativeLibraryName != null && loadedNativeLibraries.TryGetValue(nativeLibraryName, out IntPtr nativeLibrary))
{
NativeLibrary.Free(nativeLibrary);
loadedNativeLibraries.Remove(nativeLibraryName);
}
if (nativeLibraryName != null)
nativeLibraryPaths.Remove(nativeLibraryName);
}
[UnmanagedCallersOnly]
internal static void ReloadScriptingAssemblyLoadContext()
{
#if FLAX_EDITOR
// Clear all caches which might hold references to assemblies in collectible ALC
typeCache.Clear(); typeCache.Clear();
// Release all references in collectible ALC // Release all references in collectible ALC
#if FLAX_EDITOR
cachedDelegatesCollectible.Clear(); cachedDelegatesCollectible.Clear();
foreach (var pair in typeHandleCacheCollectible) foreach (var pair in typeHandleCacheCollectible)
pair.Value.Free(); pair.Value.Free();
@@ -918,23 +932,13 @@ namespace FlaxEngine.Interop
foreach (var handle in fieldHandleCacheCollectible) foreach (var handle in fieldHandleCacheCollectible)
handle.Free(); handle.Free();
fieldHandleCacheCollectible.Clear(); fieldHandleCacheCollectible.Clear();
#endif
_typeSizeCache.Clear(); _typeSizeCache.Clear();
foreach (var pair in classAttributesCacheCollectible) foreach (var pair in classAttributesCacheCollectible)
pair.Value.Free(); pair.Value.Free();
classAttributesCacheCollectible.Clear(); classAttributesCacheCollectible.Clear();
// Unload native library handles associated for this assembly
string nativeLibraryName = assemblyOwnedNativeLibraries.GetValueOrDefault(assembly);
if (nativeLibraryName != null && loadedNativeLibraries.TryGetValue(nativeLibraryName, out IntPtr nativeLibrary))
{
NativeLibrary.Free(nativeLibrary);
loadedNativeLibraries.Remove(nativeLibraryName);
}
if (nativeLibraryName != null)
nativeLibraryPaths.Remove(nativeLibraryName);
// Unload the ALC // Unload the ALC
bool unloading = true; bool unloading = true;
scriptingAssemblyLoadContext.Unloading += (alc) => { unloading = false; }; scriptingAssemblyLoadContext.Unloading += (alc) => { unloading = false; };
@@ -945,6 +949,7 @@ namespace FlaxEngine.Interop
InitScriptingAssemblyLoadContext(); InitScriptingAssemblyLoadContext();
DelegateHelpers.InitMethods(); DelegateHelpers.InitMethods();
#endif
} }
[UnmanagedCallersOnly] [UnmanagedCallersOnly]

View File

@@ -47,7 +47,7 @@ public:
#if USE_EDITOR #if USE_EDITOR
// Called by Scripting in a middle of hot-reload (after unloading modules but before loading them again). // Called by Scripting in a middle of hot-reload (after unloading modules but before loading them again).
static void OnMidHotReload(); static void ReloadScriptingAssemblyLoadContext();
#endif #endif
public: public:

View File

@@ -160,6 +160,7 @@ DECLARE_ENUM_OPERATORS(MTypeAttributes);
DECLARE_ENUM_OPERATORS(MMethodAttributes); DECLARE_ENUM_OPERATORS(MMethodAttributes);
DECLARE_ENUM_OPERATORS(MFieldAttributes); DECLARE_ENUM_OPERATORS(MFieldAttributes);
// Multiple AppDomains are superseded by AssemblyLoadContext in .NET
extern MDomain* MRootDomain; extern MDomain* MRootDomain;
extern MDomain* MActiveDomain; extern MDomain* MActiveDomain;
extern Array<MDomain*, FixedAllocation<4>> MDomains; extern Array<MDomain*, FixedAllocation<4>> MDomains;
@@ -301,11 +302,14 @@ void MCore::UnloadEngine()
#if USE_EDITOR #if USE_EDITOR
void MCore::OnMidHotReload() void MCore::ReloadScriptingAssemblyLoadContext()
{ {
// Clear any cached class attributes (see https://github.com/FlaxEngine/FlaxEngine/issues/1108) // Clear any cached class attributes (see https://github.com/FlaxEngine/FlaxEngine/issues/1108)
for (auto e : CachedClassHandles) for (auto e : CachedClassHandles)
e.Value->_attributes.Clear(); e.Value->_attributes.Clear();
static void* ReloadScriptingAssemblyLoadContextPtr = GetStaticMethodPointer(TEXT("ReloadScriptingAssemblyLoadContext"));
CallStaticMethod<void>(ReloadScriptingAssemblyLoadContextPtr);
} }
#endif #endif
@@ -723,16 +727,12 @@ bool MAssembly::LoadImage(const String& assemblyPath, const StringView& nativePa
bool MAssembly::UnloadImage(bool isReloading) bool MAssembly::UnloadImage(bool isReloading)
{ {
if (_handle) if (_handle && isReloading)
{
// TODO: closing assembly on reload only is copy-paste from mono, do we need do this on .NET too?
if (isReloading)
{ {
LOG(Info, "Unloading managed assembly \'{0}\' (is reloading)", String(_name)); LOG(Info, "Unloading managed assembly \'{0}\' (is reloading)", String(_name));
static void* CloseAssemblyPtr = GetStaticMethodPointer(TEXT("CloseAssembly")); static void* CloseAssemblyPtr = GetStaticMethodPointer(TEXT("CloseAssembly"));
CallStaticMethod<void, const void*>(CloseAssemblyPtr, _handle); CallStaticMethod<void, const void*>(CloseAssemblyPtr, _handle);
}
CachedAssemblyHandles.Remove(_handle); CachedAssemblyHandles.Remove(_handle);
_handle = nullptr; _handle = nullptr;

View File

@@ -716,7 +716,7 @@ void MCore::UnloadEngine()
#if USE_EDITOR #if USE_EDITOR
void MCore::OnMidHotReload() void MCore::ReloadScriptingAssemblyLoadContext()
{ {
} }

View File

@@ -61,7 +61,7 @@ void MCore::UnloadEngine()
#if USE_EDITOR #if USE_EDITOR
void MCore::OnMidHotReload() void MCore::ReloadScriptingAssemblyLoadContext()
{ {
} }

View File

@@ -706,7 +706,9 @@ void Scripting::Reload(bool canTriggerSceneReload)
modules.Clear(); modules.Clear();
_nonNativeModules.ClearDelete(); _nonNativeModules.ClearDelete();
_hasGameModulesLoaded = false; _hasGameModulesLoaded = false;
MCore::OnMidHotReload();
// Release and create a new assembly load context for user assemblies
MCore::ReloadScriptingAssemblyLoadContext();
// Give GC a try to cleanup old user objects and the other mess // Give GC a try to cleanup old user objects and the other mess
MCore::GC::Collect(); MCore::GC::Collect();