2 * jit-info.c: MonoJitInfo functionality
5 * Dietmar Maurer (dietmar@ximian.com)
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)
18 #include <mono/metadata/gc-internals.h>
20 #include <mono/utils/atomic.h>
21 #include <mono/utils/mono-compiler.h>
22 #include <mono/utils/mono-logger-internals.h>
23 #include <mono/utils/mono-membar.h>
24 #include <mono/utils/mono-counters.h>
25 #include <mono/utils/hazard-pointer.h>
26 #include <mono/utils/mono-tls.h>
27 #include <mono/utils/mono-mmap.h>
28 #include <mono/utils/mono-threads.h>
29 #include <mono/metadata/object.h>
30 #include <mono/metadata/object-internals.h>
31 #include <mono/metadata/domain-internals.h>
32 #include <mono/metadata/class-internals.h>
33 #include <mono/metadata/assembly.h>
34 #include <mono/metadata/exception.h>
35 #include <mono/metadata/metadata-internals.h>
36 #include <mono/metadata/gc-internals.h>
37 #include <mono/metadata/appdomain.h>
38 #include <mono/metadata/mono-debug-debugger.h>
39 #include <mono/metadata/mono-config.h>
40 #include <mono/metadata/threads-types.h>
41 #include <mono/metadata/runtime.h>
42 #include <metadata/threads.h>
43 #include <metadata/profiler-private.h>
44 #include <mono/metadata/coree.h>
46 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
48 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
49 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
50 #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)
52 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
53 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
55 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
56 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
58 #define JIT_INFO_TABLE_HAZARD_INDEX 0
59 #define JIT_INFO_HAZARD_INDEX 1
62 jit_info_table_num_elements (MonoJitInfoTable *table)
67 for (i = 0; i < table->num_chunks; ++i) {
68 MonoJitInfoTableChunk *chunk = table->chunks [i];
69 int chunk_num_elements = chunk->num_elements;
72 for (j = 0; j < chunk_num_elements; ++j) {
73 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
81 static MonoJitInfoTableChunk*
82 jit_info_table_new_chunk (void)
84 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
91 mono_jit_info_table_new (MonoDomain *domain)
93 MonoJitInfoTable *table = (MonoJitInfoTable *)g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
95 table->domain = domain;
96 table->num_chunks = 1;
97 table->chunks [0] = jit_info_table_new_chunk ();
103 mono_jit_info_table_free (MonoJitInfoTable *table)
106 int num_chunks = table->num_chunks;
107 MonoDomain *domain = table->domain;
109 mono_domain_lock (domain);
111 table->domain->num_jit_info_tables--;
112 if (table->domain->num_jit_info_tables <= 1) {
115 for (list = table->domain->jit_info_free_queue; list; list = list->next)
118 g_slist_free (table->domain->jit_info_free_queue);
119 table->domain->jit_info_free_queue = NULL;
122 /* At this point we assume that there are no other threads
123 still accessing the table, so we don't have to worry about
124 hazardous pointers. */
126 for (i = 0; i < num_chunks; ++i) {
127 MonoJitInfoTableChunk *chunk = table->chunks [i];
128 MonoJitInfo *tombstone;
130 if (--chunk->refcount > 0)
133 for (tombstone = chunk->next_tombstone; tombstone; ) {
134 MonoJitInfo *next = tombstone->n.next_tombstone;
142 mono_domain_unlock (domain);
147 /* The jit_info_table is sorted in ascending order by the end
148 * addresses of the compiled methods. The reason why we have to do
149 * this is that once we introduce tombstones, it becomes possible for
150 * code ranges to overlap, and if we sort by code start and insert at
151 * the back of the table, we cannot guarantee that we won't overlook
154 * There are actually two possible ways to do the sorting and
155 * inserting which work with our lock-free mechanism:
157 * 1. Sort by start address and insert at the front. When looking for
158 * an entry, find the last one with a start address lower than the one
159 * you're looking for, then work your way to the front of the table.
161 * 2. Sort by end address and insert at the back. When looking for an
162 * entry, find the first one with an end address higher than the one
163 * you're looking for, then work your way to the end of the table.
165 * We chose the latter out of convenience.
168 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
170 int left = 0, right = table->num_chunks;
172 g_assert (left < right);
175 int pos = (left + right) / 2;
176 MonoJitInfoTableChunk *chunk = table->chunks [pos];
178 if (addr < chunk->last_code_end)
182 } while (left < right);
183 g_assert (left == right);
185 if (left >= table->num_chunks)
186 return table->num_chunks - 1;
191 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
193 int left = 0, right = chunk->num_elements;
195 while (left < right) {
196 int pos = (left + right) / 2;
197 MonoJitInfo *ji = (MonoJitInfo *)get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
198 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
205 g_assert (left == right);
211 jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
216 chunk_pos = jit_info_table_index (table, (gint8*)addr);
217 g_assert (chunk_pos < table->num_chunks);
219 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
221 /* We now have a position that's very close to that of the
222 first element whose end address is higher than the one
223 we're looking for. If we don't have the exact position,
224 then we have a position below that one, so we'll just
225 search upward until we find our element. */
227 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
229 while (pos < chunk->num_elements) {
230 ji = (MonoJitInfo *)get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
234 if (IS_JIT_INFO_TOMBSTONE (ji)) {
235 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
238 if ((gint8*)addr >= (gint8*)ji->code_start
239 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
240 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
244 /* If we find a non-tombstone element which is already
245 beyond what we're looking for, we have to end the
247 if ((gint8*)addr < (gint8*)ji->code_start)
253 } while (chunk_pos < table->num_chunks);
257 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
262 * mono_jit_info_table_find_internal:
264 * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
265 * In this case, only those AOT methods will be found whose jit info is already loaded.
266 * If ALLOW_TRAMPOLINES is TRUE, this can return a MonoJitInfo which represents a trampoline (ji->is_trampoline is true).
267 * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
268 * In this case, the returned MonoJitInfo might not have metadata information, in particular,
269 * mono_jit_info_get_method () could fail.
272 mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot, gboolean allow_trampolines)
274 MonoJitInfoTable *table;
275 MonoJitInfo *ji, *module_ji;
276 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
278 ++mono_stats.jit_info_table_lookup_count;
280 /* First we have to get the domain's jit_info_table. This is
281 complicated by the fact that a writer might substitute a
282 new table and free the old one. What the writer guarantees
283 us is that it looks at the hazard pointers after it has
284 changed the jit_info_table pointer. So, if we guard the
285 table by a hazard pointer and make sure that the pointer is
286 still there after we've made it hazardous, we don't have to
287 worry about the writer freeing the table. */
288 table = (MonoJitInfoTable *)get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
290 ji = jit_info_table_find (table, hp, (gint8*)addr);
292 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
293 if (ji && ji->is_trampoline && !allow_trampolines)
298 /* Maybe its an AOT module */
299 if (try_aot && mono_get_root_domain () && mono_get_root_domain ()->aot_modules) {
300 table = (MonoJitInfoTable *)get_hazardous_pointer ((gpointer volatile*)&mono_get_root_domain ()->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
301 module_ji = jit_info_table_find (table, hp, (gint8*)addr);
303 ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
305 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
308 if (ji && ji->is_trampoline && !allow_trampolines)
315 * mono_jit_info_table_find:
316 * @domain: Domain that you want to look up
317 * @addr: Points to an address with JITed code.
319 * Use this function to obtain a `MonoJitInfo*` object that can be used to get
320 * some statistics. You should provide both the @domain on which you will be
321 * performing the probe, and an address. Since application domains can share code
322 * the same address can be in use by multiple domains at once.
324 * This does not return any results for trampolines.
326 * Returns: NULL if the address does not belong to JITed code (it might be native
327 * code or a trampoline) or a valid pointer to a `MonoJitInfo*`.
330 mono_jit_info_table_find (MonoDomain *domain, char *addr)
332 return mono_jit_info_table_find_internal (domain, addr, TRUE, FALSE);
335 static G_GNUC_UNUSED void
336 jit_info_table_check (MonoJitInfoTable *table)
340 for (i = 0; i < table->num_chunks; ++i) {
341 MonoJitInfoTableChunk *chunk = table->chunks [i];
344 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
345 if (chunk->refcount > 10)
346 printf("warning: chunk refcount is %d\n", chunk->refcount);
347 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
349 for (j = 0; j < chunk->num_elements; ++j) {
350 MonoJitInfo *this_ji = chunk->data [j];
353 g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= chunk->last_code_end);
355 if (j < chunk->num_elements - 1)
356 next = chunk->data [j + 1];
357 else if (i < table->num_chunks - 1) {
360 for (k = i + 1; k < table->num_chunks; ++k)
361 if (table->chunks [k]->num_elements > 0)
364 if (k >= table->num_chunks)
367 g_assert (table->chunks [k]->num_elements > 0);
368 next = table->chunks [k]->data [0];
372 g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= (gint8*)next->code_start + next->code_size);
377 static MonoJitInfoTable*
378 jit_info_table_realloc (MonoJitInfoTable *old)
381 int num_elements = jit_info_table_num_elements (old);
384 int new_chunk, new_element;
385 MonoJitInfoTable *result;
387 /* number of needed places for elements needed */
388 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
389 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
390 if (num_chunks == 0) {
391 g_assert (num_elements == 0);
392 return mono_jit_info_table_new (old->domain);
394 g_assert (num_chunks > 0);
396 result = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
397 result->domain = old->domain;
398 result->num_chunks = num_chunks;
400 for (i = 0; i < num_chunks; ++i)
401 result->chunks [i] = jit_info_table_new_chunk ();
405 for (i = 0; i < old->num_chunks; ++i) {
406 MonoJitInfoTableChunk *chunk = old->chunks [i];
407 int chunk_num_elements = chunk->num_elements;
410 for (j = 0; j < chunk_num_elements; ++j) {
411 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
412 g_assert (new_chunk < num_chunks);
413 result->chunks [new_chunk]->data [new_element] = chunk->data [j];
414 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
415 result->chunks [new_chunk]->num_elements = new_element;
423 if (new_chunk < num_chunks) {
424 g_assert (new_chunk == num_chunks - 1);
425 result->chunks [new_chunk]->num_elements = new_element;
426 g_assert (result->chunks [new_chunk]->num_elements > 0);
429 for (i = 0; i < num_chunks; ++i) {
430 MonoJitInfoTableChunk *chunk = result->chunks [i];
431 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
433 result->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
440 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
442 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
443 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
445 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
447 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
448 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
450 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
451 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
453 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
454 + new1->data [new1->num_elements - 1]->code_size;
455 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
456 + new2->data [new2->num_elements - 1]->code_size;
462 static MonoJitInfoTable*
463 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
465 MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
466 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
469 new_table->domain = table->domain;
470 new_table->num_chunks = table->num_chunks + 1;
473 for (i = 0; i < table->num_chunks; ++i) {
474 if (table->chunks [i] == chunk) {
475 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
478 new_table->chunks [j] = table->chunks [i];
479 ++new_table->chunks [j]->refcount;
484 g_assert (j == new_table->num_chunks);
489 static MonoJitInfoTableChunk*
490 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
492 MonoJitInfoTableChunk *result = jit_info_table_new_chunk ();
496 for (i = 0; i < old->num_elements; ++i) {
497 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
498 result->data [j++] = old->data [i];
501 result->num_elements = j;
502 if (result->num_elements > 0)
503 result->last_code_end = (gint8*)result->data [j - 1]->code_start + result->data [j - 1]->code_size;
505 result->last_code_end = old->last_code_end;
510 static MonoJitInfoTable*
511 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
513 MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
514 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
517 new_table->domain = table->domain;
518 new_table->num_chunks = table->num_chunks;
521 for (i = 0; i < table->num_chunks; ++i) {
522 if (table->chunks [i] == chunk)
523 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
525 new_table->chunks [j] = table->chunks [i];
526 ++new_table->chunks [j]->refcount;
531 g_assert (j == new_table->num_chunks);
536 /* As we add an element to the table the case can arise that the chunk
537 * to which we need to add is already full. In that case we have to
538 * allocate a new table and do something about that chunk. We have
539 * several strategies:
541 * If the number of elements in the table is below the low watermark
542 * or above the high watermark, we reallocate the whole table.
543 * Otherwise we only concern ourselves with the overflowing chunk:
545 * If there are no tombstones in the chunk then we split the chunk in
546 * two, each half full.
548 * If the chunk does contain tombstones, we just make a new copy of
549 * the chunk without the tombstones, which will have room for at least
550 * the one element we have to add.
552 static MonoJitInfoTable*
553 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
555 int num_elements = jit_info_table_num_elements (table);
558 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
559 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
560 //printf ("reallocing table\n");
561 return jit_info_table_realloc (table);
564 /* count the number of non-tombstone elements in the chunk */
566 for (i = 0; i < chunk->num_elements; ++i) {
567 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
571 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
572 //printf ("splitting chunk\n");
573 return jit_info_table_copy_and_split_chunk (table, chunk);
576 //printf ("purifying chunk\n");
577 return jit_info_table_copy_and_purify_chunk (table, chunk);
580 /* We add elements to the table by first making space for them by
581 * shifting the elements at the back to the right, one at a time.
582 * This results in duplicate entries during the process, but during
583 * all the time the table is in a sorted state. Also, when an element
584 * is replaced by another one, the element that replaces it has an end
585 * address that is equal to or lower than that of the replaced
586 * element. That property is necessary to guarantee that when
587 * searching for an element we end up at a position not higher than
588 * the one we're looking for (i.e. we either find the element directly
589 * or we end up to the left of it).
592 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
594 MonoJitInfoTable *table;
595 MonoJitInfoTableChunk *chunk;
603 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
604 g_assert (chunk_pos < table->num_chunks);
605 chunk = table->chunks [chunk_pos];
607 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
608 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
610 /* Debugging code, should be removed. */
611 //jit_info_table_check (new_table);
613 *table_ptr = new_table;
614 mono_memory_barrier ();
615 domain->num_jit_info_tables++;
616 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)mono_jit_info_table_free, HAZARD_FREE_MAY_LOCK, HAZARD_FREE_SAFE_CTX);
622 /* Debugging code, should be removed. */
623 //jit_info_table_check (table);
625 num_elements = chunk->num_elements;
627 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
629 /* First we need to size up the chunk by one, by copying the
630 last item, or inserting the first one, if the table is
632 if (num_elements > 0)
633 chunk->data [num_elements] = chunk->data [num_elements - 1];
635 chunk->data [0] = ji;
636 mono_memory_write_barrier ();
637 chunk->num_elements = ++num_elements;
639 /* Shift the elements up one by one. */
640 for (i = num_elements - 2; i >= pos; --i) {
641 mono_memory_write_barrier ();
642 chunk->data [i + 1] = chunk->data [i];
645 /* Now we have room and can insert the new item. */
646 mono_memory_write_barrier ();
647 chunk->data [pos] = ji;
649 /* Set the high code end address chunk entry. */
650 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
651 + chunk->data [chunk->num_elements - 1]->code_size;
653 /* Debugging code, should be removed. */
654 //jit_info_table_check (table);
658 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
660 g_assert (ji->d.method != NULL);
662 mono_domain_lock (domain);
664 ++mono_stats.jit_info_table_insert_count;
666 jit_info_table_add (domain, &domain->jit_info_table, ji);
668 mono_domain_unlock (domain);
672 mono_jit_info_make_tombstone (MonoJitInfoTableChunk *chunk, MonoJitInfo *ji)
674 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
676 tombstone->code_start = ji->code_start;
677 tombstone->code_size = ji->code_size;
678 tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
679 tombstone->n.next_tombstone = chunk->next_tombstone;
680 chunk->next_tombstone = tombstone;
686 * LOCKING: domain lock
689 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
691 if (domain->num_jit_info_tables <= 1) {
692 /* Can it actually happen that we only have one table
693 but ji is still hazardous? */
694 mono_thread_hazardous_free_or_queue (ji, g_free, HAZARD_FREE_MAY_LOCK, HAZARD_FREE_SAFE_CTX);
696 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
701 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
703 MonoJitInfoTableChunk *chunk;
704 gpointer start = ji->code_start;
707 chunk_pos = jit_info_table_index (table, (gint8 *)start);
708 g_assert (chunk_pos < table->num_chunks);
710 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, (gint8 *)start);
713 chunk = table->chunks [chunk_pos];
715 while (pos < chunk->num_elements) {
716 if (chunk->data [pos] == ji)
719 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
720 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
721 <= (guint8*)ji->code_start + ji->code_size);
728 } while (chunk_pos < table->num_chunks);
731 g_assert (chunk->data [pos] == ji);
733 chunk->data [pos] = mono_jit_info_make_tombstone (chunk, ji);
735 /* Debugging code, should be removed. */
736 //jit_info_table_check (table);
740 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
742 MonoJitInfoTable *table;
744 mono_domain_lock (domain);
745 table = domain->jit_info_table;
747 ++mono_stats.jit_info_table_remove_count;
749 jit_info_table_remove (table, ji);
751 mono_jit_info_free_or_queue (domain, ji);
753 mono_domain_unlock (domain);
757 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
760 MonoDomain *domain = mono_get_root_domain ();
763 mono_domain_lock (domain);
766 * We reuse MonoJitInfoTable to store AOT module info,
767 * this gives us async-safe lookup.
769 if (!domain->aot_modules) {
770 domain->num_jit_info_tables ++;
771 domain->aot_modules = mono_jit_info_table_new (domain);
774 ji = g_new0 (MonoJitInfo, 1);
776 ji->code_start = start;
777 ji->code_size = (guint8*)end - (guint8*)start;
778 jit_info_table_add (domain, &domain->aot_modules, ji);
780 mono_domain_unlock (domain);
784 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
786 jit_info_find_in_aot_func = func;
790 mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
792 int size = MONO_SIZEOF_JIT_INFO;
794 size += num_clauses * sizeof (MonoJitExceptionInfo);
795 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
796 size += sizeof (MonoGenericJitInfo);
797 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
798 size += sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
799 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
800 size += sizeof (MonoArchEHJitInfo);
801 if (flags & JIT_INFO_HAS_THUNK_INFO)
802 size += sizeof (MonoThunkJitInfo);
807 mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
808 MonoJitInfoFlags flags, int num_clauses, int num_holes)
810 ji->d.method = method;
811 ji->code_start = code;
812 ji->code_size = code_size;
813 ji->num_clauses = num_clauses;
814 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
815 ji->has_generic_jit_info = 1;
816 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
817 ji->has_try_block_holes = 1;
818 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
819 ji->has_arch_eh_info = 1;
820 if (flags & JIT_INFO_HAS_THUNK_INFO)
821 ji->has_thunk_info = 1;
825 * mono_jit_info_get_code_start:
826 * @ji: the JIT information handle
828 * Use this function to get the starting address for the method described by
829 * the @ji object. You can use this plus the `mono_jit_info_get_code_size`
830 * to determine the start and end of the native code.
832 * Returns: Starting address with the native code.
835 mono_jit_info_get_code_start (MonoJitInfo* ji)
837 return ji->code_start;
841 * mono_jit_info_get_code_size:
842 * @ji: the JIT information handle
844 * Use this function to get the code size for the method described by
845 * the @ji object. You can use this plus the `mono_jit_info_get_code_start`
846 * to determine the start and end of the native code.
848 * Returns: Starting address with the native code.
851 mono_jit_info_get_code_size (MonoJitInfo* ji)
853 return ji->code_size;
857 * mono_jit_info_get_method:
858 * @ji: the JIT information handle
860 * Use this function to get the `MonoMethod *` that backs
863 * Returns: The MonoMethod that represents the code tracked
867 mono_jit_info_get_method (MonoJitInfo* ji)
869 g_assert (!ji->async);
870 g_assert (!ji->is_trampoline);
875 jit_info_key_extract (gpointer value)
877 MonoJitInfo *info = (MonoJitInfo*)value;
879 return info->d.method;
883 jit_info_next_value (gpointer value)
885 MonoJitInfo *info = (MonoJitInfo*)value;
887 return (gpointer*)&info->n.next_jit_code_hash;
891 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
893 mono_internal_hash_table_init (jit_code_hash,
894 mono_aligned_addr_hash,
895 jit_info_key_extract,
896 jit_info_next_value);
900 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
902 if (ji->has_generic_jit_info)
903 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
909 * mono_jit_info_get_generic_sharing_context:
912 * Returns the jit info's generic sharing context, or NULL if it
915 MonoGenericSharingContext*
916 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
918 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
921 return gi->generic_sharing_context;
927 * mono_jit_info_set_generic_sharing_context:
929 * @gsctx: a generic sharing context
931 * Sets the jit info's generic sharing context. The jit info must
932 * have memory allocated for the context.
935 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
937 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
941 gi->generic_sharing_context = gsctx;
944 MonoTryBlockHoleTableJitInfo*
945 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
947 if (ji->has_try_block_holes) {
948 char *ptr = (char*)&ji->clauses [ji->num_clauses];
949 if (ji->has_generic_jit_info)
950 ptr += sizeof (MonoGenericJitInfo);
951 return (MonoTryBlockHoleTableJitInfo*)ptr;
958 try_block_hole_table_size (MonoJitInfo *ji)
960 MonoTryBlockHoleTableJitInfo *table;
962 table = mono_jit_info_get_try_block_hole_table_info (ji);
964 return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
968 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
970 if (ji->has_arch_eh_info) {
971 char *ptr = (char*)&ji->clauses [ji->num_clauses];
972 if (ji->has_generic_jit_info)
973 ptr += sizeof (MonoGenericJitInfo);
974 if (ji->has_try_block_holes)
975 ptr += try_block_hole_table_size (ji);
976 return (MonoArchEHJitInfo*)ptr;
983 mono_jit_info_get_thunk_info (MonoJitInfo *ji)
985 if (ji->has_thunk_info) {
986 char *ptr = (char*)&ji->clauses [ji->num_clauses];
987 if (ji->has_generic_jit_info)
988 ptr += sizeof (MonoGenericJitInfo);
989 if (ji->has_try_block_holes)
990 ptr += try_block_hole_table_size (ji);
991 if (ji->has_arch_eh_info)
992 ptr += sizeof (MonoArchEHJitInfo);
993 return (MonoThunkJitInfo*)ptr;