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 (MonoDomain *domain, char *addr)
317 return mono_jit_info_table_find_internal (domain, addr, TRUE, FALSE);
320 static G_GNUC_UNUSED void
321 jit_info_table_check (MonoJitInfoTable *table)
325 for (i = 0; i < table->num_chunks; ++i) {
326 MonoJitInfoTableChunk *chunk = table->chunks [i];
329 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
330 if (chunk->refcount > 10)
331 printf("warning: chunk refcount is %d\n", chunk->refcount);
332 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
334 for (j = 0; j < chunk->num_elements; ++j) {
335 MonoJitInfo *this_ji = chunk->data [j];
338 g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= chunk->last_code_end);
340 if (j < chunk->num_elements - 1)
341 next = chunk->data [j + 1];
342 else if (i < table->num_chunks - 1) {
345 for (k = i + 1; k < table->num_chunks; ++k)
346 if (table->chunks [k]->num_elements > 0)
349 if (k >= table->num_chunks)
352 g_assert (table->chunks [k]->num_elements > 0);
353 next = table->chunks [k]->data [0];
357 g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= (gint8*)next->code_start + next->code_size);
362 static MonoJitInfoTable*
363 jit_info_table_realloc (MonoJitInfoTable *old)
366 int num_elements = jit_info_table_num_elements (old);
369 int new_chunk, new_element;
370 MonoJitInfoTable *result;
372 /* number of needed places for elements needed */
373 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
374 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
375 if (num_chunks == 0) {
376 g_assert (num_elements == 0);
377 return mono_jit_info_table_new (old->domain);
379 g_assert (num_chunks > 0);
381 result = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
382 result->domain = old->domain;
383 result->num_chunks = num_chunks;
385 for (i = 0; i < num_chunks; ++i)
386 result->chunks [i] = jit_info_table_new_chunk ();
390 for (i = 0; i < old->num_chunks; ++i) {
391 MonoJitInfoTableChunk *chunk = old->chunks [i];
392 int chunk_num_elements = chunk->num_elements;
395 for (j = 0; j < chunk_num_elements; ++j) {
396 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
397 g_assert (new_chunk < num_chunks);
398 result->chunks [new_chunk]->data [new_element] = chunk->data [j];
399 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
400 result->chunks [new_chunk]->num_elements = new_element;
408 if (new_chunk < num_chunks) {
409 g_assert (new_chunk == num_chunks - 1);
410 result->chunks [new_chunk]->num_elements = new_element;
411 g_assert (result->chunks [new_chunk]->num_elements > 0);
414 for (i = 0; i < num_chunks; ++i) {
415 MonoJitInfoTableChunk *chunk = result->chunks [i];
416 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
418 result->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
425 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
427 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
428 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
430 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
432 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
433 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
435 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
436 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
438 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
439 + new1->data [new1->num_elements - 1]->code_size;
440 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
441 + new2->data [new2->num_elements - 1]->code_size;
447 static MonoJitInfoTable*
448 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
450 MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
451 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
454 new_table->domain = table->domain;
455 new_table->num_chunks = table->num_chunks + 1;
458 for (i = 0; i < table->num_chunks; ++i) {
459 if (table->chunks [i] == chunk) {
460 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
463 new_table->chunks [j] = table->chunks [i];
464 ++new_table->chunks [j]->refcount;
469 g_assert (j == new_table->num_chunks);
474 static MonoJitInfoTableChunk*
475 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
477 MonoJitInfoTableChunk *result = jit_info_table_new_chunk ();
481 for (i = 0; i < old->num_elements; ++i) {
482 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
483 result->data [j++] = old->data [i];
486 result->num_elements = j;
487 if (result->num_elements > 0)
488 result->last_code_end = (gint8*)result->data [j - 1]->code_start + result->data [j - 1]->code_size;
490 result->last_code_end = old->last_code_end;
495 static MonoJitInfoTable*
496 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
498 MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
499 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
502 new_table->domain = table->domain;
503 new_table->num_chunks = table->num_chunks;
506 for (i = 0; i < table->num_chunks; ++i) {
507 if (table->chunks [i] == chunk)
508 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
510 new_table->chunks [j] = table->chunks [i];
511 ++new_table->chunks [j]->refcount;
516 g_assert (j == new_table->num_chunks);
521 /* As we add an element to the table the case can arise that the chunk
522 * to which we need to add is already full. In that case we have to
523 * allocate a new table and do something about that chunk. We have
524 * several strategies:
526 * If the number of elements in the table is below the low watermark
527 * or above the high watermark, we reallocate the whole table.
528 * Otherwise we only concern ourselves with the overflowing chunk:
530 * If there are no tombstones in the chunk then we split the chunk in
531 * two, each half full.
533 * If the chunk does contain tombstones, we just make a new copy of
534 * the chunk without the tombstones, which will have room for at least
535 * the one element we have to add.
537 static MonoJitInfoTable*
538 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
540 int num_elements = jit_info_table_num_elements (table);
543 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
544 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
545 //printf ("reallocing table\n");
546 return jit_info_table_realloc (table);
549 /* count the number of non-tombstone elements in the chunk */
551 for (i = 0; i < chunk->num_elements; ++i) {
552 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
556 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
557 //printf ("splitting chunk\n");
558 return jit_info_table_copy_and_split_chunk (table, chunk);
561 //printf ("purifying chunk\n");
562 return jit_info_table_copy_and_purify_chunk (table, chunk);
565 /* We add elements to the table by first making space for them by
566 * shifting the elements at the back to the right, one at a time.
567 * This results in duplicate entries during the process, but during
568 * all the time the table is in a sorted state. Also, when an element
569 * is replaced by another one, the element that replaces it has an end
570 * address that is equal to or lower than that of the replaced
571 * element. That property is necessary to guarantee that when
572 * searching for an element we end up at a position not higher than
573 * the one we're looking for (i.e. we either find the element directly
574 * or we end up to the left of it).
577 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
579 MonoJitInfoTable *table;
580 MonoJitInfoTableChunk *chunk;
588 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
589 g_assert (chunk_pos < table->num_chunks);
590 chunk = table->chunks [chunk_pos];
592 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
593 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
595 /* Debugging code, should be removed. */
596 //jit_info_table_check (new_table);
598 *table_ptr = new_table;
599 mono_memory_barrier ();
600 domain->num_jit_info_tables++;
601 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)mono_jit_info_table_free, TRUE, FALSE);
607 /* Debugging code, should be removed. */
608 //jit_info_table_check (table);
610 num_elements = chunk->num_elements;
612 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
614 /* First we need to size up the chunk by one, by copying the
615 last item, or inserting the first one, if the table is
617 if (num_elements > 0)
618 chunk->data [num_elements] = chunk->data [num_elements - 1];
620 chunk->data [0] = ji;
621 mono_memory_write_barrier ();
622 chunk->num_elements = ++num_elements;
624 /* Shift the elements up one by one. */
625 for (i = num_elements - 2; i >= pos; --i) {
626 mono_memory_write_barrier ();
627 chunk->data [i + 1] = chunk->data [i];
630 /* Now we have room and can insert the new item. */
631 mono_memory_write_barrier ();
632 chunk->data [pos] = ji;
634 /* Set the high code end address chunk entry. */
635 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
636 + chunk->data [chunk->num_elements - 1]->code_size;
638 /* Debugging code, should be removed. */
639 //jit_info_table_check (table);
643 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
645 g_assert (ji->d.method != NULL);
647 mono_domain_lock (domain);
649 ++mono_stats.jit_info_table_insert_count;
651 jit_info_table_add (domain, &domain->jit_info_table, ji);
653 mono_domain_unlock (domain);
657 mono_jit_info_make_tombstone (MonoJitInfoTableChunk *chunk, MonoJitInfo *ji)
659 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
661 tombstone->code_start = ji->code_start;
662 tombstone->code_size = ji->code_size;
663 tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
664 tombstone->n.next_tombstone = chunk->next_tombstone;
665 chunk->next_tombstone = tombstone;
671 * LOCKING: domain lock
674 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
676 if (domain->num_jit_info_tables <= 1) {
677 /* Can it actually happen that we only have one table
678 but ji is still hazardous? */
679 mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
681 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
686 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
688 MonoJitInfoTableChunk *chunk;
689 gpointer start = ji->code_start;
692 chunk_pos = jit_info_table_index (table, (gint8 *)start);
693 g_assert (chunk_pos < table->num_chunks);
695 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, (gint8 *)start);
698 chunk = table->chunks [chunk_pos];
700 while (pos < chunk->num_elements) {
701 if (chunk->data [pos] == ji)
704 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
705 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
706 <= (guint8*)ji->code_start + ji->code_size);
713 } while (chunk_pos < table->num_chunks);
716 g_assert (chunk->data [pos] == ji);
718 chunk->data [pos] = mono_jit_info_make_tombstone (chunk, ji);
720 /* Debugging code, should be removed. */
721 //jit_info_table_check (table);
725 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
727 MonoJitInfoTable *table;
729 mono_domain_lock (domain);
730 table = domain->jit_info_table;
732 ++mono_stats.jit_info_table_remove_count;
734 jit_info_table_remove (table, ji);
736 mono_jit_info_free_or_queue (domain, ji);
738 mono_domain_unlock (domain);
742 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
745 MonoDomain *domain = mono_get_root_domain ();
748 mono_domain_lock (domain);
751 * We reuse MonoJitInfoTable to store AOT module info,
752 * this gives us async-safe lookup.
754 if (!domain->aot_modules) {
755 domain->num_jit_info_tables ++;
756 domain->aot_modules = mono_jit_info_table_new (domain);
759 ji = g_new0 (MonoJitInfo, 1);
761 ji->code_start = start;
762 ji->code_size = (guint8*)end - (guint8*)start;
763 jit_info_table_add (domain, &domain->aot_modules, ji);
765 mono_domain_unlock (domain);
769 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
771 jit_info_find_in_aot_func = func;
775 mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
777 int size = MONO_SIZEOF_JIT_INFO;
779 size += num_clauses * sizeof (MonoJitExceptionInfo);
780 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
781 size += sizeof (MonoGenericJitInfo);
782 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
783 size += sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
784 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
785 size += sizeof (MonoArchEHJitInfo);
786 if (flags & JIT_INFO_HAS_THUNK_INFO)
787 size += sizeof (MonoThunkJitInfo);
792 mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
793 MonoJitInfoFlags flags, int num_clauses, int num_holes)
795 ji->d.method = method;
796 ji->code_start = code;
797 ji->code_size = code_size;
798 ji->num_clauses = num_clauses;
799 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
800 ji->has_generic_jit_info = 1;
801 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
802 ji->has_try_block_holes = 1;
803 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
804 ji->has_arch_eh_info = 1;
805 if (flags & JIT_INFO_HAS_THUNK_INFO)
806 ji->has_thunk_info = 1;
810 mono_jit_info_get_code_start (MonoJitInfo* ji)
812 return ji->code_start;
816 mono_jit_info_get_code_size (MonoJitInfo* ji)
818 return ji->code_size;
822 mono_jit_info_get_method (MonoJitInfo* ji)
824 g_assert (!ji->async);
825 g_assert (!ji->is_trampoline);
830 jit_info_key_extract (gpointer value)
832 MonoJitInfo *info = (MonoJitInfo*)value;
834 return info->d.method;
838 jit_info_next_value (gpointer value)
840 MonoJitInfo *info = (MonoJitInfo*)value;
842 return (gpointer*)&info->n.next_jit_code_hash;
846 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
848 mono_internal_hash_table_init (jit_code_hash,
849 mono_aligned_addr_hash,
850 jit_info_key_extract,
851 jit_info_next_value);
855 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
857 if (ji->has_generic_jit_info)
858 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
864 * mono_jit_info_get_generic_sharing_context:
867 * Returns the jit info's generic sharing context, or NULL if it
870 MonoGenericSharingContext*
871 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
873 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
876 return gi->generic_sharing_context;
882 * mono_jit_info_set_generic_sharing_context:
884 * @gsctx: a generic sharing context
886 * Sets the jit info's generic sharing context. The jit info must
887 * have memory allocated for the context.
890 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
892 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
896 gi->generic_sharing_context = gsctx;
899 MonoTryBlockHoleTableJitInfo*
900 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
902 if (ji->has_try_block_holes) {
903 char *ptr = (char*)&ji->clauses [ji->num_clauses];
904 if (ji->has_generic_jit_info)
905 ptr += sizeof (MonoGenericJitInfo);
906 return (MonoTryBlockHoleTableJitInfo*)ptr;
913 try_block_hole_table_size (MonoJitInfo *ji)
915 MonoTryBlockHoleTableJitInfo *table;
917 table = mono_jit_info_get_try_block_hole_table_info (ji);
919 return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
923 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
925 if (ji->has_arch_eh_info) {
926 char *ptr = (char*)&ji->clauses [ji->num_clauses];
927 if (ji->has_generic_jit_info)
928 ptr += sizeof (MonoGenericJitInfo);
929 if (ji->has_try_block_holes)
930 ptr += try_block_hole_table_size (ji);
931 return (MonoArchEHJitInfo*)ptr;
938 mono_jit_info_get_thunk_info (MonoJitInfo *ji)
940 if (ji->has_thunk_info) {
941 char *ptr = (char*)&ji->clauses [ji->num_clauses];
942 if (ji->has_generic_jit_info)
943 ptr += sizeof (MonoGenericJitInfo);
944 if (ji->has_try_block_holes)
945 ptr += try_block_hole_table_size (ji);
946 if (ji->has_arch_eh_info)
947 ptr += sizeof (MonoArchEHJitInfo);
948 return (MonoThunkJitInfo*)ptr;