mirror of
https://github.com/VSadov/Satori.git
synced 2025-06-08 11:37:04 +09:00
[mono] Initial support for unloadable ALCs (#77399)
* [mono] Add LoaderAllocator type, whose instances are used to detect whenever a collectible ALC has managed references. * [mono] Add an implicit GC reference between objects allocated from a collectible ALC and its LoaderAllocator object. * [mono] Add a new hash table which is similar to MonoGHashTable, but it doesn't keep the key/value objects alive by itself. * [mono] Add a keepalive field to some reflection objects to keep the alc alive if user code holds a reference to them. Change the reflection hashes in MonoMemoryManager to weak hashes so the hashes themselves don't keep the alc alive. * Fix reflection hashes. * [mono] Optimize the case when mono_method_get_signature_checked () is called with a non-zero context and a non-generic signature. * Free memory manager caches. * [mono] Store static variables with GC references in collectible alcs on the GC heap. Normally, static variables are stored in an array inside MonoVTable which is registered as a GC root. For collectible alcs, this would not work, since GC references in these arrays would keep the alc alive. Instead, store them in arrays referenced by the LoaderAllocator object. This assumes the static variables will no longer be accessed after the LoaderAllocator object dies. * Add basic unload functionality. * Fix weak hashes. * Free MonoJitInfos belonging to unloaded memory managers. * Avoid returning collectible types from mono_metadata_get_shared_type (). * Add docs. * Fix the build. * Fix the build. * Disable unloading for now.
This commit is contained in:
parent
d70d2a9d11
commit
6fecc25b02
34 changed files with 1206 additions and 107 deletions
80
docs/design/mono/unloadability.md
Normal file
80
docs/design/mono/unloadability.md
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
|
||||||
|
Design
|
||||||
|
------
|
||||||
|
|
||||||
|
The design is based on docs/design/features/unloadability.md.
|
||||||
|
|
||||||
|
Memory managers
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Most runtime memory is owned by MonoMemoryManager structures, which are owned by one or more ALCs. For example,
|
||||||
|
if type T1 is from ALC1, and T2 is from ALC2, then the memory related to the generic instance T1<T2> will
|
||||||
|
be owned by the memory manager for [ALC1, ALC2]. A memory manager is collectible if one of its ALCs is collectible.
|
||||||
|
|
||||||
|
LoaderAllocator objects
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Each memory manager has a corresponding LoaderAllocator object. This object is referenced explicitly or
|
||||||
|
implicitly by every managed object which is related to the memory manager. Until unloading starts,
|
||||||
|
the memory manager keeps a strong reference to this object.
|
||||||
|
|
||||||
|
For objects whose type is from a collectible ALC, the GC maintains an implicit reference by marking
|
||||||
|
the LoaderAllocator object when the object is marked.
|
||||||
|
|
||||||
|
Reflection objects referencing the ALC have an explicit 'keepalive' field which points to the
|
||||||
|
corresponding LoaderAllocator object.
|
||||||
|
|
||||||
|
When the LoaderAllocator object is collected by the GC, it means there are no more managed
|
||||||
|
references to its memory allocator, so it can be unloaded.
|
||||||
|
|
||||||
|
Reflection caches and static variables
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
Reflection objects are kept in caches inside the runtime. These caches keep strong references to the
|
||||||
|
reflection objects. This doesn't work for collectible ALCs, since the objects keep the LoaderAllocator
|
||||||
|
object alive. So for collectible ALCs, we use a different kind of hash table whose keys/values are
|
||||||
|
stored in object[] arrays inside the LoaderAllocator object, and the hash table holds a weak reference
|
||||||
|
to these arrays. This means that the reflection objects are only kept alive by the LoaderAllocator and
|
||||||
|
by application code.
|
||||||
|
|
||||||
|
Similarly, normal static variables are treated as GC roots so any static variable pointing to an object
|
||||||
|
inside the ALC would keep the ALC alive. Instead, we store static variables inside arrays in the
|
||||||
|
LoaderAllocator object. Normal reference type variable are allocated an entry in a pinned object[],
|
||||||
|
and their address becomes an interior pointer to the pinned array element. For valuetypes, we
|
||||||
|
allocate a pinned boxed object and the static variable address becomes the address of the unboxed
|
||||||
|
object.
|
||||||
|
|
||||||
|
Unloading process
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
- The app calls AssemblyLoadContext.Unload ()
|
||||||
|
- The runtime iterates over the memory managers of the ALC. Each ALC holds a strong reference to its
|
||||||
|
LoaderAllocator object. We change the strong reference to a weak one, allowing the LoaderAllocator
|
||||||
|
to the collected.
|
||||||
|
- The app eventually drops all implicit and explicit references to the LoaderAllocator object.
|
||||||
|
- The finalizer of the LoaderAllocator object calls into the runtime to free the corresponding
|
||||||
|
memory manager.
|
||||||
|
- When all memory managers referencing the ALC are freed, the ALC itself is freed.
|
||||||
|
|
||||||
|
See the document in the Design section about the LoaderAllocatorScout object.
|
||||||
|
|
||||||
|
Remaining work
|
||||||
|
---------------
|
||||||
|
|
||||||
|
- Managed frames
|
||||||
|
Frames belonging to code in the ALC should keep the ALC alive. This can be implemented by
|
||||||
|
having all methods allocate a volatile local variable and store a reference to their LoaderAllocator object
|
||||||
|
into it.
|
||||||
|
- Thread abort
|
||||||
|
Although its not part of current .NET APIs, it might be useful to have a way to abort threads executing code
|
||||||
|
in an ALC, similarly to how domain unloads worked previously.
|
||||||
|
- Reflection pointers
|
||||||
|
Icalls which take a assembly/type etc. handle as parameter need to keep the ALC alive, otherwise there will
|
||||||
|
be subtle races.
|
||||||
|
- Boehm GC support
|
||||||
|
- TLS variables
|
||||||
|
- Enable/disable compiler flag
|
||||||
|
- Profiling, perf counters, etc. support
|
||||||
|
- Diagnostics support, i.e. what keeps an ALC alive
|
||||||
|
- Testing
|
||||||
|
- Leak detection
|
|
@ -208,6 +208,7 @@
|
||||||
<Compile Include="$(BclSourcesRoot)\System\Reflection\ConstructorInvoker.Mono.cs" />
|
<Compile Include="$(BclSourcesRoot)\System\Reflection\ConstructorInvoker.Mono.cs" />
|
||||||
<Compile Include="$(BclSourcesRoot)\System\Reflection\CustomAttribute.cs" />
|
<Compile Include="$(BclSourcesRoot)\System\Reflection\CustomAttribute.cs" />
|
||||||
<Compile Include="$(BclSourcesRoot)\System\Reflection\FieldInfo.Mono.cs" />
|
<Compile Include="$(BclSourcesRoot)\System\Reflection\FieldInfo.Mono.cs" />
|
||||||
|
<Compile Include="$(BclSourcesRoot)\System\Reflection\LoaderAllocator.cs" />
|
||||||
<Compile Include="$(BclSourcesRoot)\System\Reflection\MemberInfo.Mono.cs" />
|
<Compile Include="$(BclSourcesRoot)\System\Reflection\MemberInfo.Mono.cs" />
|
||||||
<Compile Include="$(BclSourcesRoot)\System\Reflection\MethodBase.Mono.cs" />
|
<Compile Include="$(BclSourcesRoot)\System\Reflection\MethodBase.Mono.cs" />
|
||||||
<Compile Include="$(BclSourcesRoot)\System\Reflection\MethodInvoker.Mono.cs" />
|
<Compile Include="$(BclSourcesRoot)\System\Reflection\MethodInvoker.Mono.cs" />
|
||||||
|
|
|
@ -179,6 +179,7 @@ namespace System.Reflection.Emit
|
||||||
//
|
//
|
||||||
#region Sync with RuntimeAssembly.cs and ReflectionAssembly in object-internals.h
|
#region Sync with RuntimeAssembly.cs and ReflectionAssembly in object-internals.h
|
||||||
internal IntPtr _mono_assembly;
|
internal IntPtr _mono_assembly;
|
||||||
|
private LoaderAllocator? m_keepalive;
|
||||||
|
|
||||||
private UIntPtr dynamic_assembly; /* GC-tracked */
|
private UIntPtr dynamic_assembly; /* GC-tracked */
|
||||||
private ModuleBuilder[] modules;
|
private ModuleBuilder[] modules;
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace System.Reflection
|
||||||
|
{
|
||||||
|
// See src/coreclr/System.Private.CoreLib/src/System/Reflection/LoaderAllocator.cs for
|
||||||
|
// more comments
|
||||||
|
internal sealed class LoaderAllocatorScout
|
||||||
|
{
|
||||||
|
internal IntPtr m_native;
|
||||||
|
|
||||||
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||||
|
private static extern bool Destroy(IntPtr native);
|
||||||
|
|
||||||
|
internal LoaderAllocatorScout(IntPtr native)
|
||||||
|
{
|
||||||
|
m_native = native;
|
||||||
|
}
|
||||||
|
|
||||||
|
~LoaderAllocatorScout()
|
||||||
|
{
|
||||||
|
if (!Destroy(m_native))
|
||||||
|
{
|
||||||
|
GC.ReRegisterForFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// This object is allocated by the runtime, every object
|
||||||
|
// in a collectible alc has an implicit reference to it, maintained by
|
||||||
|
// the GC, or an explicit reference through a field.
|
||||||
|
//
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal sealed class LoaderAllocator
|
||||||
|
{
|
||||||
|
#region Sync with MonoManagedLoaderAllocator in object-internals.h
|
||||||
|
#pragma warning disable CA1823, 414, 169
|
||||||
|
private LoaderAllocatorScout m_scout;
|
||||||
|
// These point to objects created by the runtime which are kept
|
||||||
|
// alive by this LoaderAllocator
|
||||||
|
private object[]? m_slots;
|
||||||
|
private object[]? m_hashes;
|
||||||
|
private int m_nslots;
|
||||||
|
#pragma warning restore CA1823, 414, 169
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private LoaderAllocator(IntPtr native)
|
||||||
|
{
|
||||||
|
m_scout = new LoaderAllocatorScout(native);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -64,9 +64,11 @@ namespace System.Reflection
|
||||||
|
|
||||||
//
|
//
|
||||||
// KEEP IN SYNC WITH _MonoReflectionAssembly in /mono/mono/metadata/object-internals.h
|
// KEEP IN SYNC WITH _MonoReflectionAssembly in /mono/mono/metadata/object-internals.h
|
||||||
|
// and AssemblyBuilder.cs.
|
||||||
//
|
//
|
||||||
#region VM dependency
|
#region VM dependency
|
||||||
private IntPtr _mono_assembly;
|
private IntPtr _mono_assembly;
|
||||||
|
private LoaderAllocator? m_keepalive;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
internal IntPtr GetUnderlyingNativeHandle() { return _mono_assembly; }
|
internal IntPtr GetUnderlyingNativeHandle() { return _mono_assembly; }
|
||||||
|
|
|
@ -24,12 +24,20 @@ namespace System.Runtime.Loader
|
||||||
[DynamicDependency(nameof(_nativeAssemblyLoadContext))]
|
[DynamicDependency(nameof(_nativeAssemblyLoadContext))]
|
||||||
private IntPtr InitializeAssemblyLoadContext(IntPtr thisHandlePtr, bool representsTPALoadContext, bool isCollectible)
|
private IntPtr InitializeAssemblyLoadContext(IntPtr thisHandlePtr, bool representsTPALoadContext, bool isCollectible)
|
||||||
{
|
{
|
||||||
|
if (isCollectible)
|
||||||
|
KeepLoaderAllocator();
|
||||||
using (SafeStringMarshal handle = RuntimeMarshal.MarshalString(Name))
|
using (SafeStringMarshal handle = RuntimeMarshal.MarshalString(Name))
|
||||||
{
|
{
|
||||||
return InternalInitializeNativeALC(thisHandlePtr, handle.Value, representsTPALoadContext, isCollectible);
|
return InternalInitializeNativeALC(thisHandlePtr, handle.Value, representsTPALoadContext, isCollectible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep the type alive since instances are created by the runtime
|
||||||
|
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(LoaderAllocator))]
|
||||||
|
private static void KeepLoaderAllocator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||||
private static extern void PrepareForAssemblyLoadContextRelease (IntPtr nativeAssemblyLoadContext, IntPtr assemblyLoadContextStrong);
|
private static extern void PrepareForAssemblyLoadContextRelease (IntPtr nativeAssemblyLoadContext, IntPtr assemblyLoadContextStrong);
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,18 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace System
|
namespace System
|
||||||
{
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public partial class Type
|
public partial class Type
|
||||||
{
|
{
|
||||||
#region keep in sync with object-internals.h
|
#region keep in sync with object-internals.h
|
||||||
internal RuntimeTypeHandle _impl;
|
internal RuntimeTypeHandle _impl;
|
||||||
|
internal LoaderAllocator? m_keepalive;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
internal IntPtr GetUnderlyingNativeHandle()
|
internal IntPtr GetUnderlyingNativeHandle()
|
||||||
|
|
|
@ -107,6 +107,8 @@ set(metadata_common_sources
|
||||||
mono-hash.h
|
mono-hash.h
|
||||||
mono-conc-hash.c
|
mono-conc-hash.c
|
||||||
mono-conc-hash.h
|
mono-conc-hash.h
|
||||||
|
weak-hash.c
|
||||||
|
weak-hash.h
|
||||||
mono-ptr-array.h
|
mono-ptr-array.h
|
||||||
monitor.h
|
monitor.h
|
||||||
object.c
|
object.c
|
||||||
|
|
|
@ -38,10 +38,13 @@ static void
|
||||||
mono_alc_init (MonoAssemblyLoadContext *alc, gboolean collectible)
|
mono_alc_init (MonoAssemblyLoadContext *alc, gboolean collectible)
|
||||||
{
|
{
|
||||||
MonoLoadedImages *li = g_new0 (MonoLoadedImages, 1);
|
MonoLoadedImages *li = g_new0 (MonoLoadedImages, 1);
|
||||||
|
|
||||||
|
// FIXME:
|
||||||
|
collectible = FALSE;
|
||||||
|
|
||||||
mono_loaded_images_init (li, alc);
|
mono_loaded_images_init (li, alc);
|
||||||
alc->loaded_images = li;
|
alc->loaded_images = li;
|
||||||
alc->loaded_assemblies = NULL;
|
alc->loaded_assemblies = NULL;
|
||||||
alc->memory_manager = mono_mem_manager_new (&alc, 1, collectible);
|
|
||||||
alc->generic_memory_managers = g_ptr_array_new ();
|
alc->generic_memory_managers = g_ptr_array_new ();
|
||||||
mono_coop_mutex_init (&alc->memory_managers_lock);
|
mono_coop_mutex_init (&alc->memory_managers_lock);
|
||||||
alc->unloading = FALSE;
|
alc->unloading = FALSE;
|
||||||
|
@ -49,6 +52,12 @@ mono_alc_init (MonoAssemblyLoadContext *alc, gboolean collectible)
|
||||||
alc->pinvoke_scopes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
alc->pinvoke_scopes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||||
mono_coop_mutex_init (&alc->assemblies_lock);
|
mono_coop_mutex_init (&alc->assemblies_lock);
|
||||||
mono_coop_mutex_init (&alc->pinvoke_lock);
|
mono_coop_mutex_init (&alc->pinvoke_lock);
|
||||||
|
|
||||||
|
alc->memory_manager = mono_mem_manager_new (&alc, 1, collectible);
|
||||||
|
|
||||||
|
if (collectible)
|
||||||
|
/* Eagerly create the loader alloc object for the main memory manager */
|
||||||
|
mono_mem_manager_get_loader_alloc (alc->memory_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MonoAssemblyLoadContext *
|
static MonoAssemblyLoadContext *
|
||||||
|
@ -98,6 +107,7 @@ mono_alc_cleanup_assemblies (MonoAssemblyLoadContext *alc)
|
||||||
// The minimum refcount on assemblies is 2: one for the domain and one for the ALC.
|
// The minimum refcount on assemblies is 2: one for the domain and one for the ALC.
|
||||||
// The domain refcount might be less than optimal on netcore, but its removal is too likely to cause issues for now.
|
// The domain refcount might be less than optimal on netcore, but its removal is too likely to cause issues for now.
|
||||||
GSList *tmp;
|
GSList *tmp;
|
||||||
|
const char *name = alc->name ? alc->name : "<default>";
|
||||||
|
|
||||||
// Remove the assemblies from loaded_assemblies
|
// Remove the assemblies from loaded_assemblies
|
||||||
for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
|
for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
|
||||||
|
@ -107,8 +117,8 @@ mono_alc_cleanup_assemblies (MonoAssemblyLoadContext *alc)
|
||||||
loaded_assemblies = g_slist_remove (loaded_assemblies, assembly);
|
loaded_assemblies = g_slist_remove (loaded_assemblies, assembly);
|
||||||
alcs_unlock ();
|
alcs_unlock ();
|
||||||
|
|
||||||
mono_assembly_decref (assembly);
|
//mono_assembly_decref (assembly);
|
||||||
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Unloading ALC [%p], removing assembly %s[%p] from loaded_assemblies, ref_count=%d\n", alc, assembly->aname.name, assembly, assembly->ref_count);
|
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Unloading ALC '%s'[%p], removing assembly %s[%p] from loaded_assemblies, ref_count=%d\n", name, alc, assembly->aname.name, assembly, assembly->ref_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release the GC roots
|
// Release the GC roots
|
||||||
|
@ -122,7 +132,7 @@ mono_alc_cleanup_assemblies (MonoAssemblyLoadContext *alc)
|
||||||
MonoAssembly *assembly = (MonoAssembly *)tmp->data;
|
MonoAssembly *assembly = (MonoAssembly *)tmp->data;
|
||||||
if (!assembly->image || !image_is_dynamic (assembly->image))
|
if (!assembly->image || !image_is_dynamic (assembly->image))
|
||||||
continue;
|
continue;
|
||||||
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Unloading ALC [%p], dynamic assembly %s[%p], ref_count=%d", alc, assembly->aname.name, assembly, assembly->ref_count);
|
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Unloading ALC '%s'[%p], dynamic assembly %s[%p], ref_count=%d", name, alc, assembly->aname.name, assembly, assembly->ref_count);
|
||||||
if (!mono_assembly_close_except_image_pools (assembly))
|
if (!mono_assembly_close_except_image_pools (assembly))
|
||||||
tmp->data = NULL;
|
tmp->data = NULL;
|
||||||
}
|
}
|
||||||
|
@ -134,7 +144,7 @@ mono_alc_cleanup_assemblies (MonoAssemblyLoadContext *alc)
|
||||||
continue;
|
continue;
|
||||||
if (!assembly->image || image_is_dynamic (assembly->image))
|
if (!assembly->image || image_is_dynamic (assembly->image))
|
||||||
continue;
|
continue;
|
||||||
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Unloading ALC [%p], non-dynamic assembly %s[%p], ref_count=%d", alc, assembly->aname.name, assembly, assembly->ref_count);
|
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Unloading ALC '%s'[%p], non-dynamic assembly %s[%p], ref_count=%d", name, alc, assembly->aname.name, assembly, assembly->ref_count);
|
||||||
if (!mono_assembly_close_except_image_pools (assembly))
|
if (!mono_assembly_close_except_image_pools (assembly))
|
||||||
tmp->data = NULL;
|
tmp->data = NULL;
|
||||||
}
|
}
|
||||||
|
@ -173,15 +183,21 @@ mono_alc_cleanup (MonoAssemblyLoadContext *alc)
|
||||||
|
|
||||||
mono_alc_cleanup_assemblies (alc);
|
mono_alc_cleanup_assemblies (alc);
|
||||||
|
|
||||||
mono_mem_manager_free (alc->memory_manager, FALSE);
|
// FIXME: Do it for every memory manager
|
||||||
|
mono_gchandle_free_internal (alc->memory_manager->loader_allocator_handle);
|
||||||
|
alc->memory_manager->loader_allocator_handle = NULL;
|
||||||
|
|
||||||
|
// FIXME: Change to FALSE
|
||||||
|
mono_mem_manager_free (alc->memory_manager, TRUE);
|
||||||
alc->memory_manager = NULL;
|
alc->memory_manager = NULL;
|
||||||
|
|
||||||
/*for (int i = 0; i < alc->generic_memory_managers->len; i++) {
|
/*for (int i = 0; i < alc->generic_memory_managers->len; i++) {
|
||||||
MonoGenericMemoryManager *memory_manager = (MonoGenericMemoryManager *)alc->generic_memory_managers->pdata [i];
|
MonoGenericMemoryManager *memory_manager = (MonoGenericMemoryManager *)alc->generic_memory_managers->pdata [i];
|
||||||
mono_mem_manager_free_generic (memory_manager, FALSE);
|
mono_mem_manager_free_generic (memory_manager, FALSE);
|
||||||
}*/
|
}*/
|
||||||
g_ptr_array_free (alc->generic_memory_managers, TRUE);
|
// FIXME:
|
||||||
mono_coop_mutex_destroy (&alc->memory_managers_lock);
|
//g_ptr_array_free (alc->generic_memory_managers, TRUE);
|
||||||
|
//mono_coop_mutex_destroy (&alc->memory_managers_lock);
|
||||||
|
|
||||||
mono_gchandle_free_internal (alc->gchandle);
|
mono_gchandle_free_internal (alc->gchandle);
|
||||||
alc->gchandle = NULL;
|
alc->gchandle = NULL;
|
||||||
|
@ -260,6 +276,10 @@ ves_icall_System_Runtime_Loader_AssemblyLoadContext_PrepareForAssemblyLoadContex
|
||||||
MonoGCHandle strong_gchandle = (MonoGCHandle)strong_gchandle_ptr;
|
MonoGCHandle strong_gchandle = (MonoGCHandle)strong_gchandle_ptr;
|
||||||
MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)alc_pointer;
|
MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)alc_pointer;
|
||||||
|
|
||||||
|
// FIXME:
|
||||||
|
if (!alc->collectible)
|
||||||
|
return;
|
||||||
|
|
||||||
g_assert (alc->collectible);
|
g_assert (alc->collectible);
|
||||||
g_assert (!alc->unloading);
|
g_assert (!alc->unloading);
|
||||||
g_assert (alc->gchandle);
|
g_assert (alc->gchandle);
|
||||||
|
@ -270,6 +290,12 @@ ves_icall_System_Runtime_Loader_AssemblyLoadContext_PrepareForAssemblyLoadContex
|
||||||
MonoGCHandle weak_gchandle = alc->gchandle;
|
MonoGCHandle weak_gchandle = alc->gchandle;
|
||||||
alc->gchandle = strong_gchandle;
|
alc->gchandle = strong_gchandle;
|
||||||
mono_gchandle_free_internal (weak_gchandle);
|
mono_gchandle_free_internal (weak_gchandle);
|
||||||
|
|
||||||
|
mono_mem_manager_start_unload (alc->memory_manager);
|
||||||
|
mono_alc_memory_managers_lock (alc);
|
||||||
|
for (guint i = 0; i < alc->generic_memory_managers->len; i++)
|
||||||
|
mono_mem_manager_start_unload ((MonoMemoryManager *)g_ptr_array_index (alc->generic_memory_managers, i));
|
||||||
|
mono_alc_memory_managers_unlock (alc);
|
||||||
}
|
}
|
||||||
|
|
||||||
gpointer
|
gpointer
|
||||||
|
@ -655,3 +681,44 @@ mono_alc_get_all_loaded_assemblies (void)
|
||||||
alcs_unlock ();
|
alcs_unlock ();
|
||||||
return assemblies;
|
return assemblies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MonoBoolean
|
||||||
|
ves_icall_System_Reflection_LoaderAllocatorScout_Destroy (gpointer native)
|
||||||
|
{
|
||||||
|
/* Not enabled yet */
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
MonoMemoryManager *mem_manager = (MonoMemoryManager *)native;
|
||||||
|
MonoAssemblyLoadContext *alc;
|
||||||
|
|
||||||
|
MonoGCHandle loader_handle = mem_manager->loader_allocator_weak_handle;
|
||||||
|
if (mono_gchandle_get_target_internal (loader_handle))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The weak handle is NULL, meaning the managed LoaderAllocator object is dead, we can
|
||||||
|
* free the native side.
|
||||||
|
*/
|
||||||
|
for (int i = 0; i < mem_manager->n_alcs; ++i) {
|
||||||
|
alc = mem_manager->alcs [i];
|
||||||
|
mono_alc_memory_managers_lock (alc);
|
||||||
|
g_ptr_array_remove (alc->generic_memory_managers, mem_manager);
|
||||||
|
mono_alc_memory_managers_unlock (alc);
|
||||||
|
}
|
||||||
|
|
||||||
|
alc = mem_manager->alcs [0];
|
||||||
|
|
||||||
|
// FIXME: Generic memory managers might need to be destroyed in a specific order/together,
|
||||||
|
// hold ref counts on alcs etc.
|
||||||
|
if (mem_manager == alc->memory_manager) {
|
||||||
|
mono_alc_cleanup (alc);
|
||||||
|
} else {
|
||||||
|
// FIXME: Use debug_unload=FALSE
|
||||||
|
mono_mem_manager_free (mem_manager, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -155,7 +155,8 @@ struct _MonoClassField {
|
||||||
* field, it's the offset from the start of the object, if
|
* field, it's the offset from the start of the object, if
|
||||||
* it's static, it's from the start of the memory chunk
|
* it's static, it's from the start of the memory chunk
|
||||||
* allocated for statics for the class.
|
* allocated for statics for the class.
|
||||||
* For special static fields, this is set to -1 during vtable construction.
|
* -1 means its a special static field.
|
||||||
|
* -2 means its a collectible static field.
|
||||||
*/
|
*/
|
||||||
int offset;
|
int offset;
|
||||||
};
|
};
|
||||||
|
@ -360,6 +361,7 @@ struct MonoVTable {
|
||||||
MonoDomain *domain; /* each object/vtable belongs to exactly one domain */
|
MonoDomain *domain; /* each object/vtable belongs to exactly one domain */
|
||||||
gpointer type; /* System.Type type for klass */
|
gpointer type; /* System.Type type for klass */
|
||||||
guint8 *interface_bitmap;
|
guint8 *interface_bitmap;
|
||||||
|
MonoGCHandle loader_alloc; /* LoaderAllocator object for objects in collectible alcs */
|
||||||
guint32 max_interface_id;
|
guint32 max_interface_id;
|
||||||
guint8 rank;
|
guint8 rank;
|
||||||
/* Keep this a guint8, the jit depends on it */
|
/* Keep this a guint8, the jit depends on it */
|
||||||
|
|
|
@ -208,4 +208,6 @@ ICALL_EXPORT MonoBoolean ves_icall_System_Array_IsValueOfElementTypeInternal (Mo
|
||||||
|
|
||||||
ICALL_EXPORT MonoBoolean ves_icall_System_Array_FastCopy (MonoObjectHandleOnStack source_handle, int source_idx, MonoObjectHandleOnStack dest_handle, int dest_idx, int length);
|
ICALL_EXPORT MonoBoolean ves_icall_System_Array_FastCopy (MonoObjectHandleOnStack source_handle, int source_idx, MonoObjectHandleOnStack dest_handle, int dest_idx, int length);
|
||||||
|
|
||||||
|
ICALL_EXPORT MonoBoolean ves_icall_System_Reflection_LoaderAllocatorScout_Destroy (gpointer native);
|
||||||
|
|
||||||
#endif // __MONO_METADATA_ICALL_DECL_H__
|
#endif // __MONO_METADATA_ICALL_DECL_H__
|
||||||
|
|
|
@ -329,6 +329,9 @@ ICALL_TYPE(FIELDI, "System.Reflection.FieldInfo", FILEDI_1)
|
||||||
HANDLES(FILEDI_1, "get_marshal_info", ves_icall_System_Reflection_FieldInfo_get_marshal_info, MonoReflectionMarshalAsAttribute, 1, (MonoReflectionField))
|
HANDLES(FILEDI_1, "get_marshal_info", ves_icall_System_Reflection_FieldInfo_get_marshal_info, MonoReflectionMarshalAsAttribute, 1, (MonoReflectionField))
|
||||||
HANDLES(FILEDI_2, "internal_from_handle_type", ves_icall_System_Reflection_FieldInfo_internal_from_handle_type, MonoReflectionField, 2, (MonoClassField_ref, MonoType_ref))
|
HANDLES(FILEDI_2, "internal_from_handle_type", ves_icall_System_Reflection_FieldInfo_internal_from_handle_type, MonoReflectionField, 2, (MonoClassField_ref, MonoType_ref))
|
||||||
|
|
||||||
|
ICALL_TYPE(LOADER_ALLOC, "System.Reflection.LoaderAllocatorScout", LOADER_ALLOC_1)
|
||||||
|
NOHANDLES(ICALL(LOADER_ALLOC_1, "Destroy", ves_icall_System_Reflection_LoaderAllocatorScout_Destroy))
|
||||||
|
|
||||||
ICALL_TYPE(MDUP, "System.Reflection.Metadata.MetadataUpdater", MDUP_1)
|
ICALL_TYPE(MDUP, "System.Reflection.Metadata.MetadataUpdater", MDUP_1)
|
||||||
NOHANDLES(ICALL(MDUP_1, "ApplyUpdateEnabled", ves_icall_AssemblyExtensions_ApplyUpdateEnabled))
|
NOHANDLES(ICALL(MDUP_1, "ApplyUpdateEnabled", ves_icall_AssemblyExtensions_ApplyUpdateEnabled))
|
||||||
NOHANDLES(ICALL(MDUP_2, "ApplyUpdate_internal", ves_icall_AssemblyExtensions_ApplyUpdate))
|
NOHANDLES(ICALL(MDUP_2, "ApplyUpdate_internal", ves_icall_AssemblyExtensions_ApplyUpdate))
|
||||||
|
|
|
@ -2053,34 +2053,6 @@ free_hash (GHashTable *hash)
|
||||||
g_hash_table_destroy (hash);
|
g_hash_table_destroy (hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
mono_wrapper_caches_free (MonoWrapperCaches *cache)
|
|
||||||
{
|
|
||||||
free_hash (cache->delegate_invoke_cache);
|
|
||||||
free_hash (cache->delegate_begin_invoke_cache);
|
|
||||||
free_hash (cache->delegate_end_invoke_cache);
|
|
||||||
free_hash (cache->delegate_bound_static_invoke_cache);
|
|
||||||
free_hash (cache->runtime_invoke_signature_cache);
|
|
||||||
|
|
||||||
free_hash (cache->delegate_abstract_invoke_cache);
|
|
||||||
|
|
||||||
free_hash (cache->runtime_invoke_method_cache);
|
|
||||||
free_hash (cache->managed_wrapper_cache);
|
|
||||||
|
|
||||||
free_hash (cache->native_wrapper_cache);
|
|
||||||
free_hash (cache->native_wrapper_aot_cache);
|
|
||||||
free_hash (cache->native_wrapper_check_cache);
|
|
||||||
free_hash (cache->native_wrapper_aot_check_cache);
|
|
||||||
|
|
||||||
free_hash (cache->native_func_wrapper_aot_cache);
|
|
||||||
free_hash (cache->native_func_wrapper_indirect_cache);
|
|
||||||
free_hash (cache->synchronized_cache);
|
|
||||||
free_hash (cache->unbox_wrapper_cache);
|
|
||||||
free_hash (cache->cominterop_invoke_cache);
|
|
||||||
free_hash (cache->cominterop_wrapper_cache);
|
|
||||||
free_hash (cache->thunk_invoke_cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mono_image_close_except_pools_all (MonoImage**images, int image_count)
|
mono_image_close_except_pools_all (MonoImage**images, int image_count)
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <mono/metadata/mempool-internals.h>
|
#include <mono/metadata/mempool-internals.h>
|
||||||
#include <mono/metadata/mono-conc-hash.h>
|
#include <mono/metadata/mono-conc-hash.h>
|
||||||
#include <mono/metadata/mono-hash.h>
|
#include <mono/metadata/mono-hash.h>
|
||||||
|
#include <mono/metadata/weak-hash.h>
|
||||||
#include <mono/metadata/object-forward.h>
|
#include <mono/metadata/object-forward.h>
|
||||||
#include <mono/utils/mono-codeman.h>
|
#include <mono/utils/mono-codeman.h>
|
||||||
#include <mono/utils/mono-coop-mutex.h>
|
#include <mono/utils/mono-coop-mutex.h>
|
||||||
|
@ -125,10 +126,8 @@ struct _MonoAssemblyLoadContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MonoMemoryManager {
|
struct _MonoMemoryManager {
|
||||||
// Whether the MemoryManager can be unloaded on netcore; should only be set at creation
|
// Whether the MemoryManager can be unloaded; should only be set at creation
|
||||||
gboolean collectible;
|
gboolean collectible;
|
||||||
// Whether this is a singleton or generic MemoryManager
|
|
||||||
gboolean is_generic;
|
|
||||||
// Whether the MemoryManager is in the process of being freed
|
// Whether the MemoryManager is in the process of being freed
|
||||||
gboolean freeing;
|
gboolean freeing;
|
||||||
|
|
||||||
|
@ -156,6 +155,10 @@ struct _MonoMemoryManager {
|
||||||
/* Information maintained by the execution engine */
|
/* Information maintained by the execution engine */
|
||||||
gpointer runtime_info;
|
gpointer runtime_info;
|
||||||
|
|
||||||
|
// Handles pointing to the corresponding LoaderAllocator object
|
||||||
|
MonoGCHandle loader_allocator_handle;
|
||||||
|
MonoGCHandle loader_allocator_weak_handle;
|
||||||
|
|
||||||
// Hashtables for Reflection handles
|
// Hashtables for Reflection handles
|
||||||
MonoGHashTable *type_hash;
|
MonoGHashTable *type_hash;
|
||||||
MonoConcGHashTable *refobject_hash;
|
MonoConcGHashTable *refobject_hash;
|
||||||
|
@ -164,6 +167,11 @@ struct _MonoMemoryManager {
|
||||||
// Maps delegate trampoline addr -> delegate object
|
// Maps delegate trampoline addr -> delegate object
|
||||||
//MonoGHashTable *delegate_hash_table;
|
//MonoGHashTable *delegate_hash_table;
|
||||||
|
|
||||||
|
/* Same hashes for collectible mem managers */
|
||||||
|
MonoWeakHashTable *weak_type_hash;
|
||||||
|
MonoWeakHashTable *weak_refobject_hash;
|
||||||
|
MonoWeakHashTable *weak_type_init_exception_hash;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic instances and aggregated custom modifiers depend on many alcs, and they need to be deleted if one
|
* Generic instances and aggregated custom modifiers depend on many alcs, and they need to be deleted if one
|
||||||
* of the alcs they depend on is unloaded. For example,
|
* of the alcs they depend on is unloaded. For example,
|
||||||
|
@ -368,6 +376,15 @@ g_slist_prepend_mem_manager (MonoMemoryManager *memory_manager, GSList *list, gp
|
||||||
return new_list;
|
return new_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MonoGCHandle
|
||||||
|
mono_mem_manager_get_loader_alloc (MonoMemoryManager *mem_manager);
|
||||||
|
|
||||||
|
void
|
||||||
|
mono_mem_manager_init_reflection_hashes (MonoMemoryManager *mem_manager);
|
||||||
|
|
||||||
|
void
|
||||||
|
mono_mem_manager_start_unload (MonoMemoryManager *mem_manager);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -777,16 +777,21 @@ mono_method_get_signature_checked (MonoMethod *method, MonoImage *image, guint32
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context) {
|
if (context) {
|
||||||
MonoMethodSignature *cached;
|
MonoMethodSignature *cached, *inflated;
|
||||||
|
|
||||||
/* This signature is not owned by a MonoMethod, so need to cache */
|
/* This signature is not owned by a MonoMethod, so need to cache */
|
||||||
sig = inflate_generic_signature_checked (image, sig, context, error);
|
inflated = inflate_generic_signature_checked (image, sig, context, error);
|
||||||
if (!is_ok (error))
|
if (!is_ok (error))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
cached = mono_metadata_get_inflated_signature (sig, context);
|
if (mono_metadata_signature_equal (sig, inflated)) {
|
||||||
if (cached != sig)
|
mono_metadata_free_inflated_signature (inflated);
|
||||||
mono_metadata_free_inflated_signature (sig);
|
return sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
cached = mono_metadata_get_inflated_signature (inflated, context);
|
||||||
|
if (cached != inflated)
|
||||||
|
mono_metadata_free_inflated_signature (inflated);
|
||||||
else
|
else
|
||||||
mono_atomic_fetch_add_i32 (&inflated_signatures_size, mono_metadata_signature_size (cached));
|
mono_atomic_fetch_add_i32 (&inflated_signatures_size, mono_metadata_signature_size (cached));
|
||||||
sig = cached;
|
sig = cached;
|
||||||
|
|
|
@ -6314,3 +6314,38 @@ mono_method_has_unmanaged_callers_only_attribute (MonoMethod *method)
|
||||||
mono_custom_attrs_free (cinfo);
|
mono_custom_attrs_free (cinfo);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_hash (GHashTable *hash)
|
||||||
|
{
|
||||||
|
if (hash)
|
||||||
|
g_hash_table_destroy (hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mono_wrapper_caches_free (MonoWrapperCaches *cache)
|
||||||
|
{
|
||||||
|
free_hash (cache->delegate_invoke_cache);
|
||||||
|
free_hash (cache->delegate_begin_invoke_cache);
|
||||||
|
free_hash (cache->delegate_end_invoke_cache);
|
||||||
|
free_hash (cache->delegate_bound_static_invoke_cache);
|
||||||
|
free_hash (cache->runtime_invoke_signature_cache);
|
||||||
|
|
||||||
|
free_hash (cache->delegate_abstract_invoke_cache);
|
||||||
|
|
||||||
|
free_hash (cache->runtime_invoke_method_cache);
|
||||||
|
free_hash (cache->managed_wrapper_cache);
|
||||||
|
|
||||||
|
free_hash (cache->native_wrapper_cache);
|
||||||
|
free_hash (cache->native_wrapper_aot_cache);
|
||||||
|
free_hash (cache->native_wrapper_check_cache);
|
||||||
|
free_hash (cache->native_wrapper_aot_check_cache);
|
||||||
|
|
||||||
|
free_hash (cache->native_func_wrapper_aot_cache);
|
||||||
|
free_hash (cache->native_func_wrapper_indirect_cache);
|
||||||
|
free_hash (cache->synchronized_cache);
|
||||||
|
free_hash (cache->unbox_wrapper_cache);
|
||||||
|
free_hash (cache->cominterop_invoke_cache);
|
||||||
|
free_hash (cache->cominterop_wrapper_cache);
|
||||||
|
free_hash (cache->thunk_invoke_cache);
|
||||||
|
}
|
||||||
|
|
|
@ -3,8 +3,11 @@
|
||||||
#include <mono/metadata/reflection-cache.h>
|
#include <mono/metadata/reflection-cache.h>
|
||||||
#include <mono/metadata/mono-hash-internals.h>
|
#include <mono/metadata/mono-hash-internals.h>
|
||||||
#include <mono/metadata/debug-internals.h>
|
#include <mono/metadata/debug-internals.h>
|
||||||
|
#include <mono/metadata/object-internals.h>
|
||||||
#include <mono/utils/unlocked.h>
|
#include <mono/utils/unlocked.h>
|
||||||
|
|
||||||
|
static GENERATE_GET_CLASS_WITH_CACHE (loader_allocator, "System.Reflection", "LoaderAllocator");
|
||||||
|
|
||||||
static LockFreeMempool*
|
static LockFreeMempool*
|
||||||
lock_free_mempool_new (void)
|
lock_free_mempool_new (void)
|
||||||
{
|
{
|
||||||
|
@ -118,9 +121,18 @@ mono_mem_manager_new (MonoAssemblyLoadContext **alcs, int nalcs, gboolean collec
|
||||||
memory_manager->class_vtable_array = g_ptr_array_new ();
|
memory_manager->class_vtable_array = g_ptr_array_new ();
|
||||||
|
|
||||||
// TODO: make these not linked to the domain for debugging
|
// TODO: make these not linked to the domain for debugging
|
||||||
memory_manager->type_hash = mono_g_hash_table_new_type_internal ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain Reflection Type Table");
|
if (!collectible) {
|
||||||
memory_manager->refobject_hash = mono_conc_g_hash_table_new_type (mono_reflected_hash, mono_reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain Reflection Object Table");
|
memory_manager->type_hash = mono_g_hash_table_new_type_internal ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain Reflection Type Table");
|
||||||
memory_manager->type_init_exception_hash = mono_g_hash_table_new_type_internal (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain Type Initialization Exception Table");
|
memory_manager->refobject_hash = mono_conc_g_hash_table_new_type (mono_reflected_hash, mono_reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain Reflection Object Table");
|
||||||
|
memory_manager->type_init_exception_hash = mono_g_hash_table_new_type_internal (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain Type Initialization Exception Table");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register it into its ALCs */
|
||||||
|
for (int i = 0; i < nalcs; ++i) {
|
||||||
|
mono_alc_memory_managers_lock (alcs [i]);
|
||||||
|
g_ptr_array_add (alcs [i]->generic_memory_managers, memory_manager);
|
||||||
|
mono_alc_memory_managers_unlock (alcs [i]);
|
||||||
|
}
|
||||||
|
|
||||||
if (mono_get_runtime_callbacks ()->init_mem_manager)
|
if (mono_get_runtime_callbacks ()->init_mem_manager)
|
||||||
mono_get_runtime_callbacks ()->init_mem_manager (memory_manager);
|
mono_get_runtime_callbacks ()->init_mem_manager (memory_manager);
|
||||||
|
@ -143,6 +155,15 @@ unregister_vtable_reflection_type (MonoVTable *vtable)
|
||||||
MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
|
MONO_GC_UNREGISTER_ROOT_IF_MOVING (vtable->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_weak_hash (MonoWeakHashTable **hash)
|
||||||
|
{
|
||||||
|
if (*hash) {
|
||||||
|
mono_weak_hash_table_destroy (*hash);
|
||||||
|
*hash = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// First phase of deletion
|
// First phase of deletion
|
||||||
static void
|
static void
|
||||||
memory_manager_delete_objects (MonoMemoryManager *memory_manager)
|
memory_manager_delete_objects (MonoMemoryManager *memory_manager)
|
||||||
|
@ -150,18 +171,37 @@ memory_manager_delete_objects (MonoMemoryManager *memory_manager)
|
||||||
memory_manager->freeing = TRUE;
|
memory_manager->freeing = TRUE;
|
||||||
|
|
||||||
// Must be done before type_hash is freed
|
// Must be done before type_hash is freed
|
||||||
for (guint i = 0; i < memory_manager->class_vtable_array->len; i++)
|
if (!memory_manager->collectible) {
|
||||||
unregister_vtable_reflection_type ((MonoVTable *)g_ptr_array_index (memory_manager->class_vtable_array, i));
|
// FIXME:
|
||||||
|
for (guint i = 0; i < memory_manager->class_vtable_array->len; i++)
|
||||||
|
unregister_vtable_reflection_type ((MonoVTable *)g_ptr_array_index (memory_manager->class_vtable_array, i));
|
||||||
|
}
|
||||||
|
|
||||||
g_ptr_array_free (memory_manager->class_vtable_array, TRUE);
|
g_ptr_array_free (memory_manager->class_vtable_array, TRUE);
|
||||||
memory_manager->class_vtable_array = NULL;
|
memory_manager->class_vtable_array = NULL;
|
||||||
mono_g_hash_table_destroy (memory_manager->type_hash);
|
|
||||||
memory_manager->type_hash = NULL;
|
if (!memory_manager->collectible) {
|
||||||
mono_conc_g_hash_table_foreach (memory_manager->refobject_hash, cleanup_refobject_hash, NULL);
|
mono_g_hash_table_destroy (memory_manager->type_hash);
|
||||||
mono_conc_g_hash_table_destroy (memory_manager->refobject_hash);
|
memory_manager->type_hash = NULL;
|
||||||
memory_manager->refobject_hash = NULL;
|
mono_conc_g_hash_table_foreach (memory_manager->refobject_hash, cleanup_refobject_hash, NULL);
|
||||||
mono_g_hash_table_destroy (memory_manager->type_init_exception_hash);
|
mono_conc_g_hash_table_destroy (memory_manager->refobject_hash);
|
||||||
memory_manager->type_init_exception_hash = NULL;
|
memory_manager->refobject_hash = NULL;
|
||||||
|
mono_g_hash_table_destroy (memory_manager->type_init_exception_hash);
|
||||||
|
memory_manager->type_init_exception_hash = NULL;
|
||||||
|
} else {
|
||||||
|
free_weak_hash (&memory_manager->weak_type_hash);
|
||||||
|
free_weak_hash (&memory_manager->weak_type_init_exception_hash);
|
||||||
|
// FIXME: Call cleanup_refobject_hash
|
||||||
|
free_weak_hash (&memory_manager->weak_refobject_hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_hash (GHashTable **hash)
|
||||||
|
{
|
||||||
|
if (*hash)
|
||||||
|
g_hash_table_destroy (*hash);
|
||||||
|
*hash = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Full deletion
|
// Full deletion
|
||||||
|
@ -181,6 +221,27 @@ memory_manager_delete (MonoMemoryManager *memory_manager, gboolean debug_unload)
|
||||||
if (!memory_manager->freeing)
|
if (!memory_manager->freeing)
|
||||||
memory_manager_delete_objects (memory_manager);
|
memory_manager_delete_objects (memory_manager);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Most memory held by these hashes is allocated from the
|
||||||
|
* mempool, but there might some extra logic needed
|
||||||
|
* like freeing interface ids.
|
||||||
|
* The free functions of the hashes are in metadata.c.
|
||||||
|
*/
|
||||||
|
MonoMemoryManager *mm = memory_manager;
|
||||||
|
if (mm->gclass_cache)
|
||||||
|
mono_conc_hashtable_destroy (mm->gclass_cache);
|
||||||
|
free_hash (&mm->ginst_cache);
|
||||||
|
free_hash (&mm->gmethod_cache);
|
||||||
|
free_hash (&mm->gsignature_cache);
|
||||||
|
free_hash (&mm->szarray_cache);
|
||||||
|
free_hash (&mm->array_cache);
|
||||||
|
free_hash (&mm->ptr_cache);
|
||||||
|
free_hash (&mm->aggregate_modifiers_cache);
|
||||||
|
mono_wrapper_caches_free (&mm->wrapper_caches);
|
||||||
|
for (int i = 0; i < mm->gshared_types_len; ++i)
|
||||||
|
free_hash (&mm->gshared_types [i]);
|
||||||
|
g_free (mm->gshared_types);
|
||||||
|
|
||||||
mono_coop_mutex_destroy (&memory_manager->lock);
|
mono_coop_mutex_destroy (&memory_manager->lock);
|
||||||
|
|
||||||
// FIXME: Free generics caches
|
// FIXME: Free generics caches
|
||||||
|
@ -188,6 +249,7 @@ memory_manager_delete (MonoMemoryManager *memory_manager, gboolean debug_unload)
|
||||||
if (debug_unload) {
|
if (debug_unload) {
|
||||||
mono_mempool_invalidate (memory_manager->_mp);
|
mono_mempool_invalidate (memory_manager->_mp);
|
||||||
mono_code_manager_invalidate (memory_manager->code_mp);
|
mono_code_manager_invalidate (memory_manager->code_mp);
|
||||||
|
memset (memory_manager, 0x42, sizeof (MonoMemoryManager));
|
||||||
} else {
|
} else {
|
||||||
mono_mempool_destroy (memory_manager->_mp);
|
mono_mempool_destroy (memory_manager->_mp);
|
||||||
memory_manager->_mp = NULL;
|
memory_manager->_mp = NULL;
|
||||||
|
@ -207,8 +269,6 @@ mono_mem_manager_free_objects (MonoMemoryManager *memory_manager)
|
||||||
void
|
void
|
||||||
mono_mem_manager_free (MonoMemoryManager *memory_manager, gboolean debug_unload)
|
mono_mem_manager_free (MonoMemoryManager *memory_manager, gboolean debug_unload)
|
||||||
{
|
{
|
||||||
g_assert (!memory_manager->is_generic);
|
|
||||||
|
|
||||||
memory_manager_delete (memory_manager, debug_unload);
|
memory_manager_delete (memory_manager, debug_unload);
|
||||||
g_free (memory_manager);
|
g_free (memory_manager);
|
||||||
}
|
}
|
||||||
|
@ -470,17 +530,8 @@ get_mem_manager_for_alcs (MonoAssemblyLoadContext **alcs, int nalcs)
|
||||||
|
|
||||||
/* Create new mem manager */
|
/* Create new mem manager */
|
||||||
res = mono_mem_manager_new (alcs, nalcs, collectible);
|
res = mono_mem_manager_new (alcs, nalcs, collectible);
|
||||||
res->is_generic = TRUE;
|
|
||||||
|
|
||||||
/* The hashes are lazily inited in metadata.c */
|
/* The hashes are lazily inited in metadata.c */
|
||||||
|
|
||||||
/* Register it into its ALCs */
|
|
||||||
for (int i = 0; i < nalcs; ++i) {
|
|
||||||
mono_alc_memory_managers_lock (alcs [i]);
|
|
||||||
g_ptr_array_add (alcs [i]->generic_memory_managers, res);
|
|
||||||
mono_alc_memory_managers_unlock (alcs [i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
mono_memory_barrier ();
|
mono_memory_barrier ();
|
||||||
|
|
||||||
mem_manager_cache_add (res);
|
mem_manager_cache_add (res);
|
||||||
|
@ -549,3 +600,118 @@ mono_mem_manager_merge (MonoMemoryManager *mm1, MonoMemoryManager *mm2)
|
||||||
}
|
}
|
||||||
return get_mem_manager_for_alcs (alcs, nalcs);
|
return get_mem_manager_for_alcs (alcs, nalcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return a GC handle for the LoaderAllocator object
|
||||||
|
* which corresponds to the mem manager.
|
||||||
|
* Return NULL if the mem manager is not collectible.
|
||||||
|
* This is done lazily since mem managers can be created from metadata code.
|
||||||
|
*/
|
||||||
|
MonoGCHandle
|
||||||
|
mono_mem_manager_get_loader_alloc (MonoMemoryManager *mem_manager)
|
||||||
|
{
|
||||||
|
ERROR_DECL (error);
|
||||||
|
MonoGCHandle res;
|
||||||
|
|
||||||
|
if (!mem_manager->collectible)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (mem_manager->loader_allocator_weak_handle)
|
||||||
|
return mem_manager->loader_allocator_weak_handle;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the LoaderAllocator object which is used to detect whenever there are managed
|
||||||
|
* references to this memory manager.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Try to do most of the construction outside the lock */
|
||||||
|
MonoObject *loader_alloc = mono_object_new_pinned (mono_class_get_loader_allocator_class (), error);
|
||||||
|
mono_error_assert_ok (error);
|
||||||
|
|
||||||
|
/* This will keep the object alive until unload has started */
|
||||||
|
mem_manager->loader_allocator_handle = mono_gchandle_new_internal (loader_alloc, TRUE);
|
||||||
|
|
||||||
|
MonoMethod *method = mono_class_get_method_from_name_checked (mono_class_get_loader_allocator_class (), ".ctor", 1, 0, error);
|
||||||
|
mono_error_assert_ok (error);
|
||||||
|
g_assert (method);
|
||||||
|
|
||||||
|
/* loader_alloc is pinned */
|
||||||
|
gpointer params [1] = { &mem_manager };
|
||||||
|
mono_runtime_invoke_checked (method, loader_alloc, params, error);
|
||||||
|
mono_error_assert_ok (error);
|
||||||
|
|
||||||
|
mono_mem_manager_lock (mem_manager);
|
||||||
|
res = mem_manager->loader_allocator_weak_handle;
|
||||||
|
if (!res) {
|
||||||
|
res = mono_gchandle_new_weakref_internal (loader_alloc, TRUE);
|
||||||
|
mono_memory_barrier ();
|
||||||
|
mem_manager->loader_allocator_weak_handle = res;
|
||||||
|
} else {
|
||||||
|
/* FIXME: The LoaderAllocator object has a finalizer, which shouldn't execute */
|
||||||
|
}
|
||||||
|
mono_mem_manager_unlock (mem_manager);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize reflection hashes in MEM_MANAGER.
|
||||||
|
* This is done on demand, see get_loader_alloc ().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
mono_mem_manager_init_reflection_hashes (MonoMemoryManager *mem_manager)
|
||||||
|
{
|
||||||
|
ERROR_DECL (error);
|
||||||
|
|
||||||
|
if (!mem_manager->collectible)
|
||||||
|
return;
|
||||||
|
if (mem_manager->weak_refobject_hash)
|
||||||
|
return;
|
||||||
|
|
||||||
|
MonoGCHandle loader_alloc_handle = mono_mem_manager_get_loader_alloc (mem_manager);
|
||||||
|
MonoManagedLoaderAllocator *loader_alloc = (MonoManagedLoaderAllocator*)mono_gchandle_get_target_internal (loader_alloc_handle);
|
||||||
|
|
||||||
|
const int nhashes = 3;
|
||||||
|
|
||||||
|
/* Create a set of object[2] arrays to hold arrays of keys/values, store them into LoaderAllocator.m_hashes */
|
||||||
|
/* Create these outside the lock */
|
||||||
|
|
||||||
|
MonoArray *holders_arr = mono_array_new_checked (mono_get_object_class (), nhashes, error);
|
||||||
|
mono_error_assert_ok (error);
|
||||||
|
|
||||||
|
// FIXME: GC safety
|
||||||
|
|
||||||
|
MonoArray *holders [16];
|
||||||
|
MonoGCHandle holder_handles [16];
|
||||||
|
for (int i = 0; i < nhashes; ++i) {
|
||||||
|
holders [i] = mono_array_new_checked (mono_get_object_class (), 2, error);
|
||||||
|
mono_error_assert_ok (error);
|
||||||
|
mono_array_setref_fast (holders_arr, i, holders [i]);
|
||||||
|
holder_handles [i] = mono_gchandle_new_weakref_internal ((MonoObject*)holders [i], FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
mono_mem_manager_lock (mem_manager);
|
||||||
|
if (!mem_manager->weak_refobject_hash) {
|
||||||
|
MONO_OBJECT_SETREF_INTERNAL (loader_alloc, m_hashes, holders_arr);
|
||||||
|
|
||||||
|
mem_manager->weak_type_hash = mono_weak_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal, MONO_HASH_VALUE_GC, holder_handles [0]);
|
||||||
|
mem_manager->weak_type_init_exception_hash = mono_weak_hash_table_new (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, holder_handles [1]);
|
||||||
|
MonoWeakHashTable *hash = mono_weak_hash_table_new (mono_reflected_hash, mono_reflected_equal, MONO_HASH_VALUE_GC, holder_handles [2]);
|
||||||
|
mono_memory_barrier ();
|
||||||
|
|
||||||
|
/* Set this last because of the double checked locking above */
|
||||||
|
mem_manager->weak_refobject_hash = hash;
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < nhashes; ++i)
|
||||||
|
mono_gchandle_free_internal (holder_handles [i]);
|
||||||
|
}
|
||||||
|
mono_mem_manager_unlock (mem_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mono_mem_manager_start_unload (MonoMemoryManager *mem_manager)
|
||||||
|
{
|
||||||
|
/* Free the strong handle so the LoaderAllocator object can be freed */
|
||||||
|
MonoGCHandle loader_handle = mem_manager->loader_allocator_handle;
|
||||||
|
mono_gchandle_free_internal (loader_handle);
|
||||||
|
}
|
||||||
|
|
|
@ -3216,7 +3216,7 @@ check_gmethod (gpointer key, gpointer value, gpointer data)
|
||||||
static void
|
static void
|
||||||
free_generic_inst (MonoGenericInst *ginst)
|
free_generic_inst (MonoGenericInst *ginst)
|
||||||
{
|
{
|
||||||
/* The ginst itself is allocated from the image set mempool */
|
/* The ginst itself is allocated from the mem manager */
|
||||||
for (guint i = 0; i < ginst->type_argc; ++i)
|
for (guint i = 0; i < ginst->type_argc; ++i)
|
||||||
mono_metadata_free_type (ginst->type_argv [i]);
|
mono_metadata_free_type (ginst->type_argv [i]);
|
||||||
}
|
}
|
||||||
|
@ -3224,7 +3224,7 @@ free_generic_inst (MonoGenericInst *ginst)
|
||||||
static void
|
static void
|
||||||
free_generic_class (MonoGenericClass *gclass)
|
free_generic_class (MonoGenericClass *gclass)
|
||||||
{
|
{
|
||||||
/* The gclass itself is allocated from the image set mempool */
|
/* The gclass itself is allocated from the mem manager */
|
||||||
if (gclass->cached_class && m_class_get_interface_id (gclass->cached_class))
|
if (gclass->cached_class && m_class_get_interface_id (gclass->cached_class))
|
||||||
mono_unload_interface_id (gclass->cached_class);
|
mono_unload_interface_id (gclass->cached_class);
|
||||||
}
|
}
|
||||||
|
@ -3269,9 +3269,11 @@ mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericConte
|
||||||
|
|
||||||
if (!mm->gsignature_cache)
|
if (!mm->gsignature_cache)
|
||||||
mm->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature);
|
mm->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature);
|
||||||
|
// FIXME: The lookup is done on the newly allocated sig so it always fails
|
||||||
res = (MonoInflatedMethodSignature *)g_hash_table_lookup (mm->gsignature_cache, &helper);
|
res = (MonoInflatedMethodSignature *)g_hash_table_lookup (mm->gsignature_cache, &helper);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
res = mono_mem_manager_alloc0 (mm, sizeof (MonoInflatedMethodSignature));
|
res = mono_mem_manager_alloc0 (mm, sizeof (MonoInflatedMethodSignature));
|
||||||
|
// FIXME: sig is an inflated signature not owned by the mem manager
|
||||||
res->sig = sig;
|
res->sig = sig;
|
||||||
res->context.class_inst = context->class_inst;
|
res->context.class_inst = context->class_inst;
|
||||||
res->context.method_inst = context->method_inst;
|
res->context.method_inst = context->method_inst;
|
||||||
|
@ -3867,6 +3869,9 @@ mono_metadata_get_shared_type (MonoType *type)
|
||||||
switch (type->type){
|
switch (type->type){
|
||||||
case MONO_TYPE_CLASS:
|
case MONO_TYPE_CLASS:
|
||||||
case MONO_TYPE_VALUETYPE:
|
case MONO_TYPE_VALUETYPE:
|
||||||
|
if (m_class_get_mem_manager (type->data.klass)->collectible)
|
||||||
|
/* These can be unloaded, so references to them shouldn't be shared */
|
||||||
|
return NULL;
|
||||||
if (type == m_class_get_byval_arg (type->data.klass))
|
if (type == m_class_get_byval_arg (type->data.klass))
|
||||||
return type;
|
return type;
|
||||||
if (type == m_class_get_this_arg (type->data.klass))
|
if (type == m_class_get_this_arg (type->data.klass))
|
||||||
|
|
|
@ -440,6 +440,7 @@ TYPED_HANDLE_DECL (MonoSafeHandle);
|
||||||
struct _MonoReflectionType {
|
struct _MonoReflectionType {
|
||||||
MonoObject object;
|
MonoObject object;
|
||||||
MonoType *type;
|
MonoType *type;
|
||||||
|
MonoObject *m_keepalive;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Safely access System.Type from native code */
|
/* Safely access System.Type from native code */
|
||||||
|
@ -906,10 +907,11 @@ struct _MonoReflectionMethodBody {
|
||||||
/* Safely access System.Reflection.MethodBody from native code */
|
/* Safely access System.Reflection.MethodBody from native code */
|
||||||
TYPED_HANDLE_DECL (MonoReflectionMethodBody);
|
TYPED_HANDLE_DECL (MonoReflectionMethodBody);
|
||||||
|
|
||||||
/* System.RuntimeAssembly */
|
/* System.Reflection.RuntimeAssembly */
|
||||||
struct _MonoReflectionAssembly {
|
struct _MonoReflectionAssembly {
|
||||||
MonoObject object;
|
MonoObject object;
|
||||||
MonoAssembly *assembly;
|
MonoAssembly *assembly;
|
||||||
|
MonoObject *m_keepalive;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -1423,6 +1425,14 @@ typedef enum {
|
||||||
} MonoManagedAssemblyLoadContextInternalState;
|
} MonoManagedAssemblyLoadContextInternalState;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MonoObject object;
|
||||||
|
MonoObject *m_scout;
|
||||||
|
MonoArray *m_slots;
|
||||||
|
MonoArray *m_hashes;
|
||||||
|
int m_nslots;
|
||||||
|
} MonoManagedLoaderAllocator;
|
||||||
|
|
||||||
/* All MonoInternalThread instances should be pinned, so it's safe to use the raw ptr. However
|
/* All MonoInternalThread instances should be pinned, so it's safe to use the raw ptr. However
|
||||||
* for uniformity, icall wrapping will make handles anyway. So this is the method for getting the payload.
|
* for uniformity, icall wrapping will make handles anyway. So this is the method for getting the payload.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -88,6 +88,9 @@ mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s,
|
||||||
static char *
|
static char *
|
||||||
mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error);
|
mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error);
|
||||||
|
|
||||||
|
static MonoArray*
|
||||||
|
mono_array_new_specific_internal (MonoVTable *vtable, uintptr_t n, gboolean pinned, MonoError *error);
|
||||||
|
|
||||||
/* Class lazy loading functions */
|
/* Class lazy loading functions */
|
||||||
static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
|
static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
|
||||||
static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
|
static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
|
||||||
|
@ -322,13 +325,18 @@ get_type_init_exception_for_vtable (MonoVTable *vtable)
|
||||||
if (!vtable->init_failed)
|
if (!vtable->init_failed)
|
||||||
g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
|
g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
|
||||||
|
|
||||||
/*
|
mono_mem_manager_init_reflection_hashes (mem_manager);
|
||||||
|
|
||||||
|
/*
|
||||||
* If the initializing thread was rudely aborted, the exception is not stored
|
* If the initializing thread was rudely aborted, the exception is not stored
|
||||||
* in the hash.
|
* in the hash.
|
||||||
*/
|
*/
|
||||||
ex = NULL;
|
ex = NULL;
|
||||||
mono_mem_manager_lock (mem_manager);
|
mono_mem_manager_lock (mem_manager);
|
||||||
ex = (MonoException *)mono_g_hash_table_lookup (mem_manager->type_init_exception_hash, klass);
|
if (mem_manager->collectible)
|
||||||
|
ex = (MonoException *)mono_weak_hash_table_lookup (mem_manager->weak_type_init_exception_hash, klass);
|
||||||
|
else
|
||||||
|
ex = (MonoException *)mono_g_hash_table_lookup (mem_manager->type_init_exception_hash, klass);
|
||||||
mono_mem_manager_unlock (mem_manager);
|
mono_mem_manager_unlock (mem_manager);
|
||||||
|
|
||||||
if (!ex) {
|
if (!ex) {
|
||||||
|
@ -570,8 +578,12 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
|
||||||
* Store the exception object so it could be thrown on subsequent
|
* Store the exception object so it could be thrown on subsequent
|
||||||
* accesses.
|
* accesses.
|
||||||
*/
|
*/
|
||||||
|
mono_mem_manager_init_reflection_hashes (mem_manager);
|
||||||
mono_mem_manager_lock (mem_manager);
|
mono_mem_manager_lock (mem_manager);
|
||||||
mono_g_hash_table_insert_internal (mem_manager->type_init_exception_hash, klass, exc_to_throw);
|
if (mem_manager->collectible)
|
||||||
|
mono_weak_hash_table_insert (mem_manager->weak_type_init_exception_hash, klass, exc_to_throw);
|
||||||
|
else
|
||||||
|
mono_g_hash_table_insert_internal (mem_manager->type_init_exception_hash, klass, exc_to_throw);
|
||||||
mono_mem_manager_unlock (mem_manager);
|
mono_mem_manager_unlock (mem_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -858,8 +870,8 @@ compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int
|
||||||
|
|
||||||
int field_offset = m_field_get_offset (field);
|
int field_offset = m_field_get_offset (field);
|
||||||
|
|
||||||
if (static_fields && field_offset == -1)
|
if (static_fields && (field->offset == -1 || field->offset == -2))
|
||||||
/* special static */
|
/* special/collectible static */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
pos = field_offset / TARGET_SIZEOF_VOID_P;
|
pos = field_offset / TARGET_SIZEOF_VOID_P;
|
||||||
|
@ -1832,6 +1844,121 @@ mono_method_add_generic_virtual_invocation (MonoVTable *vtable,
|
||||||
mono_loader_unlock ();
|
mono_loader_unlock ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate a slot in the LoaderAllocator.m_slots array.
|
||||||
|
* LOCKING: Assumes the loader lock is held.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
allocate_loader_alloc_slot (MonoManagedLoaderAllocator *loader_alloc)
|
||||||
|
{
|
||||||
|
ERROR_DECL (error);
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (!loader_alloc->m_slots || loader_alloc->m_nslots == mono_array_length_internal (loader_alloc->m_slots)) {
|
||||||
|
MonoClass *ac = mono_class_create_array (mono_get_object_class (), 1);
|
||||||
|
MonoVTable *vtable = mono_class_vtable_checked (ac, error);
|
||||||
|
mono_error_assert_ok (error);
|
||||||
|
|
||||||
|
/* Allocate pinned */
|
||||||
|
MonoArray *slots = mono_array_new_specific_internal (vtable, 64, TRUE, error);
|
||||||
|
|
||||||
|
if (loader_alloc->m_slots) {
|
||||||
|
/* Store the old array into the new one */
|
||||||
|
mono_array_setref_fast (slots, 0, loader_alloc->m_slots);
|
||||||
|
loader_alloc->m_nslots = 1;
|
||||||
|
}
|
||||||
|
MONO_OBJECT_SETREF_INTERNAL (loader_alloc, m_slots, slots);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = loader_alloc->m_nslots;
|
||||||
|
loader_alloc->m_nslots ++;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_collectible_static_addr (MonoMemoryManager *mem_manager, MonoClassField *field, gpointer addr)
|
||||||
|
{
|
||||||
|
/* Treat this as a special static field */
|
||||||
|
mono_mem_manager_lock (mem_manager);
|
||||||
|
if (!mem_manager->special_static_fields)
|
||||||
|
mem_manager->special_static_fields = g_hash_table_new (NULL, NULL);
|
||||||
|
g_hash_table_insert (mem_manager->special_static_fields, field, addr);
|
||||||
|
mono_mem_manager_unlock (mem_manager);
|
||||||
|
/* This marks the field as collectible static */
|
||||||
|
// FIXME: Won't work if assemblies are shared between alcs
|
||||||
|
field->offset = -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
allocate_collectible_static_fields (MonoVTable *vt, MonoMemoryManager *mem_manager)
|
||||||
|
{
|
||||||
|
MonoClass *klass = vt->klass;
|
||||||
|
MonoClassField *field;
|
||||||
|
MonoManagedLoaderAllocator *loader_alloc;
|
||||||
|
ERROR_DECL (error);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* References in static fields of a collectible alc shouldn't keep the ALC alive.
|
||||||
|
* This is implemented by storing reference type statics in object arrays in LoaderAllocator.
|
||||||
|
* Non-reference statics are stored normally.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* loader_alloc is pinned */
|
||||||
|
loader_alloc = (MonoManagedLoaderAllocator*)mono_gchandle_get_target_internal (vt->loader_alloc);
|
||||||
|
g_assert (loader_alloc);
|
||||||
|
|
||||||
|
mono_loader_lock ();
|
||||||
|
|
||||||
|
gpointer iter = NULL;
|
||||||
|
while ((field = mono_class_get_fields_internal (klass, &iter))) {
|
||||||
|
MonoType *type;
|
||||||
|
|
||||||
|
if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
|
||||||
|
continue;
|
||||||
|
if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (field->offset == -1)
|
||||||
|
/* FIXME: special static */
|
||||||
|
g_assert_not_reached ();
|
||||||
|
|
||||||
|
type = mono_type_get_underlying_type (field->type);
|
||||||
|
if (mono_type_is_reference (type)) {
|
||||||
|
int slot = allocate_loader_alloc_slot (loader_alloc);
|
||||||
|
/* The array is pinned so this internal pointer is ok */
|
||||||
|
// FIXME: Stores into this would need gc barriers
|
||||||
|
gpointer addr = mono_array_addr_internal (loader_alloc->m_slots, void*, slot);
|
||||||
|
|
||||||
|
set_collectible_static_addr (mem_manager, field, addr);
|
||||||
|
} else if (mono_type_is_primitive (type)) {
|
||||||
|
} else {
|
||||||
|
MonoClass *fclass = mono_class_from_mono_type_internal (field->type);
|
||||||
|
if (m_class_has_references (fclass) && field->offset != -2) {
|
||||||
|
/*
|
||||||
|
* Allocate a boxed object and use the unboxed address as the
|
||||||
|
* address of the static var.
|
||||||
|
*/
|
||||||
|
/* Set this early to prevent recursion */
|
||||||
|
field->offset = -2;
|
||||||
|
MonoObject *boxed = mono_object_new_pinned (fclass, error);
|
||||||
|
mono_error_assert_ok (error);
|
||||||
|
|
||||||
|
int slot = allocate_loader_alloc_slot (loader_alloc);
|
||||||
|
mono_array_setref_fast (loader_alloc->m_slots, slot, boxed);
|
||||||
|
|
||||||
|
/* The object is pinned so this internal pointer is ok */
|
||||||
|
// FIXME: Stores into this would need gc barriers
|
||||||
|
gpointer addr = mono_object_unbox_internal (boxed);
|
||||||
|
|
||||||
|
set_collectible_static_addr (mem_manager, field, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mono_loader_unlock ();
|
||||||
|
}
|
||||||
|
|
||||||
static MonoVTable *mono_class_create_runtime_vtable (MonoClass *klass, MonoError *error);
|
static MonoVTable *mono_class_create_runtime_vtable (MonoClass *klass, MonoError *error);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2034,9 +2161,12 @@ mono_class_create_runtime_vtable (MonoClass *klass, MonoError *error)
|
||||||
interface_offsets = (gpointer*)((char*)interface_offsets + imt_table_bytes / 2);
|
interface_offsets = (gpointer*)((char*)interface_offsets + imt_table_bytes / 2);
|
||||||
g_assert (!((gsize)vt & 7));
|
g_assert (!((gsize)vt & 7));
|
||||||
|
|
||||||
|
mem_manager = m_class_get_mem_manager (klass);
|
||||||
|
|
||||||
vt->klass = klass;
|
vt->klass = klass;
|
||||||
vt->rank = m_class_get_rank (klass);
|
vt->rank = m_class_get_rank (klass);
|
||||||
vt->domain = domain;
|
vt->domain = domain;
|
||||||
|
vt->loader_alloc = mono_mem_manager_get_loader_alloc (mem_manager);
|
||||||
if ((vt->rank > 0) || klass == mono_get_string_class ())
|
if ((vt->rank > 0) || klass == mono_get_string_class ())
|
||||||
vt->flags |= MONO_VT_FLAG_ARRAY_OR_STRING;
|
vt->flags |= MONO_VT_FLAG_ARRAY_OR_STRING;
|
||||||
|
|
||||||
|
@ -2057,8 +2187,10 @@ mono_class_create_runtime_vtable (MonoClass *klass, MonoError *error)
|
||||||
vt->gc_bits = gc_bits;
|
vt->gc_bits = gc_bits;
|
||||||
|
|
||||||
if (class_size) {
|
if (class_size) {
|
||||||
/* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
|
if (vt->loader_alloc && m_class_has_static_refs (klass))
|
||||||
|
allocate_collectible_static_fields (vt, mem_manager);
|
||||||
if (m_class_has_static_refs (klass)) {
|
if (m_class_has_static_refs (klass)) {
|
||||||
|
/* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
|
||||||
MonoGCDescriptor statics_gc_descr;
|
MonoGCDescriptor statics_gc_descr;
|
||||||
int max_set = 0;
|
int max_set = 0;
|
||||||
gsize default_bitmap [4] = {0};
|
gsize default_bitmap [4] = {0};
|
||||||
|
@ -2078,8 +2210,6 @@ mono_class_create_runtime_vtable (MonoClass *klass, MonoError *error)
|
||||||
UnlockedAdd (&mono_stats.class_static_data_size, class_size);
|
UnlockedAdd (&mono_stats.class_static_data_size, class_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
mem_manager = m_class_get_mem_manager (klass);
|
|
||||||
|
|
||||||
iter = NULL;
|
iter = NULL;
|
||||||
while ((field = mono_class_get_fields_internal (klass, &iter))) {
|
while ((field = mono_class_get_fields_internal (klass, &iter))) {
|
||||||
if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
|
if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
|
||||||
|
@ -2929,6 +3059,12 @@ mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
is_collectible_ref_static (MonoClassField *field)
|
||||||
|
{
|
||||||
|
return field->offset == -2;
|
||||||
|
}
|
||||||
|
|
||||||
guint8*
|
guint8*
|
||||||
mono_static_field_get_addr (MonoVTable *vt, MonoClassField *field)
|
mono_static_field_get_addr (MonoVTable *vt, MonoClassField *field)
|
||||||
{
|
{
|
||||||
|
@ -2946,6 +3082,11 @@ mono_static_field_get_addr (MonoVTable *vt, MonoClassField *field)
|
||||||
gpointer addr = mono_special_static_field_get_offset (field, error);
|
gpointer addr = mono_special_static_field_get_offset (field, error);
|
||||||
mono_error_assert_ok (error);
|
mono_error_assert_ok (error);
|
||||||
src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
|
src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
|
||||||
|
} else if (is_collectible_ref_static (field)) {
|
||||||
|
ERROR_DECL (error);
|
||||||
|
gpointer addr = mono_special_static_field_get_offset (field, error);
|
||||||
|
mono_error_assert_ok (error);
|
||||||
|
src = (guint8*)addr;
|
||||||
} else {
|
} else {
|
||||||
src = (guint8*)mono_vtable_get_static_field_data (vt) + m_field_get_offset (field);
|
src = (guint8*)mono_vtable_get_static_field_data (vt) + m_field_get_offset (field);
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,18 +69,32 @@ cache_object (MonoMemoryManager *mem_manager, MonoClass *klass, gpointer item, M
|
||||||
static inline MonoObjectHandle
|
static inline MonoObjectHandle
|
||||||
cache_object_handle (MonoMemoryManager *mem_manager, MonoClass *klass, gpointer item, MonoObjectHandle o)
|
cache_object_handle (MonoMemoryManager *mem_manager, MonoClass *klass, gpointer item, MonoObjectHandle o)
|
||||||
{
|
{
|
||||||
|
MonoObjectHandle obj;
|
||||||
ReflectedEntry pe;
|
ReflectedEntry pe;
|
||||||
pe.item = item;
|
pe.item = item;
|
||||||
pe.refclass = klass;
|
pe.refclass = klass;
|
||||||
|
|
||||||
|
mono_mem_manager_init_reflection_hashes (mem_manager);
|
||||||
|
|
||||||
mono_mem_manager_lock (mem_manager);
|
mono_mem_manager_lock (mem_manager);
|
||||||
MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, (MonoObject *)mono_conc_g_hash_table_lookup (mem_manager->refobject_hash, &pe));
|
if (!mem_manager->collectible) {
|
||||||
if (MONO_HANDLE_IS_NULL (obj)) {
|
obj = MONO_HANDLE_NEW (MonoObject, (MonoObject *)mono_conc_g_hash_table_lookup (mem_manager->refobject_hash, &pe));
|
||||||
ReflectedEntry *e = alloc_reflected_entry (mem_manager);
|
if (MONO_HANDLE_IS_NULL (obj)) {
|
||||||
e->item = item;
|
ReflectedEntry *e = alloc_reflected_entry (mem_manager);
|
||||||
e->refclass = klass;
|
e->item = item;
|
||||||
mono_conc_g_hash_table_insert (mem_manager->refobject_hash, e, MONO_HANDLE_RAW (o));
|
e->refclass = klass;
|
||||||
MONO_HANDLE_ASSIGN (obj, o);
|
mono_conc_g_hash_table_insert (mem_manager->refobject_hash, e, MONO_HANDLE_RAW (o));
|
||||||
|
MONO_HANDLE_ASSIGN (obj, o);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
obj = MONO_HANDLE_NEW (MonoObject, (MonoObject *)mono_weak_hash_table_lookup (mem_manager->weak_refobject_hash, &pe));
|
||||||
|
if (MONO_HANDLE_IS_NULL (obj)) {
|
||||||
|
ReflectedEntry *e = alloc_reflected_entry (mem_manager);
|
||||||
|
e->item = item;
|
||||||
|
e->refclass = klass;
|
||||||
|
mono_weak_hash_table_insert (mem_manager->weak_refobject_hash, e, MONO_HANDLE_RAW (o));
|
||||||
|
MONO_HANDLE_ASSIGN (obj, o);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mono_mem_manager_unlock (mem_manager);
|
mono_mem_manager_unlock (mem_manager);
|
||||||
return obj;
|
return obj;
|
||||||
|
@ -99,9 +113,16 @@ check_object_handle (MonoMemoryManager *mem_manager, MonoClass *klass, gpointer
|
||||||
|
|
||||||
// FIXME: May need a memory manager for item+klass ?
|
// FIXME: May need a memory manager for item+klass ?
|
||||||
|
|
||||||
|
mono_mem_manager_init_reflection_hashes (mem_manager);
|
||||||
|
|
||||||
mono_mem_manager_lock (mem_manager);
|
mono_mem_manager_lock (mem_manager);
|
||||||
MonoConcGHashTable *hash = mem_manager->refobject_hash;
|
if (!mem_manager->collectible) {
|
||||||
obj_handle = MONO_HANDLE_NEW (MonoObject, (MonoObject *)mono_conc_g_hash_table_lookup (hash, &e));
|
MonoConcGHashTable *hash = mem_manager->refobject_hash;
|
||||||
|
obj_handle = MONO_HANDLE_NEW (MonoObject, (MonoObject *)mono_conc_g_hash_table_lookup (hash, &e));
|
||||||
|
} else {
|
||||||
|
MonoWeakHashTable *hash = mem_manager->weak_refobject_hash;
|
||||||
|
obj_handle = MONO_HANDLE_NEW (MonoObject, (MonoObject *)mono_weak_hash_table_lookup (hash, &e));
|
||||||
|
}
|
||||||
mono_mem_manager_unlock (mem_manager);
|
mono_mem_manager_unlock (mem_manager);
|
||||||
|
|
||||||
return obj_handle;
|
return obj_handle;
|
||||||
|
|
|
@ -188,6 +188,7 @@ clear_cached_object (MonoMemoryManager *mem_manager, gpointer o, MonoClass *klas
|
||||||
|
|
||||||
if (mono_conc_g_hash_table_lookup_extended (mem_manager->refobject_hash, &pe, &orig_pe, &orig_value)) {
|
if (mono_conc_g_hash_table_lookup_extended (mem_manager->refobject_hash, &pe, &orig_pe, &orig_value)) {
|
||||||
mono_conc_g_hash_table_remove (mem_manager->refobject_hash, &pe);
|
mono_conc_g_hash_table_remove (mem_manager->refobject_hash, &pe);
|
||||||
|
// FIXME: These are mempool allocated, so they are not really freed
|
||||||
free_reflected_entry ((ReflectedEntry *)orig_pe);
|
free_reflected_entry ((ReflectedEntry *)orig_pe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,9 +217,18 @@ mono_assembly_get_object (MonoDomain *domain, MonoAssembly *assembly)
|
||||||
static MonoReflectionAssemblyHandle
|
static MonoReflectionAssemblyHandle
|
||||||
assembly_object_construct (MonoClass *unused_klass, MonoAssembly *assembly, gpointer user_data, MonoError *error)
|
assembly_object_construct (MonoClass *unused_klass, MonoAssembly *assembly, gpointer user_data, MonoError *error)
|
||||||
{
|
{
|
||||||
|
MonoMemoryManager *mm = m_image_get_mem_manager (assembly->image);
|
||||||
|
|
||||||
error_init (error);
|
error_init (error);
|
||||||
MonoReflectionAssemblyHandle res = MONO_HANDLE_CAST (MonoReflectionAssembly, mono_object_new_handle (mono_class_get_mono_assembly_class (), error));
|
MonoReflectionAssemblyHandle res = MONO_HANDLE_CAST (MonoReflectionAssembly, mono_object_new_handle (mono_class_get_mono_assembly_class (), error));
|
||||||
return_val_if_nok (error, MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE));
|
return_val_if_nok (error, MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE));
|
||||||
|
|
||||||
|
if (mm->collectible) {
|
||||||
|
MonoObject *loader_alloc = mono_gchandle_get_target_internal (mono_mem_manager_get_loader_alloc (mm));
|
||||||
|
g_assert (loader_alloc);
|
||||||
|
MONO_HANDLE_SETRAW (res, m_keepalive, loader_alloc);
|
||||||
|
}
|
||||||
|
|
||||||
MONO_HANDLE_SETVAL (res, assembly, MonoAssembly*, assembly);
|
MONO_HANDLE_SETVAL (res, assembly, MonoAssembly*, assembly);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -478,9 +488,13 @@ mono_type_get_object_checked (MonoType *type, MonoError *error)
|
||||||
return (MonoReflectionType *)vtable->type;
|
return (MonoReflectionType *)vtable->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mono_mem_manager_init_reflection_hashes (memory_manager);
|
||||||
mono_loader_lock (); /*FIXME mono_class_init_internal and mono_class_vtable acquire it*/
|
mono_loader_lock (); /*FIXME mono_class_init_internal and mono_class_vtable acquire it*/
|
||||||
mono_mem_manager_lock (memory_manager);
|
mono_mem_manager_lock (memory_manager);
|
||||||
res = (MonoReflectionType *)mono_g_hash_table_lookup (memory_manager->type_hash, type);
|
if (memory_manager->collectible)
|
||||||
|
res = (MonoReflectionType *)mono_weak_hash_table_lookup (memory_manager->weak_type_hash, type);
|
||||||
|
else
|
||||||
|
res = (MonoReflectionType *)mono_g_hash_table_lookup (memory_manager->type_hash, type);
|
||||||
mono_mem_manager_unlock (memory_manager);
|
mono_mem_manager_unlock (memory_manager);
|
||||||
if (res)
|
if (res)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
@ -498,11 +512,17 @@ mono_type_get_object_checked (MonoType *type, MonoError *error)
|
||||||
goto_if_nok (error, leave);
|
goto_if_nok (error, leave);
|
||||||
|
|
||||||
mono_mem_manager_lock (memory_manager);
|
mono_mem_manager_lock (memory_manager);
|
||||||
cached = (MonoReflectionType *)mono_g_hash_table_lookup (memory_manager->type_hash, type);
|
if (memory_manager->collectible)
|
||||||
|
cached = mono_weak_hash_table_lookup (memory_manager->weak_type_hash, type);
|
||||||
|
else
|
||||||
|
cached = (MonoReflectionType *)mono_g_hash_table_lookup (memory_manager->type_hash, type);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
res = cached;
|
res = cached;
|
||||||
} else {
|
} else {
|
||||||
mono_g_hash_table_insert_internal (memory_manager->type_hash, type, res);
|
if (memory_manager->collectible)
|
||||||
|
mono_weak_hash_table_insert (memory_manager->weak_type_hash, type, res);
|
||||||
|
else
|
||||||
|
mono_g_hash_table_insert_internal (memory_manager->type_hash, type, res);
|
||||||
}
|
}
|
||||||
mono_mem_manager_unlock (memory_manager);
|
mono_mem_manager_unlock (memory_manager);
|
||||||
goto leave;
|
goto leave;
|
||||||
|
@ -539,13 +559,24 @@ mono_type_get_object_checked (MonoType *type, MonoError *error)
|
||||||
goto_if_nok (error, leave);
|
goto_if_nok (error, leave);
|
||||||
|
|
||||||
res->type = type;
|
res->type = type;
|
||||||
|
if (memory_manager->collectible) {
|
||||||
|
MonoObject *loader_alloc = mono_gchandle_get_target_internal (mono_mem_manager_get_loader_alloc (memory_manager));
|
||||||
|
g_assert (loader_alloc);
|
||||||
|
MONO_OBJECT_SETREF_INTERNAL (res, m_keepalive, loader_alloc);
|
||||||
|
}
|
||||||
|
|
||||||
mono_mem_manager_lock (memory_manager);
|
mono_mem_manager_lock (memory_manager);
|
||||||
cached = (MonoReflectionType *)mono_g_hash_table_lookup (memory_manager->type_hash, type);
|
if (memory_manager->collectible)
|
||||||
|
cached = (MonoReflectionType *)mono_weak_hash_table_lookup (memory_manager->weak_type_hash, type);
|
||||||
|
else
|
||||||
|
cached = (MonoReflectionType *)mono_g_hash_table_lookup (memory_manager->type_hash, type);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
res = cached;
|
res = cached;
|
||||||
} else {
|
} else {
|
||||||
mono_g_hash_table_insert_internal (memory_manager->type_hash, type, res);
|
if (memory_manager->collectible)
|
||||||
|
mono_weak_hash_table_insert (memory_manager->weak_type_hash, type, res);
|
||||||
|
else
|
||||||
|
mono_g_hash_table_insert_internal (memory_manager->type_hash, type, res);
|
||||||
if (type->type == MONO_TYPE_VOID && !m_type_is_byref (type))
|
if (type->type == MONO_TYPE_VOID && !m_type_is_byref (type))
|
||||||
domain->typeof_void = (MonoObject*)res;
|
domain->typeof_void = (MonoObject*)res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,24 @@ sgen_vtable_get_descriptor (GCVTable vtable)
|
||||||
return (SgenDescriptor)vtable->gc_descr;
|
return (SgenDescriptor)vtable->gc_descr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline gboolean
|
||||||
|
sgen_vtable_has_class_obj (GCVTable vtable)
|
||||||
|
{
|
||||||
|
MonoGCHandle *handle = vtable->loader_alloc;
|
||||||
|
return handle != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline GCObject*
|
||||||
|
sgen_vtable_get_class_obj (GCVTable vtable)
|
||||||
|
{
|
||||||
|
MonoGCHandle *handle = vtable->loader_alloc;
|
||||||
|
if (handle)
|
||||||
|
/* This could return NULL during unloading */
|
||||||
|
return (GCObject*)mono_gchandle_get_target_internal (handle);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct _SgenClientThreadInfo SgenClientThreadInfo;
|
typedef struct _SgenClientThreadInfo SgenClientThreadInfo;
|
||||||
struct _SgenClientThreadInfo {
|
struct _SgenClientThreadInfo {
|
||||||
MonoThreadInfo info;
|
MonoThreadInfo info;
|
||||||
|
|
353
src/mono/mono/metadata/weak-hash.c
Normal file
353
src/mono/mono/metadata/weak-hash.c
Normal file
|
@ -0,0 +1,353 @@
|
||||||
|
/* Based on mono-hash.c. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is similar to MonoGHashTable, but it doesn't keep the keys/values alive.
|
||||||
|
* Instead, keys/values are stored in object[] arrays kept alive by a object[2]
|
||||||
|
* which is referenced by a weak ref.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "weak-hash.h"
|
||||||
|
#include "metadata/gc-internals.h"
|
||||||
|
|
||||||
|
#include <mono/utils/checked-build.h>
|
||||||
|
#include <mono/utils/mono-threads-coop.h>
|
||||||
|
#include <mono/utils/unlocked.h>
|
||||||
|
|
||||||
|
struct _MonoWeakHashTable {
|
||||||
|
GHashFunc hash_func;
|
||||||
|
GEqualFunc key_equal_func;
|
||||||
|
|
||||||
|
/* Only set if the keys/values are not GC tracked */
|
||||||
|
MonoObject **keys;
|
||||||
|
MonoObject **values;
|
||||||
|
int table_size;
|
||||||
|
int in_use;
|
||||||
|
MonoGHashGCType gc_type;
|
||||||
|
// Weak handle to a object[2]
|
||||||
|
MonoGCHandle key_value_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HASH_TABLE_MAX_LOAD_FACTOR 0.7f
|
||||||
|
/* We didn't really do compaction before, keep it lenient for now */
|
||||||
|
#define HASH_TABLE_MIN_LOAD_FACTOR 0.05f
|
||||||
|
/* We triple the table size at rehash time, similar with previous implementation */
|
||||||
|
#define HASH_TABLE_RESIZE_RATIO 3
|
||||||
|
|
||||||
|
static MonoArray*
|
||||||
|
get_keys (MonoWeakHashTable *hash)
|
||||||
|
{
|
||||||
|
// FIXME: Do it in the caller
|
||||||
|
MonoArray *holder = (MonoArray*)mono_gchandle_get_target_internal (hash->key_value_handle);
|
||||||
|
/* This is expected to be alive */
|
||||||
|
g_assert (holder);
|
||||||
|
return mono_array_get_fast (holder, MonoArray*, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MonoArray*
|
||||||
|
get_values (MonoWeakHashTable *hash)
|
||||||
|
{
|
||||||
|
MonoArray *holder = (MonoArray*)mono_gchandle_get_target_internal (hash->key_value_handle);
|
||||||
|
/* This is expected to be alive */
|
||||||
|
g_assert (holder);
|
||||||
|
return mono_array_get_fast (holder, MonoArray*, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
key_store (MonoWeakHashTable *hash, int slot, MonoObject* key)
|
||||||
|
{
|
||||||
|
if (hash->gc_type & MONO_HASH_KEY_GC) {
|
||||||
|
MonoArray *keys = get_keys (hash);
|
||||||
|
mono_array_setref_fast (keys, slot, key);
|
||||||
|
} else {
|
||||||
|
hash->keys [slot] = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
value_store (MonoWeakHashTable *hash, int slot, MonoObject* value)
|
||||||
|
{
|
||||||
|
if (hash->gc_type & MONO_HASH_VALUE_GC) {
|
||||||
|
MonoArray *values = get_values (hash);
|
||||||
|
mono_array_setref_fast (values, slot, value);
|
||||||
|
} else {
|
||||||
|
hash->values [slot] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns position of key or of an empty slot for it */
|
||||||
|
static int
|
||||||
|
mono_weak_hash_table_find_slot (MonoWeakHashTable *hash, const MonoObject *key)
|
||||||
|
{
|
||||||
|
guint start = ((*hash->hash_func) (key)) % hash->table_size;
|
||||||
|
guint i = start;
|
||||||
|
|
||||||
|
if (hash->gc_type & MONO_HASH_KEY_GC) {
|
||||||
|
MonoArray *keys = get_keys (hash);
|
||||||
|
|
||||||
|
if (hash->key_equal_func) {
|
||||||
|
GEqualFunc equal = hash->key_equal_func;
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
MonoObject *key2 = mono_array_get_fast (keys, MonoObject*, i);
|
||||||
|
if (!(key2 && !(*equal) (key2, key)))
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
if (i == hash->table_size)
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (TRUE) {
|
||||||
|
MonoObject *key2 = mono_array_get_fast (keys, MonoObject*, i);
|
||||||
|
if (!(key2 && key2 != key))
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
if (i == hash->table_size)
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (hash->key_equal_func) {
|
||||||
|
GEqualFunc equal = hash->key_equal_func;
|
||||||
|
|
||||||
|
while (hash->keys [i] && !(*equal) (hash->keys [i], key)) {
|
||||||
|
i++;
|
||||||
|
if (i == hash->table_size)
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (hash->keys [i] && hash->keys [i] != key) {
|
||||||
|
i++;
|
||||||
|
if (i == hash->table_size)
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
MonoWeakHashTable *
|
||||||
|
mono_weak_hash_table_new (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type, MonoGCHandle key_value_handle)
|
||||||
|
{
|
||||||
|
MONO_REQ_GC_UNSAFE_MODE;
|
||||||
|
MonoWeakHashTable *hash;
|
||||||
|
ERROR_DECL (error);
|
||||||
|
MonoArray *holder;
|
||||||
|
|
||||||
|
if (!hash_func)
|
||||||
|
hash_func = g_direct_hash;
|
||||||
|
|
||||||
|
hash = g_new0 (MonoWeakHashTable, 1);
|
||||||
|
|
||||||
|
hash->hash_func = hash_func;
|
||||||
|
hash->key_equal_func = key_equal_func;
|
||||||
|
hash->table_size = g_spaced_primes_closest (1);
|
||||||
|
hash->gc_type = type;
|
||||||
|
hash->key_value_handle = key_value_handle;
|
||||||
|
|
||||||
|
g_assert (type <= MONO_HASH_KEY_VALUE_GC);
|
||||||
|
|
||||||
|
holder = (MonoArray*)mono_gchandle_get_target_internal (key_value_handle);
|
||||||
|
g_assert (holder);
|
||||||
|
|
||||||
|
if (hash->gc_type & MONO_HASH_KEY_GC) {
|
||||||
|
MonoArray *keys = mono_array_new_checked (mono_get_object_class (), hash->table_size, error);
|
||||||
|
mono_error_assert_ok (error);
|
||||||
|
mono_array_setref_fast (holder, 0, keys);
|
||||||
|
} else {
|
||||||
|
hash->keys = g_new0 (MonoObject*, hash->table_size);
|
||||||
|
}
|
||||||
|
if (hash->gc_type & MONO_HASH_VALUE_GC) {
|
||||||
|
MonoArray *values = mono_array_new_checked (mono_get_object_class (), hash->table_size, error);
|
||||||
|
mono_error_assert_ok (error);
|
||||||
|
mono_array_setref_fast (holder, 1, values);
|
||||||
|
} else {
|
||||||
|
hash->values = g_new0 (MonoObject*, hash->table_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MonoWeakHashTable *hash;
|
||||||
|
int new_size;
|
||||||
|
MonoObject **keys;
|
||||||
|
MonoObject **values;
|
||||||
|
MonoArray *keys_arr;
|
||||||
|
MonoArray *values_arr;
|
||||||
|
} RehashData;
|
||||||
|
|
||||||
|
static void*
|
||||||
|
do_rehash (void *_data)
|
||||||
|
{
|
||||||
|
RehashData *data = (RehashData *)_data;
|
||||||
|
MonoWeakHashTable *hash = data->hash;
|
||||||
|
int current_size, i;
|
||||||
|
MonoObject **old_keys = NULL;
|
||||||
|
MonoArray *old_values_arr = NULL;
|
||||||
|
|
||||||
|
MonoArray *holder = (MonoArray*)mono_gchandle_get_target_internal (hash->key_value_handle);
|
||||||
|
g_assert (holder);
|
||||||
|
|
||||||
|
current_size = hash->table_size;
|
||||||
|
hash->table_size = data->new_size;
|
||||||
|
|
||||||
|
if (hash->gc_type & MONO_HASH_VALUE_GC) {
|
||||||
|
old_keys = hash->keys;
|
||||||
|
hash->keys = data->keys;
|
||||||
|
|
||||||
|
old_values_arr = get_values (hash);
|
||||||
|
mono_array_setref_fast (holder, 1, data->values_arr);
|
||||||
|
|
||||||
|
for (i = 0; i < current_size; i++) {
|
||||||
|
if (old_keys [i]) {
|
||||||
|
int slot = mono_weak_hash_table_find_slot (hash, old_keys [i]);
|
||||||
|
key_store (hash, slot, old_keys [i]);
|
||||||
|
value_store (hash, slot, mono_array_get_fast (old_values_arr, MonoObject*, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// FIXME:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rehash (MonoWeakHashTable *hash)
|
||||||
|
{
|
||||||
|
MONO_REQ_GC_UNSAFE_MODE; //we must run in unsafe mode to make rehash safe
|
||||||
|
|
||||||
|
RehashData data;
|
||||||
|
void *old_keys = hash->keys;
|
||||||
|
void *old_values = hash->values;
|
||||||
|
ERROR_DECL (error);
|
||||||
|
|
||||||
|
memset (&data, 0, sizeof (RehashData));
|
||||||
|
|
||||||
|
data.hash = hash;
|
||||||
|
/*
|
||||||
|
* Rehash to a size that can fit the current elements. Rehash relative to in_use
|
||||||
|
* to allow also for compaction.
|
||||||
|
*/
|
||||||
|
data.new_size = g_spaced_primes_closest (hash->in_use / HASH_TABLE_MAX_LOAD_FACTOR * HASH_TABLE_RESIZE_RATIO);
|
||||||
|
|
||||||
|
MonoArray *holder = (MonoArray*)mono_gchandle_get_target_internal (hash->key_value_handle);
|
||||||
|
g_assert (holder);
|
||||||
|
|
||||||
|
if (hash->gc_type & MONO_HASH_KEY_GC) {
|
||||||
|
MonoArray *keys = mono_array_new_checked (mono_get_object_class (), data.new_size, error);
|
||||||
|
mono_error_assert_ok (error);
|
||||||
|
data.keys_arr = keys;
|
||||||
|
} else {
|
||||||
|
data.keys = g_new0 (MonoObject*, data.new_size);
|
||||||
|
}
|
||||||
|
if (hash->gc_type & MONO_HASH_VALUE_GC) {
|
||||||
|
MonoArray *values = mono_array_new_checked (mono_get_object_class (), data.new_size, error);
|
||||||
|
mono_error_assert_ok (error);
|
||||||
|
data.values_arr = values;
|
||||||
|
} else {
|
||||||
|
data.values = g_new0 (MonoObject*, data.new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mono_threads_are_safepoints_enabled ()) {
|
||||||
|
// FIXME: Does this work ?
|
||||||
|
g_assert_not_reached ();
|
||||||
|
mono_gc_invoke_with_gc_lock (do_rehash, &data);
|
||||||
|
} else {
|
||||||
|
/* We cannot be preempted */
|
||||||
|
do_rehash (&data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(hash->gc_type & MONO_HASH_KEY_GC))
|
||||||
|
g_free (old_keys);
|
||||||
|
if (!(hash->gc_type & MONO_HASH_VALUE_GC))
|
||||||
|
g_free (old_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mono_weak_hash_table_size:
|
||||||
|
*/
|
||||||
|
guint
|
||||||
|
mono_weak_hash_table_size (MonoWeakHashTable *hash)
|
||||||
|
{
|
||||||
|
g_assert (hash);
|
||||||
|
|
||||||
|
return hash->in_use;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mono_weak_hash_table_lookup:
|
||||||
|
*/
|
||||||
|
gpointer
|
||||||
|
mono_weak_hash_table_lookup (MonoWeakHashTable *hash, gconstpointer key)
|
||||||
|
{
|
||||||
|
g_assert (hash);
|
||||||
|
|
||||||
|
int slot = mono_weak_hash_table_find_slot (hash, (MonoObject*)key);
|
||||||
|
|
||||||
|
// FIXME:
|
||||||
|
g_assert (hash->gc_type == MONO_HASH_VALUE_GC);
|
||||||
|
|
||||||
|
MonoArray* values = get_values (hash);
|
||||||
|
|
||||||
|
if (hash->keys [slot])
|
||||||
|
return mono_array_get_fast (values, MonoObject*, slot);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mono_weak_hash_table_destroy:
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
mono_weak_hash_table_destroy (MonoWeakHashTable *hash)
|
||||||
|
{
|
||||||
|
g_assert (hash);
|
||||||
|
|
||||||
|
if (!(hash->gc_type & MONO_HASH_KEY_GC))
|
||||||
|
g_free (hash->keys);
|
||||||
|
if (!(hash->gc_type & MONO_HASH_VALUE_GC))
|
||||||
|
g_free (hash->values);
|
||||||
|
g_free (hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mono_weak_hash_table_insert_replace (MonoWeakHashTable *hash, gpointer key, gpointer value, gboolean replace)
|
||||||
|
{
|
||||||
|
MONO_REQ_GC_UNSAFE_MODE;
|
||||||
|
int slot;
|
||||||
|
|
||||||
|
g_assert (hash);
|
||||||
|
|
||||||
|
if (hash->in_use > (hash->table_size * HASH_TABLE_MAX_LOAD_FACTOR))
|
||||||
|
rehash (hash);
|
||||||
|
|
||||||
|
slot = mono_weak_hash_table_find_slot (hash, (MonoObject*)key);
|
||||||
|
|
||||||
|
// FIXME:
|
||||||
|
g_assert (hash->gc_type == MONO_HASH_VALUE_GC);
|
||||||
|
|
||||||
|
if (hash->keys [slot]) {
|
||||||
|
if (replace) {
|
||||||
|
key_store (hash, slot, (MonoObject*)key);
|
||||||
|
}
|
||||||
|
value_store (hash, slot, (MonoObject*)value);
|
||||||
|
} else {
|
||||||
|
key_store (hash, slot, (MonoObject*)key);
|
||||||
|
value_store (hash, slot, (MonoObject*)value);
|
||||||
|
hash->in_use++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mono_weak_hash_table_insert (MonoWeakHashTable *h, gpointer k, gpointer v)
|
||||||
|
{
|
||||||
|
MONO_REQ_GC_UNSAFE_MODE;
|
||||||
|
mono_weak_hash_table_insert_replace (h, k, v, FALSE);
|
||||||
|
}
|
23
src/mono/mono/metadata/weak-hash.h
Normal file
23
src/mono/mono/metadata/weak-hash.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/* Based on mono-hash.h */
|
||||||
|
#ifndef __MONO_WEAK_HASH_H__
|
||||||
|
#define __MONO_WEAK_HASH_H__
|
||||||
|
|
||||||
|
#include <mono/metadata/mono-gc.h>
|
||||||
|
#include <mono/metadata/mono-hash.h>
|
||||||
|
|
||||||
|
typedef struct _MonoWeakHashTable MonoWeakHashTable;
|
||||||
|
|
||||||
|
MonoWeakHashTable *
|
||||||
|
mono_weak_hash_table_new (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type, MonoGCHandle key_value_handle);
|
||||||
|
guint mono_weak_hash_table_size (MonoWeakHashTable *hash);
|
||||||
|
gpointer mono_weak_hash_table_lookup (MonoWeakHashTable *hash, gconstpointer key);
|
||||||
|
gboolean mono_weak_hash_table_lookup_extended (MonoWeakHashTable *hash, gconstpointer key, gpointer *orig_key, gpointer *value);
|
||||||
|
void mono_weak_hash_table_foreach (MonoWeakHashTable *hash, GHFunc func, gpointer user_data);
|
||||||
|
gpointer mono_weak_hash_table_find (MonoWeakHashTable *hash, GHRFunc predicate, gpointer user_data);
|
||||||
|
gboolean mono_weak_hash_table_remove (MonoWeakHashTable *hash, gconstpointer key);
|
||||||
|
guint mono_weak_hash_table_foreach_remove (MonoWeakHashTable *hash, GHRFunc func, gpointer user_data);
|
||||||
|
void mono_weak_hash_table_destroy (MonoWeakHashTable *hash);
|
||||||
|
void mono_weak_hash_table_replace (MonoWeakHashTable *h, gpointer k, gpointer v);
|
||||||
|
void mono_weak_hash_table_insert (MonoWeakHashTable *h, gpointer k, gpointer v);
|
||||||
|
|
||||||
|
#endif /* __MONO_WEAK_HASH_H__ */
|
|
@ -1928,6 +1928,13 @@ load_aot_module (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer
|
||||||
if (image_is_dynamic (assembly->image))
|
if (image_is_dynamic (assembly->image))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (mono_image_get_alc (assembly->image)->collectible)
|
||||||
|
/*
|
||||||
|
* Assemblies loaded into collectible ALCs require different codegen
|
||||||
|
* due to static variable access etc.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
|
||||||
gboolean loaded = FALSE;
|
gboolean loaded = FALSE;
|
||||||
|
|
||||||
mono_aot_lock ();
|
mono_aot_lock ();
|
||||||
|
@ -3113,6 +3120,7 @@ decode_exception_debug_info (MonoAotModule *amodule,
|
||||||
/* Get the length first */
|
/* Get the length first */
|
||||||
decode_llvm_mono_eh_frame (amodule, NULL, code, code_len, clauses, num_clauses, nesting, &this_reg, &this_offset, &num_llvm_clauses);
|
decode_llvm_mono_eh_frame (amodule, NULL, code, code_len, clauses, num_clauses, nesting, &this_reg, &this_offset, &num_llvm_clauses);
|
||||||
len = mono_jit_info_size (flags, num_llvm_clauses, num_holes);
|
len = mono_jit_info_size (flags, num_llvm_clauses, num_holes);
|
||||||
|
g_assert (!mem_manager->collectible);
|
||||||
jinfo = (MonoJitInfo *)alloc0_jit_info_data (mem_manager, len, async);
|
jinfo = (MonoJitInfo *)alloc0_jit_info_data (mem_manager, len, async);
|
||||||
mono_jit_info_init (jinfo, method, code, code_len, flags, num_llvm_clauses, num_holes);
|
mono_jit_info_init (jinfo, method, code, code_len, flags, num_llvm_clauses, num_holes);
|
||||||
|
|
||||||
|
|
|
@ -10079,11 +10079,14 @@ calli_end:
|
||||||
CHECK_TYPELOAD (klass);
|
CHECK_TYPELOAD (klass);
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = mono_special_static_field_get_offset (field, cfg->error);
|
|
||||||
CHECK_CFG_ERROR;
|
|
||||||
CHECK_TYPELOAD (klass);
|
|
||||||
|
|
||||||
is_special_static = mono_class_field_is_special_static (field);
|
is_special_static = mono_class_field_is_special_static (field);
|
||||||
|
if (is_special_static) {
|
||||||
|
addr = mono_special_static_field_get_offset (field, cfg->error);
|
||||||
|
CHECK_CFG_ERROR;
|
||||||
|
CHECK_TYPELOAD (klass);
|
||||||
|
} else {
|
||||||
|
addr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_special_static && ((gsize)addr & 0x80000000) == 0)
|
if (is_special_static && ((gsize)addr & 0x80000000) == 0)
|
||||||
thread_ins = mono_create_tls_get (cfg, TLS_KEY_THREAD);
|
thread_ins = mono_create_tls_get (cfg, TLS_KEY_THREAD);
|
||||||
|
@ -10252,8 +10255,13 @@ calli_end:
|
||||||
} else if (il_op == MONO_CEE_STSFLD) {
|
} else if (il_op == MONO_CEE_STSFLD) {
|
||||||
MonoInst *store;
|
MonoInst *store;
|
||||||
|
|
||||||
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
|
if (m_class_get_mem_manager (m_field_get_parent (field))->collectible && (mini_type_is_reference (ftype) || m_class_has_references (mono_class_from_mono_type_internal (ftype)))) {
|
||||||
store->flags |= ins_flag;
|
/* These are stored on the GC heap, so they need GC barriers */
|
||||||
|
mini_emit_memory_store (cfg, ftype, ins, store_val, 0);
|
||||||
|
} else {
|
||||||
|
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
|
||||||
|
store->flags |= ins_flag;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
gboolean is_const = FALSE;
|
gboolean is_const = FALSE;
|
||||||
MonoVTable *vtable = NULL;
|
MonoVTable *vtable = NULL;
|
||||||
|
|
|
@ -3524,11 +3524,21 @@ is_async_method (MonoMethod *method)
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
|
mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_vars,
|
||||||
gboolean allow_partial, gboolean allow_gsharedvt)
|
gboolean allow_partial, gboolean allow_gsharedvt)
|
||||||
{
|
{
|
||||||
if (!mono_method_is_generic_impl (method))
|
if (!mono_method_is_generic_impl (method))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
if (m_method_get_mem_manager (method)->collectible) {
|
||||||
|
/*
|
||||||
|
* Generic sharing needs to be disabled for instances in collectible ALCs, because
|
||||||
|
* static variables are handled differently:
|
||||||
|
* - stores to them need write barriers since they are stored in the GC heap.
|
||||||
|
* - their address cannot be computed using MONO_RGCTX_INFO_STATIC_DATA + offset.
|
||||||
|
*/
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (!mono_debug_count ())
|
if (!mono_debug_count ())
|
||||||
allow_partial = FALSE;
|
allow_partial = FALSE;
|
||||||
|
|
|
@ -493,7 +493,7 @@ register_trampoline_jit_info (MonoMemoryManager *mem_manager, MonoTrampInfo *inf
|
||||||
{
|
{
|
||||||
MonoJitInfo *ji;
|
MonoJitInfo *ji;
|
||||||
|
|
||||||
ji = (MonoJitInfo *)mono_mem_manager_alloc0 (mem_manager, mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
|
ji = mini_alloc_jinfo (jit_mm_for_mm (mem_manager), mono_jit_info_size ((MonoJitInfoFlags)0, 0, 0));
|
||||||
mono_jit_info_init (ji, NULL, (guint8*)MINI_FTNPTR_TO_ADDR (info->code), info->code_size, (MonoJitInfoFlags)0, 0, 0);
|
mono_jit_info_init (ji, NULL, (guint8*)MINI_FTNPTR_TO_ADDR (info->code), info->code_size, (MonoJitInfoFlags)0, 0, 0);
|
||||||
ji->d.tramp_info = info;
|
ji->d.tramp_info = info;
|
||||||
ji->is_trampoline = TRUE;
|
ji->is_trampoline = TRUE;
|
||||||
|
@ -2401,7 +2401,8 @@ create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info)
|
||||||
uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
|
uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
jinfo = (MonoJitInfo *)mono_mem_manager_alloc0 (get_default_mem_manager (), MONO_SIZEOF_JIT_INFO);
|
// FIXME:
|
||||||
|
jinfo = mini_alloc_jinfo (get_default_jit_mm (), MONO_SIZEOF_JIT_INFO);
|
||||||
jinfo->d.method = wrapper;
|
jinfo->d.method = wrapper;
|
||||||
jinfo->code_start = MINI_FTNPTR_TO_ADDR (info->code);
|
jinfo->code_start = MINI_FTNPTR_TO_ADDR (info->code);
|
||||||
jinfo->code_size = info->code_size;
|
jinfo->code_size = info->code_size;
|
||||||
|
@ -4314,6 +4315,15 @@ free_jit_mem_manager (MonoMemoryManager *mem_manager)
|
||||||
mono_llvm_free_mem_manager (info);
|
mono_llvm_free_mem_manager (info);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Unregister/free jit info */
|
||||||
|
if (info->jit_infos) {
|
||||||
|
for (guint i = 0; i < info->jit_infos->len; ++i) {
|
||||||
|
MonoJitInfo *ji = g_ptr_array_index (info->jit_infos, i);
|
||||||
|
mono_jit_info_table_remove (ji);
|
||||||
|
}
|
||||||
|
g_ptr_array_free (info->jit_infos, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
g_free (info);
|
g_free (info);
|
||||||
mem_manager->runtime_info = NULL;
|
mem_manager->runtime_info = NULL;
|
||||||
}
|
}
|
||||||
|
@ -5332,3 +5342,20 @@ mini_get_interp_callbacks_api (void)
|
||||||
{
|
{
|
||||||
return mono_interp_callbacks_pointer;
|
return mono_interp_callbacks_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MonoJitInfo*
|
||||||
|
mini_alloc_jinfo (MonoJitMemoryManager *jit_mm, int size)
|
||||||
|
{
|
||||||
|
if (jit_mm->mem_manager->collectible) {
|
||||||
|
/* These are freed by mono_jit_info_table_remove () in an async way, so they have to be malloc-ed */
|
||||||
|
MonoJitInfo *ji = (MonoJitInfo*)g_malloc0 (size);
|
||||||
|
jit_mm_lock (jit_mm);
|
||||||
|
if (!jit_mm->jit_infos)
|
||||||
|
jit_mm->jit_infos = g_ptr_array_new ();
|
||||||
|
g_ptr_array_add (jit_mm->jit_infos, ji);
|
||||||
|
jit_mm_unlock (jit_mm);
|
||||||
|
return ji;
|
||||||
|
} else {
|
||||||
|
return (MonoJitInfo*)mono_mem_manager_alloc0 (jit_mm->mem_manager, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -59,12 +59,21 @@ typedef struct {
|
||||||
/* Protected by 'jit_code_hash_lock' */
|
/* Protected by 'jit_code_hash_lock' */
|
||||||
MonoInternalHashTable jit_code_hash;
|
MonoInternalHashTable jit_code_hash;
|
||||||
mono_mutex_t jit_code_hash_lock;
|
mono_mutex_t jit_code_hash_lock;
|
||||||
|
|
||||||
|
/* Array of MonoJitInfo* */
|
||||||
|
GPtrArray *jit_infos;
|
||||||
} MonoJitMemoryManager;
|
} MonoJitMemoryManager;
|
||||||
|
|
||||||
|
static inline MonoJitMemoryManager*
|
||||||
|
jit_mm_for_mm (MonoMemoryManager *mem_manager)
|
||||||
|
{
|
||||||
|
return (MonoJitMemoryManager*)(mem_manager->runtime_info);
|
||||||
|
}
|
||||||
|
|
||||||
static inline MonoJitMemoryManager*
|
static inline MonoJitMemoryManager*
|
||||||
get_default_jit_mm (void)
|
get_default_jit_mm (void)
|
||||||
{
|
{
|
||||||
return (MonoJitMemoryManager*)(mono_mem_manager_get_ambient ())->runtime_info;
|
return jit_mm_for_mm (mono_mem_manager_get_ambient ());
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Review uses and change them to a more specific mem manager
|
// FIXME: Review uses and change them to a more specific mem manager
|
||||||
|
@ -611,6 +620,7 @@ void mono_jit_dump_cleanup (void);
|
||||||
|
|
||||||
gpointer mini_alloc_generic_virtual_trampoline (MonoVTable *vtable, int size);
|
gpointer mini_alloc_generic_virtual_trampoline (MonoVTable *vtable, int size);
|
||||||
MonoException* mini_get_stack_overflow_ex (void);
|
MonoException* mini_get_stack_overflow_ex (void);
|
||||||
|
MonoJitInfo* mini_alloc_jinfo (MonoJitMemoryManager *jit_mm, int size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Per-OS implementation functions.
|
* Per-OS implementation functions.
|
||||||
|
|
|
@ -1286,7 +1286,7 @@ mono_create_jump_trampoline (MonoMethod *method, gboolean add_sync_wrapper, Mono
|
||||||
code = mono_create_specific_trampoline (m_method_get_mem_manager (method), method, MONO_TRAMPOLINE_JUMP, &code_size);
|
code = mono_create_specific_trampoline (m_method_get_mem_manager (method), method, MONO_TRAMPOLINE_JUMP, &code_size);
|
||||||
g_assert (code_size);
|
g_assert (code_size);
|
||||||
|
|
||||||
ji = (MonoJitInfo *)m_method_alloc0 (method, MONO_SIZEOF_JIT_INFO);
|
ji = mini_alloc_jinfo (jit_mm, MONO_SIZEOF_JIT_INFO);
|
||||||
ji->code_start = MINI_FTNPTR_TO_ADDR (code);
|
ji->code_start = MINI_FTNPTR_TO_ADDR (code);
|
||||||
ji->code_size = code_size;
|
ji->code_size = code_size;
|
||||||
ji->d.method = method;
|
ji->d.method = method;
|
||||||
|
|
|
@ -2358,7 +2358,7 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
|
||||||
if (cfg->method->dynamic)
|
if (cfg->method->dynamic)
|
||||||
jinfo = (MonoJitInfo *)g_malloc0 (mono_jit_info_size (flags, num_clauses, num_holes));
|
jinfo = (MonoJitInfo *)g_malloc0 (mono_jit_info_size (flags, num_clauses, num_holes));
|
||||||
else
|
else
|
||||||
jinfo = (MonoJitInfo *)mono_mem_manager_alloc0 (cfg->mem_manager, mono_jit_info_size (flags, num_clauses, num_holes));
|
jinfo = mini_alloc_jinfo (cfg->jit_mm, mono_jit_info_size (flags, num_clauses, num_holes));
|
||||||
jinfo_try_holes_size += num_holes * sizeof (MonoTryBlockHoleJitInfo);
|
jinfo_try_holes_size += num_holes * sizeof (MonoTryBlockHoleJitInfo);
|
||||||
|
|
||||||
mono_jit_info_init (jinfo, cfg->method_to_register, cfg->native_code, cfg->code_len, flags, num_clauses, num_holes);
|
mono_jit_info_init (jinfo, cfg->method_to_register, cfg->native_code, cfg->code_len, flags, num_clauses, num_holes);
|
||||||
|
|
|
@ -1174,7 +1174,7 @@ major_block_is_evacuating (MSBlockInfo *block)
|
||||||
SGEN_ASSERT (9, MS_OBJ_ALLOCED ((obj), (block)), "object %p not allocated", obj); \
|
SGEN_ASSERT (9, MS_OBJ_ALLOCED ((obj), (block)), "object %p not allocated", obj); \
|
||||||
if (!MS_MARK_BIT ((block), __word, __bit)) { \
|
if (!MS_MARK_BIT ((block), __word, __bit)) { \
|
||||||
MS_SET_MARK_BIT ((block), __word, __bit); \
|
MS_SET_MARK_BIT ((block), __word, __bit); \
|
||||||
if (sgen_gc_descr_has_references (desc)) \
|
if (sgen_gc_descr_has_references (desc) || sgen_vtable_has_class_obj (SGEN_LOAD_VTABLE (obj))) \
|
||||||
GRAY_OBJECT_ENQUEUE_SERIAL ((queue), (obj), (desc)); \
|
GRAY_OBJECT_ENQUEUE_SERIAL ((queue), (obj), (desc)); \
|
||||||
sgen_binary_protocol_mark ((obj), (gpointer)SGEN_LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((obj))); \
|
sgen_binary_protocol_mark ((obj), (gpointer)SGEN_LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((obj))); \
|
||||||
INC_NUM_MAJOR_OBJECTS_MARKED (); \
|
INC_NUM_MAJOR_OBJECTS_MARKED (); \
|
||||||
|
@ -1187,7 +1187,7 @@ major_block_is_evacuating (MSBlockInfo *block)
|
||||||
SGEN_ASSERT (9, MS_OBJ_ALLOCED ((obj), (block)), "object %p not allocated", obj); \
|
SGEN_ASSERT (9, MS_OBJ_ALLOCED ((obj), (block)), "object %p not allocated", obj); \
|
||||||
MS_SET_MARK_BIT_PAR ((block), __word, __bit, first); \
|
MS_SET_MARK_BIT_PAR ((block), __word, __bit, first); \
|
||||||
if (first) { \
|
if (first) { \
|
||||||
if (sgen_gc_descr_has_references (desc)) \
|
if (sgen_gc_descr_has_references (desc) || sgen_vtable_has_class_obj (SGEN_LOAD_VTABLE (obj))) \
|
||||||
GRAY_OBJECT_ENQUEUE_PARALLEL ((queue), (obj), (desc)); \
|
GRAY_OBJECT_ENQUEUE_PARALLEL ((queue), (obj), (desc)); \
|
||||||
sgen_binary_protocol_mark ((obj), (gpointer)SGEN_LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((obj))); \
|
sgen_binary_protocol_mark ((obj), (gpointer)SGEN_LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((obj))); \
|
||||||
INC_NUM_MAJOR_OBJECTS_MARKED (); \
|
INC_NUM_MAJOR_OBJECTS_MARKED (); \
|
||||||
|
|
|
@ -92,6 +92,18 @@ MONO_DISABLE_WARNING(4127) /* conditional expression is constant */
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SCAN_OBJECT_NOVTABLE
|
||||||
|
GCVTable vt = SGEN_LOAD_VTABLE ((GCObject*)start);
|
||||||
|
GCObject *class_obj = sgen_vtable_get_class_obj (vt);
|
||||||
|
if (G_UNLIKELY (class_obj)) {
|
||||||
|
/* Just need to scan the pinned class object */
|
||||||
|
// FIXME:
|
||||||
|
GCObject *ptr_loc = class_obj;
|
||||||
|
HANDLE_PTR (&ptr_loc, obj);
|
||||||
|
g_assert (ptr_loc == class_obj);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef SCAN_OBJECT_NOSCAN
|
#undef SCAN_OBJECT_NOSCAN
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue