4b4239eb66f7cfbd3b08ac9da26439b27bf64993
[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 MonoObject *null_cell = { NULL };
49 const MonoObjectHandle mono_null_value_handle = { (MonoObject**)&null_cell };
50
51 #define THIS_IS_AN_OK_NUMBER_OF_HANDLES 100
52
53 /* Actual handles implementation */
54 MonoRawHandle
55 mono_handle_new (MonoObject *object)
56 {
57         MonoThreadInfo *info = mono_thread_info_current ();
58         HandleStack *handles = (HandleStack *)info->handle_stack;
59         HandleChunk *top = handles->top;
60
61 retry:
62         if (G_LIKELY (top->size < OBJECTS_PER_HANDLES_CHUNK)) {
63                 MonoObject **h = &top->objects [top->size++];
64                 *h = object;
65                 return h;
66         }
67         if (G_LIKELY (top->next)) {
68                 top = top->next;
69                 top->size = 0;
70                 handles->top = top;
71                 goto retry;
72         }
73         HandleChunk *new_chunk = g_new (HandleChunk, 1);
74         new_chunk->size = 0;
75         new_chunk->prev = top;
76         new_chunk->next = NULL;
77         top->next = new_chunk;
78         handles->top = new_chunk;
79         goto retry;
80 }
81
82
83
84 HandleStack*
85 mono_handle_stack_alloc (void)
86 {
87         HandleStack *stack = g_new (HandleStack, 1);
88         HandleChunk *chunk = g_new (HandleChunk, 1);
89
90         stack->top = stack->bottom = chunk;
91         chunk->size = 0;
92         chunk->prev = chunk->next = NULL;
93         return stack;
94 }
95
96 void
97 mono_handle_stack_free (HandleStack *stack)
98 {
99         if (!stack)
100                 return;
101         HandleChunk *c = stack->bottom;
102         while (c) {
103                 HandleChunk *next = c->next;
104                 g_free (c);
105                 c = next;
106         }
107         g_free (c);
108 }
109
110 void
111 mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data)
112 {
113         HandleChunk *cur = stack->bottom;
114         HandleChunk *last = stack->top;
115
116         if (!cur)
117                 return;
118
119         while (cur) {
120                 int i;
121                 for (i = 0; i < cur->size; ++i)
122                         func ((gpointer*)&cur->objects [i], gc_data);
123                 if (cur == last)
124                         break;
125                 cur = cur->next;
126         }
127 }
128
129 void
130 mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, const char *func_name)
131 {
132         HandleStack *handles = (HandleStack *)info->handle_stack;
133         HandleChunk *cur = stackmark->chunk;
134         int size = -stackmark->size; //discard the starting point of the stack
135         while (cur) {
136                 size += cur->size;
137                 if (cur == handles->top)
138                         break;
139                 cur = cur->next;
140         }
141
142         if (size > THIS_IS_AN_OK_NUMBER_OF_HANDLES)
143                 printf ("%s USED %d handles\n", func_name, size);
144 }
145
146 /*
147  * Pop the stack until @stackmark and make @value the top value.
148  *
149  * @return the new handle for what @value points to 
150  */
151 MonoRawHandle
152 mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value)
153 {
154         g_error ("impl me");
155 }
156
157 /* Temporary place for some of the handle enabled wrapper functions*/
158
159 MonoStringHandle
160 mono_string_new_handle (MonoDomain *domain, const char *data)
161 {
162         return MONO_HANDLE_NEW (MonoString, mono_string_new (domain, data));
163 }
164
165 MonoArrayHandle
166 mono_array_new_handle (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
167 {
168         return MONO_HANDLE_NEW (MonoArray, mono_array_new_checked (domain, eclass, n, error));
169 }
170
171 #ifdef ENABLE_CHECKED_BUILD
172 /* Checked build helpers */
173 void
174 mono_handle_verify (MonoRawHandle raw_handle)
175 {
176         
177 }
178 #endif