[runtime] Call error_init instead of mono_error_init (#4425)
[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 #define CACHE_OBJECT_HANDLE(t,p,o,k) ((t) (cache_object_handle (domain, (k), (p), (o))))
91
92 static inline MonoObjectHandle
93 check_object_handle (MonoDomain* domain, MonoClass *klass, gpointer item)
94 {
95         ReflectedEntry e;
96         e.item = item;
97         e.refclass = klass;
98         mono_domain_lock (domain);
99         if (!domain->refobject_hash)
100                 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");
101         MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_g_hash_table_lookup (domain->refobject_hash, &e));
102         mono_domain_unlock (domain);
103         return obj;
104 }
105
106
107 typedef MonoObjectHandle (*ReflectionCacheConstructFunc_handle) (MonoDomain*, MonoClass*, gpointer, gpointer, MonoError *);
108
109 static inline MonoObjectHandle
110 check_or_construct_handle (MonoDomain *domain, MonoClass *klass, gpointer item, gpointer user_data, MonoError *error, ReflectionCacheConstructFunc_handle construct)
111 {
112         error_init (error);
113         MonoObjectHandle obj = check_object_handle (domain, klass, item);
114         if (!MONO_HANDLE_IS_NULL (obj))
115                 return obj;
116         MONO_HANDLE_ASSIGN (obj, construct (domain, klass, item, user_data, error));
117         return_val_if_nok (error, NULL);
118         /* note no caching if there was an error in construction */
119         return cache_object_handle (domain, klass, item, obj);
120 }
121
122
123 #define CHECK_OR_CONSTRUCT_HANDLE(t,p,k,construct,ud) ((t) check_or_construct_handle (domain, (k), (p), (ud), error, (ReflectionCacheConstructFunc_handle) (construct)))
124
125
126 #endif /*__MONO_METADATA_REFLECTION_CACHE_H__*/