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-internal.h>
20 #include <mono/utils/atomic.h>
21 #include <mono/utils/mono-compiler.h>
22 #include <mono/utils/mono-logger-internal.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-internal.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 = 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];
131 if (--chunk->refcount > 0)
134 num_elements = chunk->num_elements;
135 for (j = 0; j < num_elements; ++j) {
136 MonoJitInfo *ji = chunk->data [j];
138 if (IS_JIT_INFO_TOMBSTONE (ji))
145 mono_domain_unlock (domain);
150 /* The jit_info_table is sorted in ascending order by the end
151 * addresses of the compiled methods. The reason why we have to do
152 * this is that once we introduce tombstones, it becomes possible for
153 * code ranges to overlap, and if we sort by code start and insert at
154 * the back of the table, we cannot guarantee that we won't overlook
157 * There are actually two possible ways to do the sorting and
158 * inserting which work with our lock-free mechanism:
160 * 1. Sort by start address and insert at the front. When looking for
161 * an entry, find the last one with a start address lower than the one
162 * you're looking for, then work your way to the front of the table.
164 * 2. Sort by end address and insert at the back. When looking for an
165 * entry, find the first one with an end address higher than the one
166 * you're looking for, then work your way to the end of the table.
168 * We chose the latter out of convenience.
171 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
173 int left = 0, right = table->num_chunks;
175 g_assert (left < right);
178 int pos = (left + right) / 2;
179 MonoJitInfoTableChunk *chunk = table->chunks [pos];
181 if (addr < chunk->last_code_end)
185 } while (left < right);
186 g_assert (left == right);
188 if (left >= table->num_chunks)
189 return table->num_chunks - 1;
194 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
196 int left = 0, right = chunk->num_elements;
198 while (left < right) {
199 int pos = (left + right) / 2;
200 MonoJitInfo *ji = get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
201 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
208 g_assert (left == right);
214 jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
219 chunk_pos = jit_info_table_index (table, (gint8*)addr);
220 g_assert (chunk_pos < table->num_chunks);
222 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
224 /* We now have a position that's very close to that of the
225 first element whose end address is higher than the one
226 we're looking for. If we don't have the exact position,
227 then we have a position below that one, so we'll just
228 search upward until we find our element. */
230 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
232 while (pos < chunk->num_elements) {
233 ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
237 if (IS_JIT_INFO_TOMBSTONE (ji)) {
238 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
241 if ((gint8*)addr >= (gint8*)ji->code_start
242 && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
243 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
247 /* If we find a non-tombstone element which is already
248 beyond what we're looking for, we have to end the
250 if ((gint8*)addr < (gint8*)ji->code_start)
256 } while (chunk_pos < table->num_chunks);
260 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
265 * mono_jit_info_table_find_internal:
267 * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
268 * In this case, only those AOT methods will be found whose jit info is already loaded.
269 * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
270 * In this case, the returned MonoJitInfo might not have metadata information, in particular,
271 * mono_jit_info_get_method () could fail.
274 mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot)
276 MonoJitInfoTable *table;
277 MonoJitInfo *ji, *module_ji;
278 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
280 ++mono_stats.jit_info_table_lookup_count;
282 /* First we have to get the domain's jit_info_table. This is
283 complicated by the fact that a writer might substitute a
284 new table and free the old one. What the writer guarantees
285 us is that it looks at the hazard pointers after it has
286 changed the jit_info_table pointer. So, if we guard the
287 table by a hazard pointer and make sure that the pointer is
288 still there after we've made it hazardous, we don't have to
289 worry about the writer freeing the table. */
290 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
292 ji = jit_info_table_find (table, hp, (gint8*)addr);
294 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
298 /* Maybe its an AOT module */
299 if (try_aot && mono_get_root_domain () && mono_get_root_domain ()->aot_modules) {
300 table = 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);
312 mono_jit_info_table_find (MonoDomain *domain, char *addr)
314 return mono_jit_info_table_find_internal (domain, addr, TRUE);
317 static G_GNUC_UNUSED void
318 jit_info_table_check (MonoJitInfoTable *table)
322 for (i = 0; i < table->num_chunks; ++i) {
323 MonoJitInfoTableChunk *chunk = table->chunks [i];
326 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
327 if (chunk->refcount > 10)
328 printf("warning: chunk refcount is %d\n", chunk->refcount);
329 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
331 for (j = 0; j < chunk->num_elements; ++j) {
332 MonoJitInfo *this = chunk->data [j];
335 g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
337 if (j < chunk->num_elements - 1)
338 next = chunk->data [j + 1];
339 else if (i < table->num_chunks - 1) {
342 for (k = i + 1; k < table->num_chunks; ++k)
343 if (table->chunks [k]->num_elements > 0)
346 if (k >= table->num_chunks)
349 g_assert (table->chunks [k]->num_elements > 0);
350 next = table->chunks [k]->data [0];
354 g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
359 static MonoJitInfoTable*
360 jit_info_table_realloc (MonoJitInfoTable *old)
363 int num_elements = jit_info_table_num_elements (old);
366 int new_chunk, new_element;
367 MonoJitInfoTable *new;
369 /* number of needed places for elements needed */
370 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
371 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
372 if (num_chunks == 0) {
373 g_assert (num_elements == 0);
374 return mono_jit_info_table_new (old->domain);
376 g_assert (num_chunks > 0);
378 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
379 new->domain = old->domain;
380 new->num_chunks = num_chunks;
382 for (i = 0; i < num_chunks; ++i)
383 new->chunks [i] = jit_info_table_new_chunk ();
387 for (i = 0; i < old->num_chunks; ++i) {
388 MonoJitInfoTableChunk *chunk = old->chunks [i];
389 int chunk_num_elements = chunk->num_elements;
392 for (j = 0; j < chunk_num_elements; ++j) {
393 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
394 g_assert (new_chunk < num_chunks);
395 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
396 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
397 new->chunks [new_chunk]->num_elements = new_element;
405 if (new_chunk < num_chunks) {
406 g_assert (new_chunk == num_chunks - 1);
407 new->chunks [new_chunk]->num_elements = new_element;
408 g_assert (new->chunks [new_chunk]->num_elements > 0);
411 for (i = 0; i < num_chunks; ++i) {
412 MonoJitInfoTableChunk *chunk = new->chunks [i];
413 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
415 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
422 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
424 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
425 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
427 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
429 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
430 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
432 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
433 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
435 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
436 + new1->data [new1->num_elements - 1]->code_size;
437 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
438 + new2->data [new2->num_elements - 1]->code_size;
444 static MonoJitInfoTable*
445 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
447 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
448 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
451 new_table->domain = table->domain;
452 new_table->num_chunks = table->num_chunks + 1;
455 for (i = 0; i < table->num_chunks; ++i) {
456 if (table->chunks [i] == chunk) {
457 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
460 new_table->chunks [j] = table->chunks [i];
461 ++new_table->chunks [j]->refcount;
466 g_assert (j == new_table->num_chunks);
471 static MonoJitInfoTableChunk*
472 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
474 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
478 for (i = 0; i < old->num_elements; ++i) {
479 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
480 new->data [j++] = old->data [i];
483 new->num_elements = j;
484 if (new->num_elements > 0)
485 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
487 new->last_code_end = old->last_code_end;
492 static MonoJitInfoTable*
493 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
495 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
496 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
499 new_table->domain = table->domain;
500 new_table->num_chunks = table->num_chunks;
503 for (i = 0; i < table->num_chunks; ++i) {
504 if (table->chunks [i] == chunk)
505 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
507 new_table->chunks [j] = table->chunks [i];
508 ++new_table->chunks [j]->refcount;
513 g_assert (j == new_table->num_chunks);
518 /* As we add an element to the table the case can arise that the chunk
519 * to which we need to add is already full. In that case we have to
520 * allocate a new table and do something about that chunk. We have
521 * several strategies:
523 * If the number of elements in the table is below the low watermark
524 * or above the high watermark, we reallocate the whole table.
525 * Otherwise we only concern ourselves with the overflowing chunk:
527 * If there are no tombstones in the chunk then we split the chunk in
528 * two, each half full.
530 * If the chunk does contain tombstones, we just make a new copy of
531 * the chunk without the tombstones, which will have room for at least
532 * the one element we have to add.
534 static MonoJitInfoTable*
535 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
537 int num_elements = jit_info_table_num_elements (table);
540 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
541 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
542 //printf ("reallocing table\n");
543 return jit_info_table_realloc (table);
546 /* count the number of non-tombstone elements in the chunk */
548 for (i = 0; i < chunk->num_elements; ++i) {
549 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
553 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
554 //printf ("splitting chunk\n");
555 return jit_info_table_copy_and_split_chunk (table, chunk);
558 //printf ("purifying chunk\n");
559 return jit_info_table_copy_and_purify_chunk (table, chunk);
562 /* We add elements to the table by first making space for them by
563 * shifting the elements at the back to the right, one at a time.
564 * This results in duplicate entries during the process, but during
565 * all the time the table is in a sorted state. Also, when an element
566 * is replaced by another one, the element that replaces it has an end
567 * address that is equal to or lower than that of the replaced
568 * element. That property is necessary to guarantee that when
569 * searching for an element we end up at a position not higher than
570 * the one we're looking for (i.e. we either find the element directly
571 * or we end up to the left of it).
574 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
576 MonoJitInfoTable *table;
577 MonoJitInfoTableChunk *chunk;
585 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
586 g_assert (chunk_pos < table->num_chunks);
587 chunk = table->chunks [chunk_pos];
589 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
590 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
592 /* Debugging code, should be removed. */
593 //jit_info_table_check (new_table);
595 *table_ptr = new_table;
596 mono_memory_barrier ();
597 domain->num_jit_info_tables++;
598 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)mono_jit_info_table_free, TRUE, FALSE);
604 /* Debugging code, should be removed. */
605 //jit_info_table_check (table);
607 num_elements = chunk->num_elements;
609 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
611 /* First we need to size up the chunk by one, by copying the
612 last item, or inserting the first one, if the table is
614 if (num_elements > 0)
615 chunk->data [num_elements] = chunk->data [num_elements - 1];
617 chunk->data [0] = ji;
618 mono_memory_write_barrier ();
619 chunk->num_elements = ++num_elements;
621 /* Shift the elements up one by one. */
622 for (i = num_elements - 2; i >= pos; --i) {
623 mono_memory_write_barrier ();
624 chunk->data [i + 1] = chunk->data [i];
627 /* Now we have room and can insert the new item. */
628 mono_memory_write_barrier ();
629 chunk->data [pos] = ji;
631 /* Set the high code end address chunk entry. */
632 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
633 + chunk->data [chunk->num_elements - 1]->code_size;
635 /* Debugging code, should be removed. */
636 //jit_info_table_check (table);
640 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
642 g_assert (ji->d.method != NULL);
644 mono_domain_lock (domain);
646 ++mono_stats.jit_info_table_insert_count;
648 jit_info_table_add (domain, &domain->jit_info_table, ji);
650 mono_domain_unlock (domain);
654 mono_jit_info_make_tombstone (MonoJitInfo *ji)
656 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
658 tombstone->code_start = ji->code_start;
659 tombstone->code_size = ji->code_size;
660 tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
666 * LOCKING: domain lock
669 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
671 if (domain->num_jit_info_tables <= 1) {
672 /* Can it actually happen that we only have one table
673 but ji is still hazardous? */
674 mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
676 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
681 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
683 MonoJitInfoTableChunk *chunk;
684 gpointer start = ji->code_start;
687 chunk_pos = jit_info_table_index (table, start);
688 g_assert (chunk_pos < table->num_chunks);
690 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
693 chunk = table->chunks [chunk_pos];
695 while (pos < chunk->num_elements) {
696 if (chunk->data [pos] == ji)
699 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
700 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
701 <= (guint8*)ji->code_start + ji->code_size);
708 } while (chunk_pos < table->num_chunks);
711 g_assert (chunk->data [pos] == ji);
713 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
715 /* Debugging code, should be removed. */
716 //jit_info_table_check (table);
720 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
722 MonoJitInfoTable *table;
724 mono_domain_lock (domain);
725 table = domain->jit_info_table;
727 ++mono_stats.jit_info_table_remove_count;
729 jit_info_table_remove (table, ji);
731 mono_jit_info_free_or_queue (domain, ji);
733 mono_domain_unlock (domain);
737 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
740 MonoDomain *domain = mono_get_root_domain ();
743 mono_domain_lock (domain);
746 * We reuse MonoJitInfoTable to store AOT module info,
747 * this gives us async-safe lookup.
749 if (!domain->aot_modules) {
750 domain->num_jit_info_tables ++;
751 domain->aot_modules = mono_jit_info_table_new (domain);
754 ji = g_new0 (MonoJitInfo, 1);
756 ji->code_start = start;
757 ji->code_size = (guint8*)end - (guint8*)start;
758 jit_info_table_add (domain, &domain->aot_modules, ji);
760 mono_domain_unlock (domain);
764 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
766 jit_info_find_in_aot_func = func;
770 mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
772 int size = MONO_SIZEOF_JIT_INFO;
774 size += num_clauses * sizeof (MonoJitExceptionInfo);
775 if (flags & JIT_INFO_HAS_CAS_INFO)
776 size += sizeof (MonoMethodCasInfo);
777 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
778 size += sizeof (MonoGenericJitInfo);
779 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
780 size += sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
781 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
782 size += sizeof (MonoArchEHJitInfo);
787 mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
788 MonoJitInfoFlags flags, int num_clauses, int num_holes)
790 ji->d.method = method;
791 ji->code_start = code;
792 ji->code_size = code_size;
793 ji->num_clauses = num_clauses;
794 if (flags & JIT_INFO_HAS_CAS_INFO)
795 ji->has_cas_info = 1;
796 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
797 ji->has_generic_jit_info = 1;
798 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
799 ji->has_try_block_holes = 1;
800 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
801 ji->has_arch_eh_info = 1;
805 mono_jit_info_get_code_start (MonoJitInfo* ji)
807 return ji->code_start;
811 mono_jit_info_get_code_size (MonoJitInfo* ji)
813 return ji->code_size;
817 mono_jit_info_get_method (MonoJitInfo* ji)
819 g_assert (!ji->async);
824 jit_info_key_extract (gpointer value)
826 MonoJitInfo *info = (MonoJitInfo*)value;
828 return info->d.method;
832 jit_info_next_value (gpointer value)
834 MonoJitInfo *info = (MonoJitInfo*)value;
836 return (gpointer*)&info->next_jit_code_hash;
840 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
842 mono_internal_hash_table_init (jit_code_hash,
843 mono_aligned_addr_hash,
844 jit_info_key_extract,
845 jit_info_next_value);
849 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
851 if (ji->has_generic_jit_info)
852 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
858 * mono_jit_info_get_generic_sharing_context:
861 * Returns the jit info's generic sharing context, or NULL if it
864 MonoGenericSharingContext*
865 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
867 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
870 return gi->generic_sharing_context;
876 * mono_jit_info_set_generic_sharing_context:
878 * @gsctx: a generic sharing context
880 * Sets the jit info's generic sharing context. The jit info must
881 * have memory allocated for the context.
884 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
886 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
890 gi->generic_sharing_context = gsctx;
893 MonoTryBlockHoleTableJitInfo*
894 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
896 if (ji->has_try_block_holes) {
897 char *ptr = (char*)&ji->clauses [ji->num_clauses];
898 if (ji->has_generic_jit_info)
899 ptr += sizeof (MonoGenericJitInfo);
900 return (MonoTryBlockHoleTableJitInfo*)ptr;
907 try_block_hole_table_size (MonoJitInfo *ji)
909 MonoTryBlockHoleTableJitInfo *table;
911 table = mono_jit_info_get_try_block_hole_table_info (ji);
913 return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
917 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
919 if (ji->has_arch_eh_info) {
920 char *ptr = (char*)&ji->clauses [ji->num_clauses];
921 if (ji->has_generic_jit_info)
922 ptr += sizeof (MonoGenericJitInfo);
923 if (ji->has_try_block_holes)
924 ptr += try_block_hole_table_size (ji);
925 return (MonoArchEHJitInfo*)ptr;
932 mono_jit_info_get_cas_info (MonoJitInfo *ji)
934 if (ji->has_cas_info) {
935 char *ptr = (char*)&ji->clauses [ji->num_clauses];
936 if (ji->has_generic_jit_info)
937 ptr += sizeof (MonoGenericJitInfo);
938 if (ji->has_try_block_holes)
939 ptr += try_block_hole_table_size (ji);
940 if (ji->has_arch_eh_info)
941 ptr += sizeof (MonoArchEHJitInfo);
942 return (MonoMethodCasInfo*)ptr;