3 * MonoJitInfo functionality
6 * Dietmar Maurer (dietmar@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/gc-internals.h>
22 #include <mono/utils/atomic.h>
23 #include <mono/utils/mono-compiler.h>
24 #include <mono/utils/mono-logger-internals.h>
25 #include <mono/utils/mono-membar.h>
26 #include <mono/utils/mono-counters.h>
27 #include <mono/utils/hazard-pointer.h>
28 #include <mono/utils/mono-tls.h>
29 #include <mono/utils/mono-mmap.h>
30 #include <mono/utils/mono-threads.h>
31 #include <mono/utils/unlocked.h>
32 #include <mono/metadata/object.h>
33 #include <mono/metadata/object-internals.h>
34 #include <mono/metadata/domain-internals.h>
35 #include <mono/metadata/class-internals.h>
36 #include <mono/metadata/assembly.h>
37 #include <mono/metadata/exception.h>
38 #include <mono/metadata/metadata-internals.h>
39 #include <mono/metadata/appdomain.h>
40 #include <mono/metadata/debug-internals.h>
41 #include <mono/metadata/mono-config.h>
42 #include <mono/metadata/threads-types.h>
43 #include <mono/metadata/runtime.h>
44 #include <metadata/threads.h>
45 #include <metadata/profiler-private.h>
46 #include <mono/metadata/coree.h>
48 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
50 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
51 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
52 #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)
54 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
55 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
57 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
58 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
60 #define JIT_INFO_TABLE_HAZARD_INDEX 0
61 #define JIT_INFO_HAZARD_INDEX 1
64 jit_info_table_num_elements (MonoJitInfoTable *table)
66 return table->num_valid;
69 static MonoJitInfoTableChunk*
70 jit_info_table_new_chunk (void)
72 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
79 mono_jit_info_table_new (MonoDomain *domain)
81 MonoJitInfoTable *table = (MonoJitInfoTable *)g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
83 table->domain = domain;
84 table->num_chunks = 1;
85 table->chunks [0] = jit_info_table_new_chunk ();
92 mono_jit_info_table_free (MonoJitInfoTable *table)
95 int num_chunks = table->num_chunks;
96 MonoDomain *domain = table->domain;
98 mono_domain_lock (domain);
100 table->domain->num_jit_info_tables--;
101 if (table->domain->num_jit_info_tables <= 1) {
104 for (list = table->domain->jit_info_free_queue; list; list = list->next)
107 g_slist_free (table->domain->jit_info_free_queue);
108 table->domain->jit_info_free_queue = NULL;
111 /* At this point we assume that there are no other threads
112 still accessing the table, so we don't have to worry about
113 hazardous pointers. */
115 for (i = 0; i < num_chunks; ++i) {
116 MonoJitInfoTableChunk *chunk = table->chunks [i];
117 MonoJitInfo *tombstone;
119 if (--chunk->refcount > 0)
122 for (tombstone = chunk->next_tombstone; tombstone; ) {
123 MonoJitInfo *next = tombstone->n.next_tombstone;
131 mono_domain_unlock (domain);
136 /* The jit_info_table is sorted in ascending order by the end
137 * addresses of the compiled methods. The reason why we have to do
138 * this is that once we introduce tombstones, it becomes possible for
139 * code ranges to overlap, and if we sort by code start and insert at
140 * the back of the table, we cannot guarantee that we won't overlook
143 * There are actually two possible ways to do the sorting and
144 * inserting which work with our lock-free mechanism:
146 * 1. Sort by start address and insert at the front. When looking for
147 * an entry, find the last one with a start address lower than the one
148 * you're looking for, then work your way to the front of the table.
150 * 2. Sort by end address and insert at the back. When looking for an
151 * entry, find the first one with an end address higher than the one
152 * you're looking for, then work your way to the end of the table.
154 * We chose the latter out of convenience.
157 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
159 int left = 0, right = table->num_chunks;
161 g_assert (left < right);
164 int pos = (left + right) / 2;
165 MonoJitInfoTableChunk *chunk = table->chunks [pos];
167 if (addr < chunk->last_code_end)
171 } while (left < right);
172 g_assert (left == right);
174 if (left >= table->num_chunks)
175 return table->num_chunks - 1;
180 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
182 int left = 0, right = chunk->num_elements;
184 while (left < right) {
185 int pos = (left + right) / 2;
186 MonoJitInfo *ji = (MonoJitInfo *)mono_get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
187 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
194 g_assert (left == right);
200 jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
205 chunk_pos = jit_info_table_index (table, (gint8*)addr);
206 g_assert (chunk_pos < table->num_chunks);
208 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
210 /* We now have a position that's very close to that of the
211 first element whose end address is higher than the one
212 we're looking for. If we don't have the exact position,
213 then we have a position below that one, so we'll just
214 search upward until we find our element. */
216 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
218 while (pos < chunk->num_elements) {
219 ji = (MonoJitInfo *)mono_get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
223 if (IS_JIT_INFO_TOMBSTONE (ji)) {
224 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
227 if ((gint8*)addr >= (gint8*)ji->code_start
228 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
229 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
233 /* If we find a non-tombstone element which is already
234 beyond what we're looking for, we have to end the
236 if ((gint8*)addr < (gint8*)ji->code_start)
242 } while (chunk_pos < table->num_chunks);
246 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
251 * mono_jit_info_table_find_internal:
253 * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
254 * In this case, only those AOT methods will be found whose jit info is already loaded.
255 * If ALLOW_TRAMPOLINES is TRUE, this can return a MonoJitInfo which represents a trampoline (ji->is_trampoline is true).
256 * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
257 * In this case, the returned MonoJitInfo might not have metadata information, in particular,
258 * mono_jit_info_get_method () could fail.
261 mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot, gboolean allow_trampolines)
263 MonoJitInfoTable *table;
264 MonoJitInfo *ji, *module_ji;
265 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
267 UnlockedIncrement (&mono_stats.jit_info_table_lookup_count);
269 /* First we have to get the domain's jit_info_table. This is
270 complicated by the fact that a writer might substitute a
271 new table and free the old one. What the writer guarantees
272 us is that it looks at the hazard pointers after it has
273 changed the jit_info_table pointer. So, if we guard the
274 table by a hazard pointer and make sure that the pointer is
275 still there after we've made it hazardous, we don't have to
276 worry about the writer freeing the table. */
277 table = (MonoJitInfoTable *)mono_get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
279 ji = jit_info_table_find (table, hp, (gint8*)addr);
281 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
282 if (ji && ji->is_trampoline && !allow_trampolines)
287 /* Maybe its an AOT module */
288 if (try_aot && mono_get_root_domain () && mono_get_root_domain ()->aot_modules) {
289 table = (MonoJitInfoTable *)mono_get_hazardous_pointer ((gpointer volatile*)&mono_get_root_domain ()->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
290 module_ji = jit_info_table_find (table, hp, (gint8*)addr);
292 ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
294 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
297 if (ji && ji->is_trampoline && !allow_trampolines)
304 * mono_jit_info_table_find:
305 * \param domain Domain that you want to look up
306 * \param addr Points to an address with JITed code.
308 * Use this function to obtain a \c MonoJitInfo* object that can be used to get
309 * some statistics. You should provide both the \p domain on which you will be
310 * performing the probe, and an address. Since application domains can share code
311 * the same address can be in use by multiple domains at once.
313 * This does not return any results for trampolines.
315 * \returns NULL if the address does not belong to JITed code (it might be native
316 * code or a trampoline) or a valid pointer to a \c MonoJitInfo* .
319 mono_jit_info_table_find (MonoDomain *domain, char *addr)
321 return mono_jit_info_table_find_internal (domain, addr, TRUE, FALSE);
324 static G_GNUC_UNUSED void
325 jit_info_table_check (MonoJitInfoTable *table)
329 for (i = 0; i < table->num_chunks; ++i) {
330 MonoJitInfoTableChunk *chunk = table->chunks [i];
333 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
334 if (chunk->refcount > 10)
335 printf("warning: chunk refcount is %d\n", chunk->refcount);
336 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
338 for (j = 0; j < chunk->num_elements; ++j) {
339 MonoJitInfo *this_ji = chunk->data [j];
342 g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= chunk->last_code_end);
344 if (j < chunk->num_elements - 1)
345 next = chunk->data [j + 1];
346 else if (i < table->num_chunks - 1) {
349 for (k = i + 1; k < table->num_chunks; ++k)
350 if (table->chunks [k]->num_elements > 0)
353 if (k >= table->num_chunks)
356 g_assert (table->chunks [k]->num_elements > 0);
357 next = table->chunks [k]->data [0];
361 g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= (gint8*)next->code_start + next->code_size);
366 static MonoJitInfoTable*
367 jit_info_table_realloc (MonoJitInfoTable *old)
370 int num_elements = jit_info_table_num_elements (old);
373 int new_chunk, new_element;
374 MonoJitInfoTable *result;
376 /* number of needed places for elements needed */
377 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
378 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
379 if (num_chunks == 0) {
380 g_assert (num_elements == 0);
381 return mono_jit_info_table_new (old->domain);
383 g_assert (num_chunks > 0);
385 result = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
386 result->domain = old->domain;
387 result->num_chunks = num_chunks;
388 result->num_valid = old->num_valid;
390 for (i = 0; i < num_chunks; ++i)
391 result->chunks [i] = jit_info_table_new_chunk ();
395 for (i = 0; i < old->num_chunks; ++i) {
396 MonoJitInfoTableChunk *chunk = old->chunks [i];
397 int chunk_num_elements = chunk->num_elements;
400 for (j = 0; j < chunk_num_elements; ++j) {
401 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
402 g_assert (new_chunk < num_chunks);
403 result->chunks [new_chunk]->data [new_element] = chunk->data [j];
404 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
405 result->chunks [new_chunk]->num_elements = new_element;
413 if (new_chunk < num_chunks) {
414 g_assert (new_chunk == num_chunks - 1);
415 result->chunks [new_chunk]->num_elements = new_element;
416 g_assert (result->chunks [new_chunk]->num_elements > 0);
419 for (i = 0; i < num_chunks; ++i) {
420 MonoJitInfoTableChunk *chunk = result->chunks [i];
421 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
423 result->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
430 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
432 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
433 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
435 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
437 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
438 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
440 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
441 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
443 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
444 + new1->data [new1->num_elements - 1]->code_size;
445 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
446 + new2->data [new2->num_elements - 1]->code_size;
452 static MonoJitInfoTable*
453 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
455 MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
456 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
459 new_table->domain = table->domain;
460 new_table->num_chunks = table->num_chunks + 1;
461 new_table->num_valid = table->num_valid;
464 for (i = 0; i < table->num_chunks; ++i) {
465 if (table->chunks [i] == chunk) {
466 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
469 new_table->chunks [j] = table->chunks [i];
470 ++new_table->chunks [j]->refcount;
475 g_assert (j == new_table->num_chunks);
480 static MonoJitInfoTableChunk*
481 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
483 MonoJitInfoTableChunk *result = jit_info_table_new_chunk ();
487 for (i = 0; i < old->num_elements; ++i) {
488 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
489 result->data [j++] = old->data [i];
492 result->num_elements = j;
493 if (result->num_elements > 0)
494 result->last_code_end = (gint8*)result->data [j - 1]->code_start + result->data [j - 1]->code_size;
496 result->last_code_end = old->last_code_end;
501 static MonoJitInfoTable*
502 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
504 MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
505 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
508 new_table->domain = table->domain;
509 new_table->num_chunks = table->num_chunks;
510 new_table->num_valid = table->num_valid;
513 for (i = 0; i < table->num_chunks; ++i) {
514 if (table->chunks [i] == chunk)
515 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
517 new_table->chunks [j] = table->chunks [i];
518 ++new_table->chunks [j]->refcount;
523 g_assert (j == new_table->num_chunks);
528 /* As we add an element to the table the case can arise that the chunk
529 * to which we need to add is already full. In that case we have to
530 * allocate a new table and do something about that chunk. We have
531 * several strategies:
533 * If the number of elements in the table is below the low watermark
534 * or above the high watermark, we reallocate the whole table.
535 * Otherwise we only concern ourselves with the overflowing chunk:
537 * If there are no tombstones in the chunk then we split the chunk in
538 * two, each half full.
540 * If the chunk does contain tombstones, we just make a new copy of
541 * the chunk without the tombstones, which will have room for at least
542 * the one element we have to add.
544 static MonoJitInfoTable*
545 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
547 int num_elements = jit_info_table_num_elements (table);
550 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
551 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
552 //printf ("reallocing table\n");
553 return jit_info_table_realloc (table);
556 /* count the number of non-tombstone elements in the chunk */
558 for (i = 0; i < chunk->num_elements; ++i) {
559 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
563 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
564 //printf ("splitting chunk\n");
565 return jit_info_table_copy_and_split_chunk (table, chunk);
568 //printf ("purifying chunk\n");
569 return jit_info_table_copy_and_purify_chunk (table, chunk);
572 /* We add elements to the table by first making space for them by
573 * shifting the elements at the back to the right, one at a time.
574 * This results in duplicate entries during the process, but during
575 * all the time the table is in a sorted state. Also, when an element
576 * is replaced by another one, the element that replaces it has an end
577 * address that is equal to or lower than that of the replaced
578 * element. That property is necessary to guarantee that when
579 * searching for an element we end up at a position not higher than
580 * the one we're looking for (i.e. we either find the element directly
581 * or we end up to the left of it).
584 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
586 MonoJitInfoTable *table;
587 MonoJitInfoTableChunk *chunk;
595 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
596 g_assert (chunk_pos < table->num_chunks);
597 chunk = table->chunks [chunk_pos];
599 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
600 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
602 /* Debugging code, should be removed. */
603 //jit_info_table_check (new_table);
605 *table_ptr = new_table;
606 mono_memory_barrier ();
607 domain->num_jit_info_tables++;
608 mono_thread_hazardous_try_free (table, (MonoHazardousFreeFunc)mono_jit_info_table_free);
614 /* Debugging code, should be removed. */
615 //jit_info_table_check (table);
617 num_elements = chunk->num_elements;
619 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
621 /* First we need to size up the chunk by one, by copying the
622 last item, or inserting the first one, if the table is
624 if (num_elements > 0)
625 chunk->data [num_elements] = chunk->data [num_elements - 1];
627 chunk->data [0] = ji;
628 mono_memory_write_barrier ();
629 chunk->num_elements = ++num_elements;
631 /* Shift the elements up one by one. */
632 for (i = num_elements - 2; i >= pos; --i) {
633 mono_memory_write_barrier ();
634 chunk->data [i + 1] = chunk->data [i];
637 /* Now we have room and can insert the new item. */
638 mono_memory_write_barrier ();
639 chunk->data [pos] = ji;
641 /* Set the high code end address chunk entry. */
642 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
643 + chunk->data [chunk->num_elements - 1]->code_size;
647 /* Debugging code, should be removed. */
648 //jit_info_table_check (table);
652 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
654 g_assert (ji->d.method != NULL);
656 mono_domain_lock (domain);
658 UnlockedIncrement (&mono_stats.jit_info_table_insert_count);
660 jit_info_table_add (domain, &domain->jit_info_table, ji);
662 mono_domain_unlock (domain);
666 mono_jit_info_make_tombstone (MonoJitInfoTableChunk *chunk, MonoJitInfo *ji)
668 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
670 tombstone->code_start = ji->code_start;
671 tombstone->code_size = ji->code_size;
672 tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
673 tombstone->n.next_tombstone = chunk->next_tombstone;
674 chunk->next_tombstone = tombstone;
680 * LOCKING: domain lock
683 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
685 if (domain->num_jit_info_tables <= 1) {
686 /* Can it actually happen that we only have one table
687 but ji is still hazardous? */
688 mono_thread_hazardous_try_free (ji, g_free);
690 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
695 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
697 MonoJitInfoTableChunk *chunk;
698 gpointer start = ji->code_start;
701 chunk_pos = jit_info_table_index (table, (gint8 *)start);
702 g_assert (chunk_pos < table->num_chunks);
704 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, (gint8 *)start);
707 chunk = table->chunks [chunk_pos];
709 while (pos < chunk->num_elements) {
710 if (chunk->data [pos] == ji)
713 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
714 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
715 <= (guint8*)ji->code_start + ji->code_size);
722 } while (chunk_pos < table->num_chunks);
725 g_assert (chunk->data [pos] == ji);
727 chunk->data [pos] = mono_jit_info_make_tombstone (chunk, ji);
730 /* Debugging code, should be removed. */
731 //jit_info_table_check (table);
735 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
737 MonoJitInfoTable *table;
739 mono_domain_lock (domain);
740 table = domain->jit_info_table;
742 UnlockedIncrement (&mono_stats.jit_info_table_remove_count);
744 jit_info_table_remove (table, ji);
746 mono_jit_info_free_or_queue (domain, ji);
748 mono_domain_unlock (domain);
752 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
755 MonoDomain *domain = mono_get_root_domain ();
758 mono_domain_lock (domain);
761 * We reuse MonoJitInfoTable to store AOT module info,
762 * this gives us async-safe lookup.
764 if (!domain->aot_modules) {
765 domain->num_jit_info_tables ++;
766 domain->aot_modules = mono_jit_info_table_new (domain);
769 ji = g_new0 (MonoJitInfo, 1);
771 ji->code_start = start;
772 ji->code_size = (guint8*)end - (guint8*)start;
773 jit_info_table_add (domain, &domain->aot_modules, ji);
775 mono_domain_unlock (domain);
779 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
781 jit_info_find_in_aot_func = func;
785 mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
787 int size = MONO_SIZEOF_JIT_INFO;
789 size += num_clauses * sizeof (MonoJitExceptionInfo);
790 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
791 size += sizeof (MonoGenericJitInfo);
792 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
793 size += sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
794 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
795 size += sizeof (MonoArchEHJitInfo);
796 if (flags & JIT_INFO_HAS_THUNK_INFO)
797 size += sizeof (MonoThunkJitInfo);
798 if (flags & JIT_INFO_HAS_UNWIND_INFO)
799 size += sizeof (MonoUnwindJitInfo);
804 mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
805 MonoJitInfoFlags flags, int num_clauses, int num_holes)
807 ji->d.method = method;
808 ji->code_start = code;
809 ji->code_size = code_size;
810 ji->num_clauses = num_clauses;
811 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
812 ji->has_generic_jit_info = 1;
813 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
814 ji->has_try_block_holes = 1;
815 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
816 ji->has_arch_eh_info = 1;
817 if (flags & JIT_INFO_HAS_THUNK_INFO)
818 ji->has_thunk_info = 1;
819 if (flags & JIT_INFO_HAS_UNWIND_INFO)
820 ji->has_unwind_info = 1;
824 * mono_jit_info_get_code_start:
825 * \param ji the JIT information handle
827 * Use this function to get the starting address for the method described by
828 * the \p ji object. You can use this plus the \c mono_jit_info_get_code_size
829 * to determine the start and end of the native code.
831 * \returns Starting address with the native code.
834 mono_jit_info_get_code_start (MonoJitInfo* ji)
836 return ji->code_start;
840 * mono_jit_info_get_code_size:
841 * \param ji the JIT information handle
843 * Use this function to get the code size for the method described by
844 * the \p ji object. You can use this plus the \c mono_jit_info_get_code_start
845 * to determine the start and end of the native code.
847 * \returns Starting address with the native code.
850 mono_jit_info_get_code_size (MonoJitInfo* ji)
852 return ji->code_size;
856 * mono_jit_info_get_method:
857 * \param ji the JIT information handle
859 * Use this function to get the \c MonoMethod* that backs
862 * \returns The \c MonoMethod that represents the code tracked
866 mono_jit_info_get_method (MonoJitInfo* ji)
868 g_assert (!ji->async);
869 g_assert (!ji->is_trampoline);
874 jit_info_key_extract (gpointer value)
876 MonoJitInfo *info = (MonoJitInfo*)value;
878 return info->d.method;
882 jit_info_next_value (gpointer value)
884 MonoJitInfo *info = (MonoJitInfo*)value;
886 return (gpointer*)&info->n.next_jit_code_hash;
890 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
892 mono_internal_hash_table_init (jit_code_hash,
893 mono_aligned_addr_hash,
894 jit_info_key_extract,
895 jit_info_next_value);
899 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
901 if (ji->has_generic_jit_info)
902 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
908 * mono_jit_info_get_generic_sharing_context:
911 * Returns the jit info's generic sharing context, or NULL if it
914 MonoGenericSharingContext*
915 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
917 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
920 return gi->generic_sharing_context;
926 * mono_jit_info_set_generic_sharing_context:
928 * @gsctx: a generic sharing context
930 * Sets the jit info's generic sharing context. The jit info must
931 * have memory allocated for the context.
934 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
936 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
940 gi->generic_sharing_context = gsctx;
943 MonoTryBlockHoleTableJitInfo*
944 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
946 if (ji->has_try_block_holes) {
947 char *ptr = (char*)&ji->clauses [ji->num_clauses];
948 if (ji->has_generic_jit_info)
949 ptr += sizeof (MonoGenericJitInfo);
950 return (MonoTryBlockHoleTableJitInfo*)ptr;
957 try_block_hole_table_size (MonoJitInfo *ji)
959 MonoTryBlockHoleTableJitInfo *table;
961 table = mono_jit_info_get_try_block_hole_table_info (ji);
963 return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
967 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
969 if (ji->has_arch_eh_info) {
970 char *ptr = (char*)&ji->clauses [ji->num_clauses];
971 if (ji->has_generic_jit_info)
972 ptr += sizeof (MonoGenericJitInfo);
973 if (ji->has_try_block_holes)
974 ptr += try_block_hole_table_size (ji);
975 return (MonoArchEHJitInfo*)ptr;
982 mono_jit_info_get_thunk_info (MonoJitInfo *ji)
984 if (ji->has_thunk_info) {
985 char *ptr = (char*)&ji->clauses [ji->num_clauses];
986 if (ji->has_generic_jit_info)
987 ptr += sizeof (MonoGenericJitInfo);
988 if (ji->has_try_block_holes)
989 ptr += try_block_hole_table_size (ji);
990 if (ji->has_arch_eh_info)
991 ptr += sizeof (MonoArchEHJitInfo);
992 return (MonoThunkJitInfo*)ptr;
999 mono_jit_info_get_unwind_info (MonoJitInfo *ji)
1001 if (ji->has_unwind_info) {
1002 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1003 if (ji->has_generic_jit_info)
1004 ptr += sizeof (MonoGenericJitInfo);
1005 if (ji->has_try_block_holes)
1006 ptr += try_block_hole_table_size (ji);
1007 if (ji->has_arch_eh_info)
1008 ptr += sizeof (MonoArchEHJitInfo);
1009 if (ji->has_thunk_info)
1010 ptr += sizeof (MonoThunkJitInfo);
1011 return (MonoUnwindJitInfo*)ptr;