Merge pull request #3240 from alexanderkyte/aot_compiler_leaks
[mono.git] / mono / metadata / handle.c
1 /*
2  * handle.c: Handle to object in native code
3  *
4  * Authors:
5  *  - Ludovic Henry <ludovic@xamarin.com>
6  *  - Aleksey Klieger <aleksey.klieger@xamarin.com>
7  *  - Rodrigo Kumpera <kumpera@xamarin.com>
8  *
9  * Copyright 2016 Dot net foundation.
10  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11  */
12
13 #include <config.h>
14 #include <glib.h>
15
16 #include <mono/metadata/handle.h>
17 #include <mono/metadata/object-internals.h>
18 #include <mono/metadata/gc-internals.h>
19 #include <mono/utils/atomic.h>
20 #include <mono/utils/mono-lazy-init.h>
21 #include <mono/utils/mono-threads.h>
22 /* TODO (missing pieces)
23
24 Add counters for:
25         number of stack marks
26         stack marks per icall
27         mix/max/avg size of stack marks
28         handle stack wastage
29
30 Actually do something in mono_handle_verify
31
32 Shrink the handles stack in mono_handle_stack_scan
33 Properly report it to the profiler.
34 Add a boehm implementation
35
36 TODO (things to explore):
37
38 There's no convenient way to wrap the object allocation function.
39 Right now we do this:
40         MonoCultureInfoHandle culture = MONO_HANDLE_NEW (MonoCultureInfo, mono_object_new_checked (domain, klass, &error));
41
42 Maybe what we need is a round of cleanup around all exposed types in the runtime to unify all helpers under the same hoof.
43 Combine: MonoDefaults, GENERATE_GET_CLASS_WITH_CACHE, TYPED_HANDLE_DECL and friends.
44         This would solve the age old issue of making it clear which types are optional and tell that to the linker.
45         We could then generate neat type safe wrappers.
46 */
47
48 const MonoObjectHandle mono_null_value_handle = NULL;
49
50 #define THIS_IS_AN_OK_NUMBER_OF_HANDLES 100
51
52 /* Actual handles implementation */
53 MonoRawHandle
54 mono_handle_new (MonoObject *object)
55 {
56         MonoThreadInfo *info = mono_thread_info_current ();
57         HandleStack *handles = (HandleStack *)info->handle_stack;
58         HandleChunk *top = handles->top;
59
60 retry:
61         if (G_LIKELY (top->size < OBJECTS_PER_HANDLES_CHUNK)) {
62                 MonoObject **h = &top->objects [top->size++];
63                 *h = object;
64                 return h;
65         }
66         if (G_LIKELY (top->next)) {
67                 top = top->next;
68                 top->size = 0;
69                 handles->top = top;
70                 goto retry;
71         }
72         HandleChunk *new_chunk = g_new (HandleChunk, 1);
73         new_chunk->size = 0;
74         new_chunk->prev = top;
75         new_chunk->next = NULL;
76         top->next = new_chunk;
77         handles->top = new_chunk;
78         goto retry;
79 }
80
81
82
83 HandleStack*
84 mono_handle_stack_alloc (void)
85 {
86         HandleStack *stack = g_new (HandleStack, 1);
87         HandleChunk *chunk = g_new (HandleChunk, 1);
88
89         stack->top = stack->bottom = chunk;
90         chunk->size = 0;
91         chunk->prev = chunk->next = NULL;
92         return stack;
93 }
94
95 void
96 mono_handle_stack_free (HandleStack *stack)
97 {
98         if (!stack)
99                 return;
100         HandleChunk *c = stack->bottom;
101         while (c) {
102                 HandleChunk *next = c->next;
103                 g_free (c);
104                 c = next;
105         }
106         g_free (c);
107 }
108
109 void
110 mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data)
111 {
112         HandleChunk *cur = stack->bottom;
113         HandleChunk *last = stack->top;
114
115         if (!cur)
116                 return;
117
118         while (cur) {
119                 int i;
120                 for (i = 0; i < cur->size; ++i)
121                         func ((gpointer*)&cur->objects [i], gc_data);
122                 if (cur == last)
123                         break;
124                 cur = cur->next;
125         }
126 }
127
128 void
129 mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, const char *func_name)
130 {
131         HandleStack *handles = (HandleStack *)info->handle_stack;
132         HandleChunk *cur = stackmark->chunk;
133         int size = -stackmark->size; //discard the starting point of the stack
134         while (cur) {
135                 size += cur->size;
136                 if (cur == handles->top)
137                         break;
138                 cur = cur->next;
139         }
140
141         if (size > THIS_IS_AN_OK_NUMBER_OF_HANDLES)
142                 printf ("%s USED %d handles\n", func_name, size);
143 }
144
145 /*
146  * Pop the stack until @stackmark and make @value the top value.
147  *
148  * @return the new handle for what @value points to 
149  */
150 MonoRawHandle
151 mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value)
152 {
153         g_error ("impl me");
154 }
155
156 /* Temporary place for some of the handle enabled wrapper functions*/
157
158 MonoStringHandle
159 mono_string_new_handle (MonoDomain *domain, const char *data)
160 {
161         return MONO_HANDLE_NEW (MonoString, mono_string_new (domain, data));
162 }
163
164 MonoArrayHandle
165 mono_array_new_handle (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
166 {
167         return MONO_HANDLE_NEW (MonoArray, mono_array_new_checked (domain, eclass, n, error));
168 }
169
170 #ifdef ENABLE_CHECKED_BUILD
171 /* Checked build helpers */
172 void
173 mono_handle_verify (MonoRawHandle raw_handle)
174 {
175         
176 }
177 #endif