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/metadata/object.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/domain-internals.h>
34 #include <mono/metadata/class-internals.h>
35 #include <mono/metadata/assembly.h>
36 #include <mono/metadata/exception.h>
37 #include <mono/metadata/metadata-internals.h>
38 #include <mono/metadata/appdomain.h>
39 #include <mono/metadata/debug-internals.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
63 jit_info_table_num_elements (MonoJitInfoTable *table)
65 return table->num_valid;
68 static MonoJitInfoTableChunk*
69 jit_info_table_new_chunk (void)
71 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
78 mono_jit_info_table_new (MonoDomain *domain)
80 MonoJitInfoTable *table = (MonoJitInfoTable *)g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
82 table->domain = domain;
83 table->num_chunks = 1;
84 table->chunks [0] = jit_info_table_new_chunk ();
91 mono_jit_info_table_free (MonoJitInfoTable *table)
94 int num_chunks = table->num_chunks;
95 MonoDomain *domain = table->domain;
97 mono_domain_lock (domain);
99 table->domain->num_jit_info_tables--;
100 if (table->domain->num_jit_info_tables <= 1) {
103 for (list = table->domain->jit_info_free_queue; list; list = list->next)
106 g_slist_free (table->domain->jit_info_free_queue);
107 table->domain->jit_info_free_queue = NULL;
110 /* At this point we assume that there are no other threads
111 still accessing the table, so we don't have to worry about
112 hazardous pointers. */
114 for (i = 0; i < num_chunks; ++i) {
115 MonoJitInfoTableChunk *chunk = table->chunks [i];
116 MonoJitInfo *tombstone;
118 if (--chunk->refcount > 0)
121 for (tombstone = chunk->next_tombstone; tombstone; ) {
122 MonoJitInfo *next = tombstone->n.next_tombstone;
130 mono_domain_unlock (domain);
135 /* The jit_info_table is sorted in ascending order by the end
136 * addresses of the compiled methods. The reason why we have to do
137 * this is that once we introduce tombstones, it becomes possible for
138 * code ranges to overlap, and if we sort by code start and insert at
139 * the back of the table, we cannot guarantee that we won't overlook
142 * There are actually two possible ways to do the sorting and
143 * inserting which work with our lock-free mechanism:
145 * 1. Sort by start address and insert at the front. When looking for
146 * an entry, find the last one with a start address lower than the one
147 * you're looking for, then work your way to the front of the table.
149 * 2. Sort by end address and insert at the back. When looking for an
150 * entry, find the first one with an end address higher than the one
151 * you're looking for, then work your way to the end of the table.
153 * We chose the latter out of convenience.
156 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
158 int left = 0, right = table->num_chunks;
160 g_assert (left < right);
163 int pos = (left + right) / 2;
164 MonoJitInfoTableChunk *chunk = table->chunks [pos];
166 if (addr < chunk->last_code_end)
170 } while (left < right);
171 g_assert (left == right);
173 if (left >= table->num_chunks)
174 return table->num_chunks - 1;
179 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
181 int left = 0, right = chunk->num_elements;
183 while (left < right) {
184 int pos = (left + right) / 2;
185 MonoJitInfo *ji = (MonoJitInfo *)mono_get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
186 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
193 g_assert (left == right);
199 jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
204 chunk_pos = jit_info_table_index (table, (gint8*)addr);
205 g_assert (chunk_pos < table->num_chunks);
207 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
209 /* We now have a position that's very close to that of the
210 first element whose end address is higher than the one
211 we're looking for. If we don't have the exact position,
212 then we have a position below that one, so we'll just
213 search upward until we find our element. */
215 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
217 while (pos < chunk->num_elements) {
218 ji = (MonoJitInfo *)mono_get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
222 if (IS_JIT_INFO_TOMBSTONE (ji)) {
223 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
226 if ((gint8*)addr >= (gint8*)ji->code_start
227 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
228 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
232 /* If we find a non-tombstone element which is already
233 beyond what we're looking for, we have to end the
235 if ((gint8*)addr < (gint8*)ji->code_start)
241 } while (chunk_pos < table->num_chunks);
245 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
250 * mono_jit_info_table_find_internal:
252 * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
253 * In this case, only those AOT methods will be found whose jit info is already loaded.
254 * If ALLOW_TRAMPOLINES is TRUE, this can return a MonoJitInfo which represents a trampoline (ji->is_trampoline is true).
255 * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
256 * In this case, the returned MonoJitInfo might not have metadata information, in particular,
257 * mono_jit_info_get_method () could fail.
260 mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot, gboolean allow_trampolines)
262 MonoJitInfoTable *table;
263 MonoJitInfo *ji, *module_ji;
264 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
266 ++mono_stats.jit_info_table_lookup_count;
268 /* First we have to get the domain's jit_info_table. This is
269 complicated by the fact that a writer might substitute a
270 new table and free the old one. What the writer guarantees
271 us is that it looks at the hazard pointers after it has
272 changed the jit_info_table pointer. So, if we guard the
273 table by a hazard pointer and make sure that the pointer is
274 still there after we've made it hazardous, we don't have to
275 worry about the writer freeing the table. */
276 table = (MonoJitInfoTable *)mono_get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
278 ji = jit_info_table_find (table, hp, (gint8*)addr);
280 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
281 if (ji && ji->is_trampoline && !allow_trampolines)
286 /* Maybe its an AOT module */
287 if (try_aot && mono_get_root_domain () && mono_get_root_domain ()->aot_modules) {
288 table = (MonoJitInfoTable *)mono_get_hazardous_pointer ((gpointer volatile*)&mono_get_root_domain ()->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
289 module_ji = jit_info_table_find (table, hp, (gint8*)addr);
291 ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
293 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
296 if (ji && ji->is_trampoline && !allow_trampolines)
303 * mono_jit_info_table_find:
304 * \param domain Domain that you want to look up
305 * \param addr Points to an address with JITed code.
307 * Use this function to obtain a \c MonoJitInfo* object that can be used to get
308 * some statistics. You should provide both the \p domain on which you will be
309 * performing the probe, and an address. Since application domains can share code
310 * the same address can be in use by multiple domains at once.
312 * This does not return any results for trampolines.
314 * \returns NULL if the address does not belong to JITed code (it might be native
315 * code or a trampoline) or a valid pointer to a \c MonoJitInfo* .
318 mono_jit_info_table_find (MonoDomain *domain, char *addr)
320 return mono_jit_info_table_find_internal (domain, addr, TRUE, FALSE);
323 static G_GNUC_UNUSED void
324 jit_info_table_check (MonoJitInfoTable *table)
328 for (i = 0; i < table->num_chunks; ++i) {
329 MonoJitInfoTableChunk *chunk = table->chunks [i];
332 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
333 if (chunk->refcount > 10)
334 printf("warning: chunk refcount is %d\n", chunk->refcount);
335 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
337 for (j = 0; j < chunk->num_elements; ++j) {
338 MonoJitInfo *this_ji = chunk->data [j];
341 g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= chunk->last_code_end);
343 if (j < chunk->num_elements - 1)
344 next = chunk->data [j + 1];
345 else if (i < table->num_chunks - 1) {
348 for (k = i + 1; k < table->num_chunks; ++k)
349 if (table->chunks [k]->num_elements > 0)
352 if (k >= table->num_chunks)
355 g_assert (table->chunks [k]->num_elements > 0);
356 next = table->chunks [k]->data [0];
360 g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= (gint8*)next->code_start + next->code_size);
365 static MonoJitInfoTable*
366 jit_info_table_realloc (MonoJitInfoTable *old)
369 int num_elements = jit_info_table_num_elements (old);
372 int new_chunk, new_element;
373 MonoJitInfoTable *result;
375 /* number of needed places for elements needed */
376 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
377 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
378 if (num_chunks == 0) {
379 g_assert (num_elements == 0);
380 return mono_jit_info_table_new (old->domain);
382 g_assert (num_chunks > 0);
384 result = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
385 result->domain = old->domain;
386 result->num_chunks = num_chunks;
387 result->num_valid = old->num_valid;
389 for (i = 0; i < num_chunks; ++i)
390 result->chunks [i] = jit_info_table_new_chunk ();
394 for (i = 0; i < old->num_chunks; ++i) {
395 MonoJitInfoTableChunk *chunk = old->chunks [i];
396 int chunk_num_elements = chunk->num_elements;
399 for (j = 0; j < chunk_num_elements; ++j) {
400 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
401 g_assert (new_chunk < num_chunks);
402 result->chunks [new_chunk]->data [new_element] = chunk->data [j];
403 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
404 result->chunks [new_chunk]->num_elements = new_element;
412 if (new_chunk < num_chunks) {
413 g_assert (new_chunk == num_chunks - 1);
414 result->chunks [new_chunk]->num_elements = new_element;
415 g_assert (result->chunks [new_chunk]->num_elements > 0);
418 for (i = 0; i < num_chunks; ++i) {
419 MonoJitInfoTableChunk *chunk = result->chunks [i];
420 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
422 result->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
429 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
431 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
432 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
434 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
436 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
437 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
439 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
440 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
442 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
443 + new1->data [new1->num_elements - 1]->code_size;
444 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
445 + new2->data [new2->num_elements - 1]->code_size;
451 static MonoJitInfoTable*
452 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
454 MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
455 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
458 new_table->domain = table->domain;
459 new_table->num_chunks = table->num_chunks + 1;
460 new_table->num_valid = table->num_valid;
463 for (i = 0; i < table->num_chunks; ++i) {
464 if (table->chunks [i] == chunk) {
465 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
468 new_table->chunks [j] = table->chunks [i];
469 ++new_table->chunks [j]->refcount;
474 g_assert (j == new_table->num_chunks);
479 static MonoJitInfoTableChunk*
480 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
482 MonoJitInfoTableChunk *result = jit_info_table_new_chunk ();
486 for (i = 0; i < old->num_elements; ++i) {
487 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
488 result->data [j++] = old->data [i];
491 result->num_elements = j;
492 if (result->num_elements > 0)
493 result->last_code_end = (gint8*)result->data [j - 1]->code_start + result->data [j - 1]->code_size;
495 result->last_code_end = old->last_code_end;
500 static MonoJitInfoTable*
501 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
503 MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
504 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
507 new_table->domain = table->domain;
508 new_table->num_chunks = table->num_chunks;
509 new_table->num_valid = table->num_valid;
512 for (i = 0; i < table->num_chunks; ++i) {
513 if (table->chunks [i] == chunk)
514 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
516 new_table->chunks [j] = table->chunks [i];
517 ++new_table->chunks [j]->refcount;
522 g_assert (j == new_table->num_chunks);
527 /* As we add an element to the table the case can arise that the chunk
528 * to which we need to add is already full. In that case we have to
529 * allocate a new table and do something about that chunk. We have
530 * several strategies:
532 * If the number of elements in the table is below the low watermark
533 * or above the high watermark, we reallocate the whole table.
534 * Otherwise we only concern ourselves with the overflowing chunk:
536 * If there are no tombstones in the chunk then we split the chunk in
537 * two, each half full.
539 * If the chunk does contain tombstones, we just make a new copy of
540 * the chunk without the tombstones, which will have room for at least
541 * the one element we have to add.
543 static MonoJitInfoTable*
544 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
546 int num_elements = jit_info_table_num_elements (table);
549 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
550 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
551 //printf ("reallocing table\n");
552 return jit_info_table_realloc (table);
555 /* count the number of non-tombstone elements in the chunk */
557 for (i = 0; i < chunk->num_elements; ++i) {
558 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
562 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
563 //printf ("splitting chunk\n");
564 return jit_info_table_copy_and_split_chunk (table, chunk);
567 //printf ("purifying chunk\n");
568 return jit_info_table_copy_and_purify_chunk (table, chunk);
571 /* We add elements to the table by first making space for them by
572 * shifting the elements at the back to the right, one at a time.
573 * This results in duplicate entries during the process, but during
574 * all the time the table is in a sorted state. Also, when an element
575 * is replaced by another one, the element that replaces it has an end
576 * address that is equal to or lower than that of the replaced
577 * element. That property is necessary to guarantee that when
578 * searching for an element we end up at a position not higher than
579 * the one we're looking for (i.e. we either find the element directly
580 * or we end up to the left of it).
583 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
585 MonoJitInfoTable *table;
586 MonoJitInfoTableChunk *chunk;
594 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
595 g_assert (chunk_pos < table->num_chunks);
596 chunk = table->chunks [chunk_pos];
598 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
599 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
601 /* Debugging code, should be removed. */
602 //jit_info_table_check (new_table);
604 *table_ptr = new_table;
605 mono_memory_barrier ();
606 domain->num_jit_info_tables++;
607 mono_thread_hazardous_try_free (table, (MonoHazardousFreeFunc)mono_jit_info_table_free);
613 /* Debugging code, should be removed. */
614 //jit_info_table_check (table);
616 num_elements = chunk->num_elements;
618 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
620 /* First we need to size up the chunk by one, by copying the
621 last item, or inserting the first one, if the table is
623 if (num_elements > 0)
624 chunk->data [num_elements] = chunk->data [num_elements - 1];
626 chunk->data [0] = ji;
627 mono_memory_write_barrier ();
628 chunk->num_elements = ++num_elements;
630 /* Shift the elements up one by one. */
631 for (i = num_elements - 2; i >= pos; --i) {
632 mono_memory_write_barrier ();
633 chunk->data [i + 1] = chunk->data [i];
636 /* Now we have room and can insert the new item. */
637 mono_memory_write_barrier ();
638 chunk->data [pos] = ji;
640 /* Set the high code end address chunk entry. */
641 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
642 + chunk->data [chunk->num_elements - 1]->code_size;
646 /* Debugging code, should be removed. */
647 //jit_info_table_check (table);
651 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
653 g_assert (ji->d.method != NULL);
655 mono_domain_lock (domain);
657 ++mono_stats.jit_info_table_insert_count;
659 jit_info_table_add (domain, &domain->jit_info_table, ji);
661 mono_domain_unlock (domain);
665 mono_jit_info_make_tombstone (MonoJitInfoTableChunk *chunk, MonoJitInfo *ji)
667 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
669 tombstone->code_start = ji->code_start;
670 tombstone->code_size = ji->code_size;
671 tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
672 tombstone->n.next_tombstone = chunk->next_tombstone;
673 chunk->next_tombstone = tombstone;
679 * LOCKING: domain lock
682 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
684 if (domain->num_jit_info_tables <= 1) {
685 /* Can it actually happen that we only have one table
686 but ji is still hazardous? */
687 mono_thread_hazardous_try_free (ji, g_free);
689 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
694 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
696 MonoJitInfoTableChunk *chunk;
697 gpointer start = ji->code_start;
700 chunk_pos = jit_info_table_index (table, (gint8 *)start);
701 g_assert (chunk_pos < table->num_chunks);
703 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, (gint8 *)start);
706 chunk = table->chunks [chunk_pos];
708 while (pos < chunk->num_elements) {
709 if (chunk->data [pos] == ji)
712 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
713 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
714 <= (guint8*)ji->code_start + ji->code_size);
721 } while (chunk_pos < table->num_chunks);
724 g_assert (chunk->data [pos] == ji);
726 chunk->data [pos] = mono_jit_info_make_tombstone (chunk, ji);
729 /* Debugging code, should be removed. */
730 //jit_info_table_check (table);
734 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
736 MonoJitInfoTable *table;
738 mono_domain_lock (domain);
739 table = domain->jit_info_table;
741 ++mono_stats.jit_info_table_remove_count;
743 jit_info_table_remove (table, ji);
745 mono_jit_info_free_or_queue (domain, ji);
747 mono_domain_unlock (domain);
751 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
754 MonoDomain *domain = mono_get_root_domain ();
757 mono_domain_lock (domain);
760 * We reuse MonoJitInfoTable to store AOT module info,
761 * this gives us async-safe lookup.
763 if (!domain->aot_modules) {
764 domain->num_jit_info_tables ++;
765 domain->aot_modules = mono_jit_info_table_new (domain);
768 ji = g_new0 (MonoJitInfo, 1);
770 ji->code_start = start;
771 ji->code_size = (guint8*)end - (guint8*)start;
772 jit_info_table_add (domain, &domain->aot_modules, ji);
774 mono_domain_unlock (domain);
778 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
780 jit_info_find_in_aot_func = func;
784 mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
786 int size = MONO_SIZEOF_JIT_INFO;
788 size += num_clauses * sizeof (MonoJitExceptionInfo);
789 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
790 size += sizeof (MonoGenericJitInfo);
791 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
792 size += sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
793 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
794 size += sizeof (MonoArchEHJitInfo);
795 if (flags & JIT_INFO_HAS_THUNK_INFO)
796 size += sizeof (MonoThunkJitInfo);
797 if (flags & JIT_INFO_HAS_UNWIND_INFO)
798 size += sizeof (MonoUnwindJitInfo);
803 mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
804 MonoJitInfoFlags flags, int num_clauses, int num_holes)
806 ji->d.method = method;
807 ji->code_start = code;
808 ji->code_size = code_size;
809 ji->num_clauses = num_clauses;
810 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
811 ji->has_generic_jit_info = 1;
812 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
813 ji->has_try_block_holes = 1;
814 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
815 ji->has_arch_eh_info = 1;
816 if (flags & JIT_INFO_HAS_THUNK_INFO)
817 ji->has_thunk_info = 1;
818 if (flags & JIT_INFO_HAS_UNWIND_INFO)
819 ji->has_unwind_info = 1;
823 * mono_jit_info_get_code_start:
824 * \param ji the JIT information handle
826 * Use this function to get the starting address for the method described by
827 * the \p ji object. You can use this plus the \c mono_jit_info_get_code_size
828 * to determine the start and end of the native code.
830 * \returns Starting address with the native code.
833 mono_jit_info_get_code_start (MonoJitInfo* ji)
835 return ji->code_start;
839 * mono_jit_info_get_code_size:
840 * \param ji the JIT information handle
842 * Use this function to get the code size for the method described by
843 * the \p ji object. You can use this plus the \c mono_jit_info_get_code_start
844 * to determine the start and end of the native code.
846 * \returns Starting address with the native code.
849 mono_jit_info_get_code_size (MonoJitInfo* ji)
851 return ji->code_size;
855 * mono_jit_info_get_method:
856 * \param ji the JIT information handle
858 * Use this function to get the \c MonoMethod* that backs
861 * \returns The \c MonoMethod that represents the code tracked
865 mono_jit_info_get_method (MonoJitInfo* ji)
867 g_assert (!ji->async);
868 g_assert (!ji->is_trampoline);
873 jit_info_key_extract (gpointer value)
875 MonoJitInfo *info = (MonoJitInfo*)value;
877 return info->d.method;
881 jit_info_next_value (gpointer value)
883 MonoJitInfo *info = (MonoJitInfo*)value;
885 return (gpointer*)&info->n.next_jit_code_hash;
889 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
891 mono_internal_hash_table_init (jit_code_hash,
892 mono_aligned_addr_hash,
893 jit_info_key_extract,
894 jit_info_next_value);
898 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
900 if (ji->has_generic_jit_info)
901 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
907 * mono_jit_info_get_generic_sharing_context:
910 * Returns the jit info's generic sharing context, or NULL if it
913 MonoGenericSharingContext*
914 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
916 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
919 return gi->generic_sharing_context;
925 * mono_jit_info_set_generic_sharing_context:
927 * @gsctx: a generic sharing context
929 * Sets the jit info's generic sharing context. The jit info must
930 * have memory allocated for the context.
933 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
935 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
939 gi->generic_sharing_context = gsctx;
942 MonoTryBlockHoleTableJitInfo*
943 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
945 if (ji->has_try_block_holes) {
946 char *ptr = (char*)&ji->clauses [ji->num_clauses];
947 if (ji->has_generic_jit_info)
948 ptr += sizeof (MonoGenericJitInfo);
949 return (MonoTryBlockHoleTableJitInfo*)ptr;
956 try_block_hole_table_size (MonoJitInfo *ji)
958 MonoTryBlockHoleTableJitInfo *table;
960 table = mono_jit_info_get_try_block_hole_table_info (ji);
962 return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
966 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
968 if (ji->has_arch_eh_info) {
969 char *ptr = (char*)&ji->clauses [ji->num_clauses];
970 if (ji->has_generic_jit_info)
971 ptr += sizeof (MonoGenericJitInfo);
972 if (ji->has_try_block_holes)
973 ptr += try_block_hole_table_size (ji);
974 return (MonoArchEHJitInfo*)ptr;
981 mono_jit_info_get_thunk_info (MonoJitInfo *ji)
983 if (ji->has_thunk_info) {
984 char *ptr = (char*)&ji->clauses [ji->num_clauses];
985 if (ji->has_generic_jit_info)
986 ptr += sizeof (MonoGenericJitInfo);
987 if (ji->has_try_block_holes)
988 ptr += try_block_hole_table_size (ji);
989 if (ji->has_arch_eh_info)
990 ptr += sizeof (MonoArchEHJitInfo);
991 return (MonoThunkJitInfo*)ptr;
998 mono_jit_info_get_unwind_info (MonoJitInfo *ji)
1000 if (ji->has_unwind_info) {
1001 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1002 if (ji->has_generic_jit_info)
1003 ptr += sizeof (MonoGenericJitInfo);
1004 if (ji->has_try_block_holes)
1005 ptr += try_block_hole_table_size (ji);
1006 if (ji->has_arch_eh_info)
1007 ptr += sizeof (MonoArchEHJitInfo);
1008 if (ji->has_thunk_info)
1009 ptr += sizeof (MonoThunkJitInfo);
1010 return (MonoUnwindJitInfo*)ptr;