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 * If ALLOW_TRAMPOLINES is TRUE, this can return a MonoJitInfo which represents a trampoline (ji->is_trampoline is true).
270 * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
271 * In this case, the returned MonoJitInfo might not have metadata information, in particular,
272 * mono_jit_info_get_method () could fail.
275 mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot, gboolean allow_trampolines)
277 MonoJitInfoTable *table;
278 MonoJitInfo *ji, *module_ji;
279 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
281 ++mono_stats.jit_info_table_lookup_count;
283 /* First we have to get the domain's jit_info_table. This is
284 complicated by the fact that a writer might substitute a
285 new table and free the old one. What the writer guarantees
286 us is that it looks at the hazard pointers after it has
287 changed the jit_info_table pointer. So, if we guard the
288 table by a hazard pointer and make sure that the pointer is
289 still there after we've made it hazardous, we don't have to
290 worry about the writer freeing the table. */
291 table = get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
293 ji = jit_info_table_find (table, hp, (gint8*)addr);
295 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
296 if (ji && ji->is_trampoline && !allow_trampolines)
301 /* Maybe its an AOT module */
302 if (try_aot && mono_get_root_domain () && mono_get_root_domain ()->aot_modules) {
303 table = get_hazardous_pointer ((gpointer volatile*)&mono_get_root_domain ()->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
304 module_ji = jit_info_table_find (table, hp, (gint8*)addr);
306 ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
308 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
311 if (ji && ji->is_trampoline && !allow_trampolines)
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 = chunk->data [j];
341 g_assert ((gint8*)this->code_start + this->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->code_start + this->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 *new;
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 new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
385 new->domain = old->domain;
386 new->num_chunks = num_chunks;
388 for (i = 0; i < num_chunks; ++i)
389 new->chunks [i] = jit_info_table_new_chunk ();
393 for (i = 0; i < old->num_chunks; ++i) {
394 MonoJitInfoTableChunk *chunk = old->chunks [i];
395 int chunk_num_elements = chunk->num_elements;
398 for (j = 0; j < chunk_num_elements; ++j) {
399 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
400 g_assert (new_chunk < num_chunks);
401 new->chunks [new_chunk]->data [new_element] = chunk->data [j];
402 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
403 new->chunks [new_chunk]->num_elements = new_element;
411 if (new_chunk < num_chunks) {
412 g_assert (new_chunk == num_chunks - 1);
413 new->chunks [new_chunk]->num_elements = new_element;
414 g_assert (new->chunks [new_chunk]->num_elements > 0);
417 for (i = 0; i < num_chunks; ++i) {
418 MonoJitInfoTableChunk *chunk = new->chunks [i];
419 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
421 new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
428 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
430 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
431 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
433 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
435 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
436 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
438 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
439 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
441 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
442 + new1->data [new1->num_elements - 1]->code_size;
443 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
444 + new2->data [new2->num_elements - 1]->code_size;
450 static MonoJitInfoTable*
451 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
453 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
454 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
457 new_table->domain = table->domain;
458 new_table->num_chunks = table->num_chunks + 1;
461 for (i = 0; i < table->num_chunks; ++i) {
462 if (table->chunks [i] == chunk) {
463 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
466 new_table->chunks [j] = table->chunks [i];
467 ++new_table->chunks [j]->refcount;
472 g_assert (j == new_table->num_chunks);
477 static MonoJitInfoTableChunk*
478 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
480 MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
484 for (i = 0; i < old->num_elements; ++i) {
485 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
486 new->data [j++] = old->data [i];
489 new->num_elements = j;
490 if (new->num_elements > 0)
491 new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
493 new->last_code_end = old->last_code_end;
498 static MonoJitInfoTable*
499 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
501 MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
502 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
505 new_table->domain = table->domain;
506 new_table->num_chunks = table->num_chunks;
509 for (i = 0; i < table->num_chunks; ++i) {
510 if (table->chunks [i] == chunk)
511 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
513 new_table->chunks [j] = table->chunks [i];
514 ++new_table->chunks [j]->refcount;
519 g_assert (j == new_table->num_chunks);
524 /* As we add an element to the table the case can arise that the chunk
525 * to which we need to add is already full. In that case we have to
526 * allocate a new table and do something about that chunk. We have
527 * several strategies:
529 * If the number of elements in the table is below the low watermark
530 * or above the high watermark, we reallocate the whole table.
531 * Otherwise we only concern ourselves with the overflowing chunk:
533 * If there are no tombstones in the chunk then we split the chunk in
534 * two, each half full.
536 * If the chunk does contain tombstones, we just make a new copy of
537 * the chunk without the tombstones, which will have room for at least
538 * the one element we have to add.
540 static MonoJitInfoTable*
541 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
543 int num_elements = jit_info_table_num_elements (table);
546 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
547 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
548 //printf ("reallocing table\n");
549 return jit_info_table_realloc (table);
552 /* count the number of non-tombstone elements in the chunk */
554 for (i = 0; i < chunk->num_elements; ++i) {
555 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
559 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
560 //printf ("splitting chunk\n");
561 return jit_info_table_copy_and_split_chunk (table, chunk);
564 //printf ("purifying chunk\n");
565 return jit_info_table_copy_and_purify_chunk (table, chunk);
568 /* We add elements to the table by first making space for them by
569 * shifting the elements at the back to the right, one at a time.
570 * This results in duplicate entries during the process, but during
571 * all the time the table is in a sorted state. Also, when an element
572 * is replaced by another one, the element that replaces it has an end
573 * address that is equal to or lower than that of the replaced
574 * element. That property is necessary to guarantee that when
575 * searching for an element we end up at a position not higher than
576 * the one we're looking for (i.e. we either find the element directly
577 * or we end up to the left of it).
580 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
582 MonoJitInfoTable *table;
583 MonoJitInfoTableChunk *chunk;
591 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
592 g_assert (chunk_pos < table->num_chunks);
593 chunk = table->chunks [chunk_pos];
595 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
596 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
598 /* Debugging code, should be removed. */
599 //jit_info_table_check (new_table);
601 *table_ptr = new_table;
602 mono_memory_barrier ();
603 domain->num_jit_info_tables++;
604 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)mono_jit_info_table_free, TRUE, FALSE);
610 /* Debugging code, should be removed. */
611 //jit_info_table_check (table);
613 num_elements = chunk->num_elements;
615 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
617 /* First we need to size up the chunk by one, by copying the
618 last item, or inserting the first one, if the table is
620 if (num_elements > 0)
621 chunk->data [num_elements] = chunk->data [num_elements - 1];
623 chunk->data [0] = ji;
624 mono_memory_write_barrier ();
625 chunk->num_elements = ++num_elements;
627 /* Shift the elements up one by one. */
628 for (i = num_elements - 2; i >= pos; --i) {
629 mono_memory_write_barrier ();
630 chunk->data [i + 1] = chunk->data [i];
633 /* Now we have room and can insert the new item. */
634 mono_memory_write_barrier ();
635 chunk->data [pos] = ji;
637 /* Set the high code end address chunk entry. */
638 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
639 + chunk->data [chunk->num_elements - 1]->code_size;
641 /* Debugging code, should be removed. */
642 //jit_info_table_check (table);
646 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
648 g_assert (ji->d.method != NULL);
650 mono_domain_lock (domain);
652 ++mono_stats.jit_info_table_insert_count;
654 jit_info_table_add (domain, &domain->jit_info_table, ji);
656 mono_domain_unlock (domain);
660 mono_jit_info_make_tombstone (MonoJitInfo *ji)
662 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
664 tombstone->code_start = ji->code_start;
665 tombstone->code_size = ji->code_size;
666 tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
672 * LOCKING: domain lock
675 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
677 if (domain->num_jit_info_tables <= 1) {
678 /* Can it actually happen that we only have one table
679 but ji is still hazardous? */
680 mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
682 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
687 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
689 MonoJitInfoTableChunk *chunk;
690 gpointer start = ji->code_start;
693 chunk_pos = jit_info_table_index (table, start);
694 g_assert (chunk_pos < table->num_chunks);
696 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
699 chunk = table->chunks [chunk_pos];
701 while (pos < chunk->num_elements) {
702 if (chunk->data [pos] == ji)
705 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
706 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
707 <= (guint8*)ji->code_start + ji->code_size);
714 } while (chunk_pos < table->num_chunks);
717 g_assert (chunk->data [pos] == ji);
719 chunk->data [pos] = mono_jit_info_make_tombstone (ji);
721 /* Debugging code, should be removed. */
722 //jit_info_table_check (table);
726 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
728 MonoJitInfoTable *table;
730 mono_domain_lock (domain);
731 table = domain->jit_info_table;
733 ++mono_stats.jit_info_table_remove_count;
735 jit_info_table_remove (table, ji);
737 mono_jit_info_free_or_queue (domain, ji);
739 mono_domain_unlock (domain);
743 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
746 MonoDomain *domain = mono_get_root_domain ();
749 mono_domain_lock (domain);
752 * We reuse MonoJitInfoTable to store AOT module info,
753 * this gives us async-safe lookup.
755 if (!domain->aot_modules) {
756 domain->num_jit_info_tables ++;
757 domain->aot_modules = mono_jit_info_table_new (domain);
760 ji = g_new0 (MonoJitInfo, 1);
762 ji->code_start = start;
763 ji->code_size = (guint8*)end - (guint8*)start;
764 jit_info_table_add (domain, &domain->aot_modules, ji);
766 mono_domain_unlock (domain);
770 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
772 jit_info_find_in_aot_func = func;
776 mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
778 int size = MONO_SIZEOF_JIT_INFO;
780 size += num_clauses * sizeof (MonoJitExceptionInfo);
781 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
782 size += sizeof (MonoGenericJitInfo);
783 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
784 size += sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
785 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
786 size += sizeof (MonoArchEHJitInfo);
787 if (flags & JIT_INFO_HAS_THUNK_INFO)
788 size += sizeof (MonoThunkJitInfo);
793 mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
794 MonoJitInfoFlags flags, int num_clauses, int num_holes)
796 ji->d.method = method;
797 ji->code_start = code;
798 ji->code_size = code_size;
799 ji->num_clauses = num_clauses;
800 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
801 ji->has_generic_jit_info = 1;
802 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
803 ji->has_try_block_holes = 1;
804 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
805 ji->has_arch_eh_info = 1;
806 if (flags & JIT_INFO_HAS_THUNK_INFO)
807 ji->has_thunk_info = 1;
811 mono_jit_info_get_code_start (MonoJitInfo* ji)
813 return ji->code_start;
817 mono_jit_info_get_code_size (MonoJitInfo* ji)
819 return ji->code_size;
823 mono_jit_info_get_method (MonoJitInfo* ji)
825 g_assert (!ji->async);
826 g_assert (!ji->is_trampoline);
831 jit_info_key_extract (gpointer value)
833 MonoJitInfo *info = (MonoJitInfo*)value;
835 return info->d.method;
839 jit_info_next_value (gpointer value)
841 MonoJitInfo *info = (MonoJitInfo*)value;
843 return (gpointer*)&info->next_jit_code_hash;
847 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
849 mono_internal_hash_table_init (jit_code_hash,
850 mono_aligned_addr_hash,
851 jit_info_key_extract,
852 jit_info_next_value);
856 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
858 if (ji->has_generic_jit_info)
859 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
865 * mono_jit_info_get_generic_sharing_context:
868 * Returns the jit info's generic sharing context, or NULL if it
871 MonoGenericSharingContext*
872 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
874 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
877 return gi->generic_sharing_context;
883 * mono_jit_info_set_generic_sharing_context:
885 * @gsctx: a generic sharing context
887 * Sets the jit info's generic sharing context. The jit info must
888 * have memory allocated for the context.
891 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
893 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
897 gi->generic_sharing_context = gsctx;
900 MonoTryBlockHoleTableJitInfo*
901 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
903 if (ji->has_try_block_holes) {
904 char *ptr = (char*)&ji->clauses [ji->num_clauses];
905 if (ji->has_generic_jit_info)
906 ptr += sizeof (MonoGenericJitInfo);
907 return (MonoTryBlockHoleTableJitInfo*)ptr;
914 try_block_hole_table_size (MonoJitInfo *ji)
916 MonoTryBlockHoleTableJitInfo *table;
918 table = mono_jit_info_get_try_block_hole_table_info (ji);
920 return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
924 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
926 if (ji->has_arch_eh_info) {
927 char *ptr = (char*)&ji->clauses [ji->num_clauses];
928 if (ji->has_generic_jit_info)
929 ptr += sizeof (MonoGenericJitInfo);
930 if (ji->has_try_block_holes)
931 ptr += try_block_hole_table_size (ji);
932 return (MonoArchEHJitInfo*)ptr;
939 mono_jit_info_get_thunk_info (MonoJitInfo *ji)
941 if (ji->has_thunk_info) {
942 char *ptr = (char*)&ji->clauses [ji->num_clauses];
943 if (ji->has_generic_jit_info)
944 ptr += sizeof (MonoGenericJitInfo);
945 if (ji->has_try_block_holes)
946 ptr += try_block_hole_table_size (ji);
947 if (ji->has_arch_eh_info)
948 ptr += sizeof (MonoArchEHJitInfo);
949 return (MonoThunkJitInfo*)ptr;