Merge pull request #4033 from ntherning/no-stdcall-for-icalls-on-windows-32-bit
[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
90 #define CACHE_OBJECT(t,p,o,k) ((t) (cache_object (domain, (k), (p), (o))))
91
92
93 static inline MonoObject*
94 check_object (MonoDomain* domain, MonoClass *klass, gpointer item)
95 {
96         ReflectedEntry e;
97         e.item = item;
98         e.refclass = klass;
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);
104         return obj;
105 }
106
107 static inline MonoObjectHandle
108 check_object_handle (MonoDomain* domain, MonoClass *klass, gpointer item)
109 {
110         ReflectedEntry e;
111         e.item = item;
112         e.refclass = klass;
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);
118         return obj;
119 }
120
121
122 typedef MonoObject* (*ReflectionCacheConstructFunc) (MonoDomain*, MonoClass*, gpointer, gpointer, MonoError *);
123
124 typedef MonoObjectHandle (*ReflectionCacheConstructFunc_handle) (MonoDomain*, MonoClass*, gpointer, gpointer, MonoError *);
125
126
127 static inline MonoObject*
128 check_or_construct (MonoDomain *domain, MonoClass *klass, gpointer item, gpointer user_data, MonoError *error, ReflectionCacheConstructFunc construct)
129 {
130         mono_error_init (error);
131         MonoObject *obj = check_object (domain, klass, item);
132         if (obj)
133                 return obj;
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);
138 }
139
140 static inline MonoObjectHandle
141 check_or_construct_handle (MonoDomain *domain, MonoClass *klass, gpointer item, gpointer user_data, MonoError *error, ReflectionCacheConstructFunc_handle construct)
142 {
143         mono_error_init (error);
144         MonoObjectHandle obj = check_object_handle (domain, klass, item);
145         if (!MONO_HANDLE_IS_NULL (obj))
146                 return 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);
151 }
152
153
154 #define CHECK_OR_CONSTRUCT(t,p,k,construct,ud) ((t) check_or_construct (domain, (k), (p), (ud), error, (ReflectionCacheConstructFunc) (construct)))
155
156 #define CHECK_OR_CONSTRUCT_HANDLE(t,p,k,construct,ud) ((t) check_or_construct_handle (domain, (k), (p), (ud), error, (ReflectionCacheConstructFunc_handle) (construct)))
157
158
159 #endif /*__MONO_METADATA_REFLECTION_CACHE_H__*/