1
0
Fork 0
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:
Zoltan Varga 2022-12-15 10:43:29 -05:00 committed by GitHub
parent d70d2a9d11
commit 6fecc25b02
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 1206 additions and 107 deletions

View 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

View file

@ -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" />

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -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; }

View file

@ -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);

View file

@ -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()

View file

@ -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

View file

@ -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
}

View file

@ -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 */

View file

@ -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__

View file

@ -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))

View file

@ -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)
{ {

View file

@ -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

View file

@ -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;

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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))

View file

@ -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.
*/ */

View file

@ -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);
} }

View file

@ -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;

View file

@ -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;
} }

View file

@ -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;

View 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);
}

View 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__ */

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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.

View file

@ -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;

View file

@ -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);

View file

@ -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 (); \

View file

@ -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