[linker] We need to mark nested types even if the declaring type isn't marked.
[mono-project.git] / mono / metadata / jit-info.c
blob6ffff1a6b7328511743975d2b247935fe7aa9d6d
1 /*
2 * jit-info.c: MonoJitInfo functionality
4 * Author:
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Patrik Torstensson
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include <config.h>
15 #include <glib.h>
16 #include <string.h>
17 #include <sys/stat.h>
19 #include <mono/metadata/gc-internals.h>
21 #include <mono/utils/atomic.h>
22 #include <mono/utils/mono-compiler.h>
23 #include <mono/utils/mono-logger-internals.h>
24 #include <mono/utils/mono-membar.h>
25 #include <mono/utils/mono-counters.h>
26 #include <mono/utils/hazard-pointer.h>
27 #include <mono/utils/mono-tls.h>
28 #include <mono/utils/mono-mmap.h>
29 #include <mono/utils/mono-threads.h>
30 #include <mono/metadata/object.h>
31 #include <mono/metadata/object-internals.h>
32 #include <mono/metadata/domain-internals.h>
33 #include <mono/metadata/class-internals.h>
34 #include <mono/metadata/assembly.h>
35 #include <mono/metadata/exception.h>
36 #include <mono/metadata/metadata-internals.h>
37 #include <mono/metadata/gc-internals.h>
38 #include <mono/metadata/appdomain.h>
39 #include <mono/metadata/mono-debug-debugger.h>
40 #include <mono/metadata/mono-config.h>
41 #include <mono/metadata/threads-types.h>
42 #include <mono/metadata/runtime.h>
43 #include <metadata/threads.h>
44 #include <metadata/profiler-private.h>
45 #include <mono/metadata/coree.h>
47 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
49 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
50 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
51 #define JIT_INFO_TABLE_FILLED_NUM_ELEMENTS (MONO_JIT_INFO_TABLE_CHUNK_SIZE * JIT_INFO_TABLE_FILL_RATIO_NOM / JIT_INFO_TABLE_FILL_RATIO_DENOM)
53 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
54 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
56 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
57 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
59 #define JIT_INFO_TABLE_HAZARD_INDEX 0
60 #define JIT_INFO_HAZARD_INDEX 1
62 static int
63 jit_info_table_num_elements (MonoJitInfoTable *table)
65 int i;
66 int num_elements = 0;
68 for (i = 0; i < table->num_chunks; ++i) {
69 MonoJitInfoTableChunk *chunk = table->chunks [i];
70 int chunk_num_elements = chunk->num_elements;
71 int j;
73 for (j = 0; j < chunk_num_elements; ++j) {
74 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
75 ++num_elements;
79 return num_elements;
82 static MonoJitInfoTableChunk*
83 jit_info_table_new_chunk (void)
85 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
86 chunk->refcount = 1;
88 return chunk;
91 MonoJitInfoTable *
92 mono_jit_info_table_new (MonoDomain *domain)
94 MonoJitInfoTable *table = (MonoJitInfoTable *)g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
96 table->domain = domain;
97 table->num_chunks = 1;
98 table->chunks [0] = jit_info_table_new_chunk ();
100 return table;
103 void
104 mono_jit_info_table_free (MonoJitInfoTable *table)
106 int i;
107 int num_chunks = table->num_chunks;
108 MonoDomain *domain = table->domain;
110 mono_domain_lock (domain);
112 table->domain->num_jit_info_tables--;
113 if (table->domain->num_jit_info_tables <= 1) {
114 GSList *list;
116 for (list = table->domain->jit_info_free_queue; list; list = list->next)
117 g_free (list->data);
119 g_slist_free (table->domain->jit_info_free_queue);
120 table->domain->jit_info_free_queue = NULL;
123 /* At this point we assume that there are no other threads
124 still accessing the table, so we don't have to worry about
125 hazardous pointers. */
127 for (i = 0; i < num_chunks; ++i) {
128 MonoJitInfoTableChunk *chunk = table->chunks [i];
129 MonoJitInfo *tombstone;
131 if (--chunk->refcount > 0)
132 continue;
134 for (tombstone = chunk->next_tombstone; tombstone; ) {
135 MonoJitInfo *next = tombstone->n.next_tombstone;
136 g_free (tombstone);
137 tombstone = next;
140 g_free (chunk);
143 mono_domain_unlock (domain);
145 g_free (table);
148 /* The jit_info_table is sorted in ascending order by the end
149 * addresses of the compiled methods. The reason why we have to do
150 * this is that once we introduce tombstones, it becomes possible for
151 * code ranges to overlap, and if we sort by code start and insert at
152 * the back of the table, we cannot guarantee that we won't overlook
153 * an entry.
155 * There are actually two possible ways to do the sorting and
156 * inserting which work with our lock-free mechanism:
158 * 1. Sort by start address and insert at the front. When looking for
159 * an entry, find the last one with a start address lower than the one
160 * you're looking for, then work your way to the front of the table.
162 * 2. Sort by end address and insert at the back. When looking for an
163 * entry, find the first one with an end address higher than the one
164 * you're looking for, then work your way to the end of the table.
166 * We chose the latter out of convenience.
168 static int
169 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
171 int left = 0, right = table->num_chunks;
173 g_assert (left < right);
175 do {
176 int pos = (left + right) / 2;
177 MonoJitInfoTableChunk *chunk = table->chunks [pos];
179 if (addr < chunk->last_code_end)
180 right = pos;
181 else
182 left = pos + 1;
183 } while (left < right);
184 g_assert (left == right);
186 if (left >= table->num_chunks)
187 return table->num_chunks - 1;
188 return left;
191 static int
192 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
194 int left = 0, right = chunk->num_elements;
196 while (left < right) {
197 int pos = (left + right) / 2;
198 MonoJitInfo *ji = (MonoJitInfo *)mono_get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
199 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
201 if (addr < code_end)
202 right = pos;
203 else
204 left = pos + 1;
206 g_assert (left == right);
208 return left;
211 static MonoJitInfo*
212 jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
214 MonoJitInfo *ji;
215 int chunk_pos, pos;
217 chunk_pos = jit_info_table_index (table, (gint8*)addr);
218 g_assert (chunk_pos < table->num_chunks);
220 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
222 /* We now have a position that's very close to that of the
223 first element whose end address is higher than the one
224 we're looking for. If we don't have the exact position,
225 then we have a position below that one, so we'll just
226 search upward until we find our element. */
227 do {
228 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
230 while (pos < chunk->num_elements) {
231 ji = (MonoJitInfo *)mono_get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
233 ++pos;
235 if (IS_JIT_INFO_TOMBSTONE (ji)) {
236 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
237 continue;
239 if ((gint8*)addr >= (gint8*)ji->code_start
240 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
241 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
242 return ji;
245 /* If we find a non-tombstone element which is already
246 beyond what we're looking for, we have to end the
247 search. */
248 if ((gint8*)addr < (gint8*)ji->code_start)
249 goto not_found;
252 ++chunk_pos;
253 pos = 0;
254 } while (chunk_pos < table->num_chunks);
256 not_found:
257 if (hp)
258 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
259 return NULL;
263 * mono_jit_info_table_find_internal:
265 * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
266 * In this case, only those AOT methods will be found whose jit info is already loaded.
267 * If ALLOW_TRAMPOLINES is TRUE, this can return a MonoJitInfo which represents a trampoline (ji->is_trampoline is true).
268 * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
269 * In this case, the returned MonoJitInfo might not have metadata information, in particular,
270 * mono_jit_info_get_method () could fail.
272 MonoJitInfo*
273 mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot, gboolean allow_trampolines)
275 MonoJitInfoTable *table;
276 MonoJitInfo *ji, *module_ji;
277 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
279 ++mono_stats.jit_info_table_lookup_count;
281 /* First we have to get the domain's jit_info_table. This is
282 complicated by the fact that a writer might substitute a
283 new table and free the old one. What the writer guarantees
284 us is that it looks at the hazard pointers after it has
285 changed the jit_info_table pointer. So, if we guard the
286 table by a hazard pointer and make sure that the pointer is
287 still there after we've made it hazardous, we don't have to
288 worry about the writer freeing the table. */
289 table = (MonoJitInfoTable *)mono_get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
291 ji = jit_info_table_find (table, hp, (gint8*)addr);
292 if (hp)
293 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
294 if (ji && ji->is_trampoline && !allow_trampolines)
295 return NULL;
296 if (ji)
297 return ji;
299 /* Maybe its an AOT module */
300 if (try_aot && mono_get_root_domain () && mono_get_root_domain ()->aot_modules) {
301 table = (MonoJitInfoTable *)mono_get_hazardous_pointer ((gpointer volatile*)&mono_get_root_domain ()->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
302 module_ji = jit_info_table_find (table, hp, (gint8*)addr);
303 if (module_ji)
304 ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
305 if (hp)
306 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
309 if (ji && ji->is_trampoline && !allow_trampolines)
310 return NULL;
312 return ji;
316 * mono_jit_info_table_find:
317 * @domain: Domain that you want to look up
318 * @addr: Points to an address with JITed code.
320 * Use this function to obtain a `MonoJitInfo*` object that can be used to get
321 * some statistics. You should provide both the @domain on which you will be
322 * performing the probe, and an address. Since application domains can share code
323 * the same address can be in use by multiple domains at once.
325 * This does not return any results for trampolines.
327 * Returns: NULL if the address does not belong to JITed code (it might be native
328 * code or a trampoline) or a valid pointer to a `MonoJitInfo*`.
330 MonoJitInfo*
331 mono_jit_info_table_find (MonoDomain *domain, char *addr)
333 return mono_jit_info_table_find_internal (domain, addr, TRUE, FALSE);
336 static G_GNUC_UNUSED void
337 jit_info_table_check (MonoJitInfoTable *table)
339 int i;
341 for (i = 0; i < table->num_chunks; ++i) {
342 MonoJitInfoTableChunk *chunk = table->chunks [i];
343 int j;
345 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
346 if (chunk->refcount > 10)
347 printf("warning: chunk refcount is %d\n", chunk->refcount);
348 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
350 for (j = 0; j < chunk->num_elements; ++j) {
351 MonoJitInfo *this_ji = chunk->data [j];
352 MonoJitInfo *next;
354 g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= chunk->last_code_end);
356 if (j < chunk->num_elements - 1)
357 next = chunk->data [j + 1];
358 else if (i < table->num_chunks - 1) {
359 int k;
361 for (k = i + 1; k < table->num_chunks; ++k)
362 if (table->chunks [k]->num_elements > 0)
363 break;
365 if (k >= table->num_chunks)
366 return;
368 g_assert (table->chunks [k]->num_elements > 0);
369 next = table->chunks [k]->data [0];
370 } else
371 return;
373 g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= (gint8*)next->code_start + next->code_size);
378 static MonoJitInfoTable*
379 jit_info_table_realloc (MonoJitInfoTable *old)
381 int i;
382 int num_elements = jit_info_table_num_elements (old);
383 int required_size;
384 int num_chunks;
385 int new_chunk, new_element;
386 MonoJitInfoTable *result;
388 /* number of needed places for elements needed */
389 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
390 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
391 if (num_chunks == 0) {
392 g_assert (num_elements == 0);
393 return mono_jit_info_table_new (old->domain);
395 g_assert (num_chunks > 0);
397 result = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
398 result->domain = old->domain;
399 result->num_chunks = num_chunks;
401 for (i = 0; i < num_chunks; ++i)
402 result->chunks [i] = jit_info_table_new_chunk ();
404 new_chunk = 0;
405 new_element = 0;
406 for (i = 0; i < old->num_chunks; ++i) {
407 MonoJitInfoTableChunk *chunk = old->chunks [i];
408 int chunk_num_elements = chunk->num_elements;
409 int j;
411 for (j = 0; j < chunk_num_elements; ++j) {
412 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
413 g_assert (new_chunk < num_chunks);
414 result->chunks [new_chunk]->data [new_element] = chunk->data [j];
415 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
416 result->chunks [new_chunk]->num_elements = new_element;
417 ++new_chunk;
418 new_element = 0;
424 if (new_chunk < num_chunks) {
425 g_assert (new_chunk == num_chunks - 1);
426 result->chunks [new_chunk]->num_elements = new_element;
427 g_assert (result->chunks [new_chunk]->num_elements > 0);
430 for (i = 0; i < num_chunks; ++i) {
431 MonoJitInfoTableChunk *chunk = result->chunks [i];
432 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
434 result->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
437 return result;
440 static void
441 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
443 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
444 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
446 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
448 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
449 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
451 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
452 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
454 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
455 + new1->data [new1->num_elements - 1]->code_size;
456 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
457 + new2->data [new2->num_elements - 1]->code_size;
459 *new1p = new1;
460 *new2p = new2;
463 static MonoJitInfoTable*
464 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
466 MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
467 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
468 int i, j;
470 new_table->domain = table->domain;
471 new_table->num_chunks = table->num_chunks + 1;
473 j = 0;
474 for (i = 0; i < table->num_chunks; ++i) {
475 if (table->chunks [i] == chunk) {
476 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
477 j += 2;
478 } else {
479 new_table->chunks [j] = table->chunks [i];
480 ++new_table->chunks [j]->refcount;
481 ++j;
485 g_assert (j == new_table->num_chunks);
487 return new_table;
490 static MonoJitInfoTableChunk*
491 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
493 MonoJitInfoTableChunk *result = jit_info_table_new_chunk ();
494 int i, j;
496 j = 0;
497 for (i = 0; i < old->num_elements; ++i) {
498 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
499 result->data [j++] = old->data [i];
502 result->num_elements = j;
503 if (result->num_elements > 0)
504 result->last_code_end = (gint8*)result->data [j - 1]->code_start + result->data [j - 1]->code_size;
505 else
506 result->last_code_end = old->last_code_end;
508 return result;
511 static MonoJitInfoTable*
512 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
514 MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
515 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
516 int i, j;
518 new_table->domain = table->domain;
519 new_table->num_chunks = table->num_chunks;
521 j = 0;
522 for (i = 0; i < table->num_chunks; ++i) {
523 if (table->chunks [i] == chunk)
524 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
525 else {
526 new_table->chunks [j] = table->chunks [i];
527 ++new_table->chunks [j]->refcount;
528 ++j;
532 g_assert (j == new_table->num_chunks);
534 return new_table;
537 /* As we add an element to the table the case can arise that the chunk
538 * to which we need to add is already full. In that case we have to
539 * allocate a new table and do something about that chunk. We have
540 * several strategies:
542 * If the number of elements in the table is below the low watermark
543 * or above the high watermark, we reallocate the whole table.
544 * Otherwise we only concern ourselves with the overflowing chunk:
546 * If there are no tombstones in the chunk then we split the chunk in
547 * two, each half full.
549 * If the chunk does contain tombstones, we just make a new copy of
550 * the chunk without the tombstones, which will have room for at least
551 * the one element we have to add.
553 static MonoJitInfoTable*
554 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
556 int num_elements = jit_info_table_num_elements (table);
557 int i;
559 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
560 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
561 //printf ("reallocing table\n");
562 return jit_info_table_realloc (table);
565 /* count the number of non-tombstone elements in the chunk */
566 num_elements = 0;
567 for (i = 0; i < chunk->num_elements; ++i) {
568 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
569 ++num_elements;
572 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
573 //printf ("splitting chunk\n");
574 return jit_info_table_copy_and_split_chunk (table, chunk);
577 //printf ("purifying chunk\n");
578 return jit_info_table_copy_and_purify_chunk (table, chunk);
581 /* We add elements to the table by first making space for them by
582 * shifting the elements at the back to the right, one at a time.
583 * This results in duplicate entries during the process, but during
584 * all the time the table is in a sorted state. Also, when an element
585 * is replaced by another one, the element that replaces it has an end
586 * address that is equal to or lower than that of the replaced
587 * element. That property is necessary to guarantee that when
588 * searching for an element we end up at a position not higher than
589 * the one we're looking for (i.e. we either find the element directly
590 * or we end up to the left of it).
592 static void
593 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
595 MonoJitInfoTable *table;
596 MonoJitInfoTableChunk *chunk;
597 int chunk_pos, pos;
598 int num_elements;
599 int i;
601 table = *table_ptr;
603 restart:
604 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
605 g_assert (chunk_pos < table->num_chunks);
606 chunk = table->chunks [chunk_pos];
608 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
609 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
611 /* Debugging code, should be removed. */
612 //jit_info_table_check (new_table);
614 *table_ptr = new_table;
615 mono_memory_barrier ();
616 domain->num_jit_info_tables++;
617 mono_thread_hazardous_try_free (table, (MonoHazardousFreeFunc)mono_jit_info_table_free);
618 table = new_table;
620 goto restart;
623 /* Debugging code, should be removed. */
624 //jit_info_table_check (table);
626 num_elements = chunk->num_elements;
628 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
630 /* First we need to size up the chunk by one, by copying the
631 last item, or inserting the first one, if the table is
632 empty. */
633 if (num_elements > 0)
634 chunk->data [num_elements] = chunk->data [num_elements - 1];
635 else
636 chunk->data [0] = ji;
637 mono_memory_write_barrier ();
638 chunk->num_elements = ++num_elements;
640 /* Shift the elements up one by one. */
641 for (i = num_elements - 2; i >= pos; --i) {
642 mono_memory_write_barrier ();
643 chunk->data [i + 1] = chunk->data [i];
646 /* Now we have room and can insert the new item. */
647 mono_memory_write_barrier ();
648 chunk->data [pos] = ji;
650 /* Set the high code end address chunk entry. */
651 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
652 + chunk->data [chunk->num_elements - 1]->code_size;
654 /* Debugging code, should be removed. */
655 //jit_info_table_check (table);
658 void
659 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
661 g_assert (ji->d.method != NULL);
663 mono_domain_lock (domain);
665 ++mono_stats.jit_info_table_insert_count;
667 jit_info_table_add (domain, &domain->jit_info_table, ji);
669 mono_domain_unlock (domain);
672 static MonoJitInfo*
673 mono_jit_info_make_tombstone (MonoJitInfoTableChunk *chunk, MonoJitInfo *ji)
675 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
677 tombstone->code_start = ji->code_start;
678 tombstone->code_size = ji->code_size;
679 tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
680 tombstone->n.next_tombstone = chunk->next_tombstone;
681 chunk->next_tombstone = tombstone;
683 return tombstone;
687 * LOCKING: domain lock
689 static void
690 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
692 if (domain->num_jit_info_tables <= 1) {
693 /* Can it actually happen that we only have one table
694 but ji is still hazardous? */
695 mono_thread_hazardous_try_free (ji, g_free);
696 } else {
697 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
701 static void
702 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
704 MonoJitInfoTableChunk *chunk;
705 gpointer start = ji->code_start;
706 int chunk_pos, pos;
708 chunk_pos = jit_info_table_index (table, (gint8 *)start);
709 g_assert (chunk_pos < table->num_chunks);
711 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, (gint8 *)start);
713 do {
714 chunk = table->chunks [chunk_pos];
716 while (pos < chunk->num_elements) {
717 if (chunk->data [pos] == ji)
718 goto found;
720 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
721 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
722 <= (guint8*)ji->code_start + ji->code_size);
724 ++pos;
727 ++chunk_pos;
728 pos = 0;
729 } while (chunk_pos < table->num_chunks);
731 found:
732 g_assert (chunk->data [pos] == ji);
734 chunk->data [pos] = mono_jit_info_make_tombstone (chunk, ji);
736 /* Debugging code, should be removed. */
737 //jit_info_table_check (table);
740 void
741 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
743 MonoJitInfoTable *table;
745 mono_domain_lock (domain);
746 table = domain->jit_info_table;
748 ++mono_stats.jit_info_table_remove_count;
750 jit_info_table_remove (table, ji);
752 mono_jit_info_free_or_queue (domain, ji);
754 mono_domain_unlock (domain);
757 void
758 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
760 MonoJitInfo *ji;
761 MonoDomain *domain = mono_get_root_domain ();
763 g_assert (domain);
764 mono_domain_lock (domain);
767 * We reuse MonoJitInfoTable to store AOT module info,
768 * this gives us async-safe lookup.
770 if (!domain->aot_modules) {
771 domain->num_jit_info_tables ++;
772 domain->aot_modules = mono_jit_info_table_new (domain);
775 ji = g_new0 (MonoJitInfo, 1);
776 ji->d.image = image;
777 ji->code_start = start;
778 ji->code_size = (guint8*)end - (guint8*)start;
779 jit_info_table_add (domain, &domain->aot_modules, ji);
781 mono_domain_unlock (domain);
784 void
785 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
787 jit_info_find_in_aot_func = func;
791 mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
793 int size = MONO_SIZEOF_JIT_INFO;
795 size += num_clauses * sizeof (MonoJitExceptionInfo);
796 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
797 size += sizeof (MonoGenericJitInfo);
798 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
799 size += sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
800 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
801 size += sizeof (MonoArchEHJitInfo);
802 if (flags & JIT_INFO_HAS_THUNK_INFO)
803 size += sizeof (MonoThunkJitInfo);
804 return size;
807 void
808 mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
809 MonoJitInfoFlags flags, int num_clauses, int num_holes)
811 ji->d.method = method;
812 ji->code_start = code;
813 ji->code_size = code_size;
814 ji->num_clauses = num_clauses;
815 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
816 ji->has_generic_jit_info = 1;
817 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
818 ji->has_try_block_holes = 1;
819 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
820 ji->has_arch_eh_info = 1;
821 if (flags & JIT_INFO_HAS_THUNK_INFO)
822 ji->has_thunk_info = 1;
826 * mono_jit_info_get_code_start:
827 * @ji: the JIT information handle
829 * Use this function to get the starting address for the method described by
830 * the @ji object. You can use this plus the `mono_jit_info_get_code_size`
831 * to determine the start and end of the native code.
833 * Returns: Starting address with the native code.
835 gpointer
836 mono_jit_info_get_code_start (MonoJitInfo* ji)
838 return ji->code_start;
842 * mono_jit_info_get_code_size:
843 * @ji: the JIT information handle
845 * Use this function to get the code size for the method described by
846 * the @ji object. You can use this plus the `mono_jit_info_get_code_start`
847 * to determine the start and end of the native code.
849 * Returns: Starting address with the native code.
852 mono_jit_info_get_code_size (MonoJitInfo* ji)
854 return ji->code_size;
858 * mono_jit_info_get_method:
859 * @ji: the JIT information handle
861 * Use this function to get the `MonoMethod *` that backs
862 * the @ji object.
864 * Returns: The MonoMethod that represents the code tracked
865 * by @ji.
867 MonoMethod*
868 mono_jit_info_get_method (MonoJitInfo* ji)
870 g_assert (!ji->async);
871 g_assert (!ji->is_trampoline);
872 return ji->d.method;
875 static gpointer
876 jit_info_key_extract (gpointer value)
878 MonoJitInfo *info = (MonoJitInfo*)value;
880 return info->d.method;
883 static gpointer*
884 jit_info_next_value (gpointer value)
886 MonoJitInfo *info = (MonoJitInfo*)value;
888 return (gpointer*)&info->n.next_jit_code_hash;
891 void
892 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
894 mono_internal_hash_table_init (jit_code_hash,
895 mono_aligned_addr_hash,
896 jit_info_key_extract,
897 jit_info_next_value);
900 MonoGenericJitInfo*
901 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
903 if (ji->has_generic_jit_info)
904 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
905 else
906 return NULL;
910 * mono_jit_info_get_generic_sharing_context:
911 * @ji: a jit info
913 * Returns the jit info's generic sharing context, or NULL if it
914 * doesn't have one.
916 MonoGenericSharingContext*
917 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
919 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
921 if (gi)
922 return gi->generic_sharing_context;
923 else
924 return NULL;
928 * mono_jit_info_set_generic_sharing_context:
929 * @ji: a jit info
930 * @gsctx: a generic sharing context
932 * Sets the jit info's generic sharing context. The jit info must
933 * have memory allocated for the context.
935 void
936 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
938 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
940 g_assert (gi);
942 gi->generic_sharing_context = gsctx;
945 MonoTryBlockHoleTableJitInfo*
946 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
948 if (ji->has_try_block_holes) {
949 char *ptr = (char*)&ji->clauses [ji->num_clauses];
950 if (ji->has_generic_jit_info)
951 ptr += sizeof (MonoGenericJitInfo);
952 return (MonoTryBlockHoleTableJitInfo*)ptr;
953 } else {
954 return NULL;
958 static int
959 try_block_hole_table_size (MonoJitInfo *ji)
961 MonoTryBlockHoleTableJitInfo *table;
963 table = mono_jit_info_get_try_block_hole_table_info (ji);
964 g_assert (table);
965 return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
968 MonoArchEHJitInfo*
969 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
971 if (ji->has_arch_eh_info) {
972 char *ptr = (char*)&ji->clauses [ji->num_clauses];
973 if (ji->has_generic_jit_info)
974 ptr += sizeof (MonoGenericJitInfo);
975 if (ji->has_try_block_holes)
976 ptr += try_block_hole_table_size (ji);
977 return (MonoArchEHJitInfo*)ptr;
978 } else {
979 return NULL;
983 MonoThunkJitInfo*
984 mono_jit_info_get_thunk_info (MonoJitInfo *ji)
986 if (ji->has_thunk_info) {
987 char *ptr = (char*)&ji->clauses [ji->num_clauses];
988 if (ji->has_generic_jit_info)
989 ptr += sizeof (MonoGenericJitInfo);
990 if (ji->has_try_block_holes)
991 ptr += try_block_hole_table_size (ji);
992 if (ji->has_arch_eh_info)
993 ptr += sizeof (MonoArchEHJitInfo);
994 return (MonoThunkJitInfo*)ptr;
995 } else {
996 return NULL;