Implement mono_gc_alloc_fixed on Boehm to be uncollectable. This matches SGen behavio...
[mono.git] / mono / metadata / reflection-cache.h
1 /* 
2  * Copyright 2016 Microsoft
3  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
4  */
5 #ifndef __MONO_METADATA_REFLECTION_CACHE_H__
6 #define __MONO_METADATA_REFLECTION_CACHE_H__
7
8 #include <glib.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>
14
15 /*
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.
19  */
20
21 typedef struct {
22         gpointer item;
23         MonoClass *refclass;
24 } ReflectedEntry;
25
26 gboolean
27 reflected_equal (gconstpointer a, gconstpointer b);
28
29 guint
30 reflected_hash (gconstpointer a);
31
32 #ifdef HAVE_BOEHM_GC
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
37 #else
38 #define ALLOC_REFENTRY (ReflectedEntry *)mono_mempool_alloc (domain->mp, sizeof (ReflectedEntry))
39 /* FIXME: */
40 #define FREE_REFENTRY(entry)
41 #endif
42
43 static inline MonoObject*
44 cache_object (MonoDomain *domain, MonoClass *klass, gpointer item, MonoObject* o)
45 {
46         MonoObject *obj;
47         ReflectedEntry pe;
48         pe.item = item;
49         pe.refclass = klass;
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");
53
54         obj = (MonoObject*) mono_g_hash_table_lookup (domain->refobject_hash, &pe);
55         if (obj == NULL) {
56                 ReflectedEntry *e = ALLOC_REFENTRY;
57                 e->item = item;
58                 e->refclass = klass;
59                 mono_g_hash_table_insert (domain->refobject_hash, e, o);
60                 obj = o;
61         }
62         mono_domain_unlock (domain);
63         return obj;
64 }
65
66
67 static inline MonoObjectHandle
68 cache_object_handle (MonoDomain *domain, MonoClass *klass, gpointer item, MonoObjectHandle o)
69 {
70         ReflectedEntry pe;
71         pe.item = item;
72         pe.refclass = klass;
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");
76
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;
80                 e->item = item;
81                 e->refclass = klass;
82                 mono_g_hash_table_insert (domain->refobject_hash, e, MONO_HANDLE_RAW (o));
83                 MONO_HANDLE_ASSIGN (obj, o);
84         }
85         mono_domain_unlock (domain);
86         return obj;
87 }
88
89 #define CACHE_OBJECT(t,p,o,k) ((t) (cache_object (domain, (k), (p), (o))))
90
91 static inline MonoObjectHandle
92 check_object_handle (MonoDomain* domain, MonoClass *klass, gpointer item)
93 {
94         ReflectedEntry e;
95         e.item = item;
96         e.refclass = klass;
97         mono_domain_lock (domain);
98         if (!domain->refobject_hash)
99                 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");
100         MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_g_hash_table_lookup (domain->refobject_hash, &e));
101         mono_domain_unlock (domain);
102         return obj;
103 }
104
105
106 typedef MonoObjectHandle (*ReflectionCacheConstructFunc_handle) (MonoDomain*, MonoClass*, gpointer, gpointer, MonoError *);
107
108 static inline MonoObjectHandle
109 check_or_construct_handle (MonoDomain *domain, MonoClass *klass, gpointer item, gpointer user_data, MonoError *error, ReflectionCacheConstructFunc_handle construct)
110 {
111         mono_error_init (error);
112         MonoObjectHandle obj = check_object_handle (domain, klass, item);
113         if (!MONO_HANDLE_IS_NULL (obj))
114                 return obj;
115         MONO_HANDLE_ASSIGN (obj, construct (domain, klass, item, user_data, error));
116         return_val_if_nok (error, NULL);
117         /* note no caching if there was an error in construction */
118         return cache_object_handle (domain, klass, item, obj);
119 }
120
121
122 #define CHECK_OR_CONSTRUCT_HANDLE(t,p,k,construct,ud) ((t) check_or_construct_handle (domain, (k), (p), (ud), error, (ReflectionCacheConstructFunc_handle) (construct)))
123
124
125 #endif /*__MONO_METADATA_REFLECTION_CACHE_H__*/