2 * Copyright 2016 Microsoft
3 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 #ifndef __MONO_METADATA_REFLECTION_CACHE_H__
6 #define __MONO_METADATA_REFLECTION_CACHE_H__
9 #include <mono/metadata/domain-internals.h>
10 #include <mono/metadata/handle.h>
11 #include <mono/metadata/mono-hash.h>
12 #include <mono/metadata/mempool.h>
13 #include <mono/utils/mono-error-internals.h>
16 * We need to return always the same object for MethodInfo, FieldInfo etc..
17 * but we need to consider the reflected type.
18 * type uses a different hash, since it uses custom hash/equal functions.
27 reflected_equal (gconstpointer a, gconstpointer b);
30 reflected_hash (gconstpointer a);
33 /* ReflectedEntry doesn't need to be GC tracked */
34 #define ALLOC_REFENTRY g_new0 (ReflectedEntry, 1)
35 #define FREE_REFENTRY(entry) g_free ((entry))
36 #define REFENTRY_REQUIRES_CLEANUP
38 #define ALLOC_REFENTRY (ReflectedEntry *)mono_mempool_alloc (domain->mp, sizeof (ReflectedEntry))
40 #define FREE_REFENTRY(entry)
43 static inline MonoObject*
44 cache_object (MonoDomain *domain, MonoClass *klass, gpointer item, MonoObject* o)
50 mono_domain_lock (domain);
51 if (!domain->refobject_hash)
52 domain->refobject_hash = mono_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
54 obj = (MonoObject*) mono_g_hash_table_lookup (domain->refobject_hash, &pe);
56 ReflectedEntry *e = ALLOC_REFENTRY;
59 mono_g_hash_table_insert (domain->refobject_hash, e, o);
62 mono_domain_unlock (domain);
67 static inline MonoObjectHandle
68 cache_object_handle (MonoDomain *domain, MonoClass *klass, gpointer item, MonoObjectHandle o)
73 mono_domain_lock (domain);
74 if (!domain->refobject_hash)
75 domain->refobject_hash = mono_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
77 MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_g_hash_table_lookup (domain->refobject_hash, &pe));
78 if (MONO_HANDLE_IS_NULL (obj)) {
79 ReflectedEntry *e = ALLOC_REFENTRY;
82 mono_g_hash_table_insert (domain->refobject_hash, e, MONO_HANDLE_RAW (o));
83 MONO_HANDLE_ASSIGN (obj, o);
85 mono_domain_unlock (domain);
90 #define CACHE_OBJECT(t,p,o,k) ((t) (cache_object (domain, (k), (p), (o))))
93 static inline MonoObject*
94 check_object (MonoDomain* domain, MonoClass *klass, gpointer item)
99 mono_domain_lock (domain);
100 if (!domain->refobject_hash)
101 domain->refobject_hash = mono_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
102 MonoObject *obj = (MonoObject*) mono_g_hash_table_lookup (domain->refobject_hash, &e);
103 mono_domain_unlock (domain);
107 static inline MonoObjectHandle
108 check_object_handle (MonoDomain* domain, MonoClass *klass, gpointer item)
113 mono_domain_lock (domain);
114 if (!domain->refobject_hash)
115 domain->refobject_hash = mono_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
116 MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_g_hash_table_lookup (domain->refobject_hash, &e));
117 mono_domain_unlock (domain);
122 typedef MonoObject* (*ReflectionCacheConstructFunc) (MonoDomain*, MonoClass*, gpointer, gpointer, MonoError *);
124 typedef MonoObjectHandle (*ReflectionCacheConstructFunc_handle) (MonoDomain*, MonoClass*, gpointer, gpointer, MonoError *);
127 static inline MonoObject*
128 check_or_construct (MonoDomain *domain, MonoClass *klass, gpointer item, gpointer user_data, MonoError *error, ReflectionCacheConstructFunc construct)
130 mono_error_init (error);
131 MonoObject *obj = check_object (domain, klass, item);
134 obj = construct (domain, klass, item, user_data, error);
135 return_val_if_nok (error, NULL);
136 /* note no caching if there was an error in construction */
137 return cache_object (domain, klass, item, obj);
140 static inline MonoObjectHandle
141 check_or_construct_handle (MonoDomain *domain, MonoClass *klass, gpointer item, gpointer user_data, MonoError *error, ReflectionCacheConstructFunc_handle construct)
143 mono_error_init (error);
144 MonoObjectHandle obj = check_object_handle (domain, klass, item);
145 if (!MONO_HANDLE_IS_NULL (obj))
147 MONO_HANDLE_ASSIGN (obj, construct (domain, klass, item, user_data, error));
148 return_val_if_nok (error, NULL);
149 /* note no caching if there was an error in construction */
150 return cache_object_handle (domain, klass, item, obj);
154 #define CHECK_OR_CONSTRUCT(t,p,k,construct,ud) ((t) check_or_construct (domain, (k), (p), (ud), error, (ReflectionCacheConstructFunc) (construct)))
156 #define CHECK_OR_CONSTRUCT_HANDLE(t,p,k,construct,ud) ((t) check_or_construct_handle (domain, (k), (p), (ud), error, (ReflectionCacheConstructFunc_handle) (construct)))
159 #endif /*__MONO_METADATA_REFLECTION_CACHE_H__*/