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)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
19 #include <mono/metadata/gc-internals.h>
21 #include <mono/utils/atomic.h>
22 #include <mono/utils/mono-compiler.h>
23 #include <mono/utils/mono-logger-internals.h>
24 #include <mono/utils/mono-membar.h>
25 #include <mono/utils/mono-counters.h>
26 #include <mono/utils/hazard-pointer.h>
27 #include <mono/utils/mono-tls.h>
28 #include <mono/utils/mono-mmap.h>
29 #include <mono/utils/mono-threads.h>
30 #include <mono/metadata/object.h>
31 #include <mono/metadata/object-internals.h>
32 #include <mono/metadata/domain-internals.h>
33 #include <mono/metadata/class-internals.h>
34 #include <mono/metadata/assembly.h>
35 #include <mono/metadata/exception.h>
36 #include <mono/metadata/metadata-internals.h>
37 #include <mono/metadata/gc-internals.h>
38 #include <mono/metadata/appdomain.h>
39 #include <mono/metadata/mono-debug-debugger.h>
40 #include <mono/metadata/mono-config.h>
41 #include <mono/metadata/threads-types.h>
42 #include <mono/metadata/runtime.h>
43 #include <metadata/threads.h>
44 #include <metadata/profiler-private.h>
45 #include <mono/metadata/coree.h>
47 static MonoJitInfoFindInAot jit_info_find_in_aot_func
= NULL
;
49 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
50 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
51 #define JIT_INFO_TABLE_FILLED_NUM_ELEMENTS (MONO_JIT_INFO_TABLE_CHUNK_SIZE * JIT_INFO_TABLE_FILL_RATIO_NOM / JIT_INFO_TABLE_FILL_RATIO_DENOM)
53 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
54 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
56 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
57 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
59 #define JIT_INFO_TABLE_HAZARD_INDEX 0
60 #define JIT_INFO_HAZARD_INDEX 1
63 jit_info_table_num_elements (MonoJitInfoTable
*table
)
68 for (i
= 0; i
< table
->num_chunks
; ++i
) {
69 MonoJitInfoTableChunk
*chunk
= table
->chunks
[i
];
70 int chunk_num_elements
= chunk
->num_elements
;
73 for (j
= 0; j
< chunk_num_elements
; ++j
) {
74 if (!IS_JIT_INFO_TOMBSTONE (chunk
->data
[j
]))
82 static MonoJitInfoTableChunk
*
83 jit_info_table_new_chunk (void)
85 MonoJitInfoTableChunk
*chunk
= g_new0 (MonoJitInfoTableChunk
, 1);
92 mono_jit_info_table_new (MonoDomain
*domain
)
94 MonoJitInfoTable
*table
= (MonoJitInfoTable
*)g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE
+ sizeof (MonoJitInfoTableChunk
*));
96 table
->domain
= domain
;
97 table
->num_chunks
= 1;
98 table
->chunks
[0] = jit_info_table_new_chunk ();
104 mono_jit_info_table_free (MonoJitInfoTable
*table
)
107 int num_chunks
= table
->num_chunks
;
108 MonoDomain
*domain
= table
->domain
;
110 mono_domain_lock (domain
);
112 table
->domain
->num_jit_info_tables
--;
113 if (table
->domain
->num_jit_info_tables
<= 1) {
116 for (list
= table
->domain
->jit_info_free_queue
; list
; list
= list
->next
)
119 g_slist_free (table
->domain
->jit_info_free_queue
);
120 table
->domain
->jit_info_free_queue
= NULL
;
123 /* At this point we assume that there are no other threads
124 still accessing the table, so we don't have to worry about
125 hazardous pointers. */
127 for (i
= 0; i
< num_chunks
; ++i
) {
128 MonoJitInfoTableChunk
*chunk
= table
->chunks
[i
];
129 MonoJitInfo
*tombstone
;
131 if (--chunk
->refcount
> 0)
134 for (tombstone
= chunk
->next_tombstone
; tombstone
; ) {
135 MonoJitInfo
*next
= tombstone
->n
.next_tombstone
;
143 mono_domain_unlock (domain
);
148 /* The jit_info_table is sorted in ascending order by the end
149 * addresses of the compiled methods. The reason why we have to do
150 * this is that once we introduce tombstones, it becomes possible for
151 * code ranges to overlap, and if we sort by code start and insert at
152 * the back of the table, we cannot guarantee that we won't overlook
155 * There are actually two possible ways to do the sorting and
156 * inserting which work with our lock-free mechanism:
158 * 1. Sort by start address and insert at the front. When looking for
159 * an entry, find the last one with a start address lower than the one
160 * you're looking for, then work your way to the front of the table.
162 * 2. Sort by end address and insert at the back. When looking for an
163 * entry, find the first one with an end address higher than the one
164 * you're looking for, then work your way to the end of the table.
166 * We chose the latter out of convenience.
169 jit_info_table_index (MonoJitInfoTable
*table
, gint8
*addr
)
171 int left
= 0, right
= table
->num_chunks
;
173 g_assert (left
< right
);
176 int pos
= (left
+ right
) / 2;
177 MonoJitInfoTableChunk
*chunk
= table
->chunks
[pos
];
179 if (addr
< chunk
->last_code_end
)
183 } while (left
< right
);
184 g_assert (left
== right
);
186 if (left
>= table
->num_chunks
)
187 return table
->num_chunks
- 1;
192 jit_info_table_chunk_index (MonoJitInfoTableChunk
*chunk
, MonoThreadHazardPointers
*hp
, gint8
*addr
)
194 int left
= 0, right
= chunk
->num_elements
;
196 while (left
< right
) {
197 int pos
= (left
+ right
) / 2;
198 MonoJitInfo
*ji
= (MonoJitInfo
*)mono_get_hazardous_pointer((gpointer
volatile*)&chunk
->data
[pos
], hp
, JIT_INFO_HAZARD_INDEX
);
199 gint8
*code_end
= (gint8
*)ji
->code_start
+ ji
->code_size
;
206 g_assert (left
== right
);
212 jit_info_table_find (MonoJitInfoTable
*table
, MonoThreadHazardPointers
*hp
, gint8
*addr
)
217 chunk_pos
= jit_info_table_index (table
, (gint8
*)addr
);
218 g_assert (chunk_pos
< table
->num_chunks
);
220 pos
= jit_info_table_chunk_index (table
->chunks
[chunk_pos
], hp
, (gint8
*)addr
);
222 /* We now have a position that's very close to that of the
223 first element whose end address is higher than the one
224 we're looking for. If we don't have the exact position,
225 then we have a position below that one, so we'll just
226 search upward until we find our element. */
228 MonoJitInfoTableChunk
*chunk
= table
->chunks
[chunk_pos
];
230 while (pos
< chunk
->num_elements
) {
231 ji
= (MonoJitInfo
*)mono_get_hazardous_pointer ((gpointer
volatile*)&chunk
->data
[pos
], hp
, JIT_INFO_HAZARD_INDEX
);
235 if (IS_JIT_INFO_TOMBSTONE (ji
)) {
236 mono_hazard_pointer_clear (hp
, JIT_INFO_HAZARD_INDEX
);
239 if ((gint8
*)addr
>= (gint8
*)ji
->code_start
240 && (gint8
*)addr
< (gint8
*)ji
->code_start
+ ji
->code_size
) {
241 mono_hazard_pointer_clear (hp
, JIT_INFO_HAZARD_INDEX
);
245 /* If we find a non-tombstone element which is already
246 beyond what we're looking for, we have to end the
248 if ((gint8
*)addr
< (gint8
*)ji
->code_start
)
254 } while (chunk_pos
< table
->num_chunks
);
258 mono_hazard_pointer_clear (hp
, JIT_INFO_HAZARD_INDEX
);
263 * mono_jit_info_table_find_internal:
265 * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
266 * In this case, only those AOT methods will be found whose jit info is already loaded.
267 * If ALLOW_TRAMPOLINES is TRUE, this can return a MonoJitInfo which represents a trampoline (ji->is_trampoline is true).
268 * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
269 * In this case, the returned MonoJitInfo might not have metadata information, in particular,
270 * mono_jit_info_get_method () could fail.
273 mono_jit_info_table_find_internal (MonoDomain
*domain
, char *addr
, gboolean try_aot
, gboolean allow_trampolines
)
275 MonoJitInfoTable
*table
;
276 MonoJitInfo
*ji
, *module_ji
;
277 MonoThreadHazardPointers
*hp
= mono_hazard_pointer_get ();
279 ++mono_stats
.jit_info_table_lookup_count
;
281 /* First we have to get the domain's jit_info_table. This is
282 complicated by the fact that a writer might substitute a
283 new table and free the old one. What the writer guarantees
284 us is that it looks at the hazard pointers after it has
285 changed the jit_info_table pointer. So, if we guard the
286 table by a hazard pointer and make sure that the pointer is
287 still there after we've made it hazardous, we don't have to
288 worry about the writer freeing the table. */
289 table
= (MonoJitInfoTable
*)mono_get_hazardous_pointer ((gpointer
volatile*)&domain
->jit_info_table
, hp
, JIT_INFO_TABLE_HAZARD_INDEX
);
291 ji
= jit_info_table_find (table
, hp
, (gint8
*)addr
);
293 mono_hazard_pointer_clear (hp
, JIT_INFO_TABLE_HAZARD_INDEX
);
294 if (ji
&& ji
->is_trampoline
&& !allow_trampolines
)
299 /* Maybe its an AOT module */
300 if (try_aot
&& mono_get_root_domain () && mono_get_root_domain ()->aot_modules
) {
301 table
= (MonoJitInfoTable
*)mono_get_hazardous_pointer ((gpointer
volatile*)&mono_get_root_domain ()->aot_modules
, hp
, JIT_INFO_TABLE_HAZARD_INDEX
);
302 module_ji
= jit_info_table_find (table
, hp
, (gint8
*)addr
);
304 ji
= jit_info_find_in_aot_func (domain
, module_ji
->d
.image
, addr
);
306 mono_hazard_pointer_clear (hp
, JIT_INFO_TABLE_HAZARD_INDEX
);
309 if (ji
&& ji
->is_trampoline
&& !allow_trampolines
)
316 * mono_jit_info_table_find:
317 * @domain: Domain that you want to look up
318 * @addr: Points to an address with JITed code.
320 * Use this function to obtain a `MonoJitInfo*` object that can be used to get
321 * some statistics. You should provide both the @domain on which you will be
322 * performing the probe, and an address. Since application domains can share code
323 * the same address can be in use by multiple domains at once.
325 * This does not return any results for trampolines.
327 * Returns: NULL if the address does not belong to JITed code (it might be native
328 * code or a trampoline) or a valid pointer to a `MonoJitInfo*`.
331 mono_jit_info_table_find (MonoDomain
*domain
, char *addr
)
333 return mono_jit_info_table_find_internal (domain
, addr
, TRUE
, FALSE
);
336 static G_GNUC_UNUSED
void
337 jit_info_table_check (MonoJitInfoTable
*table
)
341 for (i
= 0; i
< table
->num_chunks
; ++i
) {
342 MonoJitInfoTableChunk
*chunk
= table
->chunks
[i
];
345 g_assert (chunk
->refcount
> 0 /* && chunk->refcount <= 8 */);
346 if (chunk
->refcount
> 10)
347 printf("warning: chunk refcount is %d\n", chunk
->refcount
);
348 g_assert (chunk
->num_elements
<= MONO_JIT_INFO_TABLE_CHUNK_SIZE
);
350 for (j
= 0; j
< chunk
->num_elements
; ++j
) {
351 MonoJitInfo
*this_ji
= chunk
->data
[j
];
354 g_assert ((gint8
*)this_ji
->code_start
+ this_ji
->code_size
<= chunk
->last_code_end
);
356 if (j
< chunk
->num_elements
- 1)
357 next
= chunk
->data
[j
+ 1];
358 else if (i
< table
->num_chunks
- 1) {
361 for (k
= i
+ 1; k
< table
->num_chunks
; ++k
)
362 if (table
->chunks
[k
]->num_elements
> 0)
365 if (k
>= table
->num_chunks
)
368 g_assert (table
->chunks
[k
]->num_elements
> 0);
369 next
= table
->chunks
[k
]->data
[0];
373 g_assert ((gint8
*)this_ji
->code_start
+ this_ji
->code_size
<= (gint8
*)next
->code_start
+ next
->code_size
);
378 static MonoJitInfoTable
*
379 jit_info_table_realloc (MonoJitInfoTable
*old
)
382 int num_elements
= jit_info_table_num_elements (old
);
385 int new_chunk
, new_element
;
386 MonoJitInfoTable
*result
;
388 /* number of needed places for elements needed */
389 required_size
= (int)((long)num_elements
* JIT_INFO_TABLE_FILL_RATIO_DENOM
/ JIT_INFO_TABLE_FILL_RATIO_NOM
);
390 num_chunks
= (required_size
+ MONO_JIT_INFO_TABLE_CHUNK_SIZE
- 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE
;
391 if (num_chunks
== 0) {
392 g_assert (num_elements
== 0);
393 return mono_jit_info_table_new (old
->domain
);
395 g_assert (num_chunks
> 0);
397 result
= (MonoJitInfoTable
*)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
+ sizeof (MonoJitInfoTableChunk
*) * num_chunks
);
398 result
->domain
= old
->domain
;
399 result
->num_chunks
= num_chunks
;
401 for (i
= 0; i
< num_chunks
; ++i
)
402 result
->chunks
[i
] = jit_info_table_new_chunk ();
406 for (i
= 0; i
< old
->num_chunks
; ++i
) {
407 MonoJitInfoTableChunk
*chunk
= old
->chunks
[i
];
408 int chunk_num_elements
= chunk
->num_elements
;
411 for (j
= 0; j
< chunk_num_elements
; ++j
) {
412 if (!IS_JIT_INFO_TOMBSTONE (chunk
->data
[j
])) {
413 g_assert (new_chunk
< num_chunks
);
414 result
->chunks
[new_chunk
]->data
[new_element
] = chunk
->data
[j
];
415 if (++new_element
>= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS
) {
416 result
->chunks
[new_chunk
]->num_elements
= new_element
;
424 if (new_chunk
< num_chunks
) {
425 g_assert (new_chunk
== num_chunks
- 1);
426 result
->chunks
[new_chunk
]->num_elements
= new_element
;
427 g_assert (result
->chunks
[new_chunk
]->num_elements
> 0);
430 for (i
= 0; i
< num_chunks
; ++i
) {
431 MonoJitInfoTableChunk
*chunk
= result
->chunks
[i
];
432 MonoJitInfo
*ji
= chunk
->data
[chunk
->num_elements
- 1];
434 result
->chunks
[i
]->last_code_end
= (gint8
*)ji
->code_start
+ ji
->code_size
;
441 jit_info_table_split_chunk (MonoJitInfoTableChunk
*chunk
, MonoJitInfoTableChunk
**new1p
, MonoJitInfoTableChunk
**new2p
)
443 MonoJitInfoTableChunk
*new1
= jit_info_table_new_chunk ();
444 MonoJitInfoTableChunk
*new2
= jit_info_table_new_chunk ();
446 g_assert (chunk
->num_elements
== MONO_JIT_INFO_TABLE_CHUNK_SIZE
);
448 new1
->num_elements
= MONO_JIT_INFO_TABLE_CHUNK_SIZE
/ 2;
449 new2
->num_elements
= MONO_JIT_INFO_TABLE_CHUNK_SIZE
- new1
->num_elements
;
451 memcpy ((void*)new1
->data
, (void*)chunk
->data
, sizeof (MonoJitInfo
*) * new1
->num_elements
);
452 memcpy ((void*)new2
->data
, (void*)(chunk
->data
+ new1
->num_elements
), sizeof (MonoJitInfo
*) * new2
->num_elements
);
454 new1
->last_code_end
= (gint8
*)new1
->data
[new1
->num_elements
- 1]->code_start
455 + new1
->data
[new1
->num_elements
- 1]->code_size
;
456 new2
->last_code_end
= (gint8
*)new2
->data
[new2
->num_elements
- 1]->code_start
457 + new2
->data
[new2
->num_elements
- 1]->code_size
;
463 static MonoJitInfoTable
*
464 jit_info_table_copy_and_split_chunk (MonoJitInfoTable
*table
, MonoJitInfoTableChunk
*chunk
)
466 MonoJitInfoTable
*new_table
= (MonoJitInfoTable
*)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
467 + sizeof (MonoJitInfoTableChunk
*) * (table
->num_chunks
+ 1));
470 new_table
->domain
= table
->domain
;
471 new_table
->num_chunks
= table
->num_chunks
+ 1;
474 for (i
= 0; i
< table
->num_chunks
; ++i
) {
475 if (table
->chunks
[i
] == chunk
) {
476 jit_info_table_split_chunk (chunk
, &new_table
->chunks
[j
], &new_table
->chunks
[j
+ 1]);
479 new_table
->chunks
[j
] = table
->chunks
[i
];
480 ++new_table
->chunks
[j
]->refcount
;
485 g_assert (j
== new_table
->num_chunks
);
490 static MonoJitInfoTableChunk
*
491 jit_info_table_purify_chunk (MonoJitInfoTableChunk
*old
)
493 MonoJitInfoTableChunk
*result
= jit_info_table_new_chunk ();
497 for (i
= 0; i
< old
->num_elements
; ++i
) {
498 if (!IS_JIT_INFO_TOMBSTONE (old
->data
[i
]))
499 result
->data
[j
++] = old
->data
[i
];
502 result
->num_elements
= j
;
503 if (result
->num_elements
> 0)
504 result
->last_code_end
= (gint8
*)result
->data
[j
- 1]->code_start
+ result
->data
[j
- 1]->code_size
;
506 result
->last_code_end
= old
->last_code_end
;
511 static MonoJitInfoTable
*
512 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable
*table
, MonoJitInfoTableChunk
*chunk
)
514 MonoJitInfoTable
*new_table
= (MonoJitInfoTable
*)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
515 + sizeof (MonoJitInfoTableChunk
*) * table
->num_chunks
);
518 new_table
->domain
= table
->domain
;
519 new_table
->num_chunks
= table
->num_chunks
;
522 for (i
= 0; i
< table
->num_chunks
; ++i
) {
523 if (table
->chunks
[i
] == chunk
)
524 new_table
->chunks
[j
++] = jit_info_table_purify_chunk (table
->chunks
[i
]);
526 new_table
->chunks
[j
] = table
->chunks
[i
];
527 ++new_table
->chunks
[j
]->refcount
;
532 g_assert (j
== new_table
->num_chunks
);
537 /* As we add an element to the table the case can arise that the chunk
538 * to which we need to add is already full. In that case we have to
539 * allocate a new table and do something about that chunk. We have
540 * several strategies:
542 * If the number of elements in the table is below the low watermark
543 * or above the high watermark, we reallocate the whole table.
544 * Otherwise we only concern ourselves with the overflowing chunk:
546 * If there are no tombstones in the chunk then we split the chunk in
547 * two, each half full.
549 * If the chunk does contain tombstones, we just make a new copy of
550 * the chunk without the tombstones, which will have room for at least
551 * the one element we have to add.
553 static MonoJitInfoTable
*
554 jit_info_table_chunk_overflow (MonoJitInfoTable
*table
, MonoJitInfoTableChunk
*chunk
)
556 int num_elements
= jit_info_table_num_elements (table
);
559 if (num_elements
< JIT_INFO_TABLE_LOW_WATERMARK (table
->num_chunks
* MONO_JIT_INFO_TABLE_CHUNK_SIZE
)
560 || num_elements
> JIT_INFO_TABLE_HIGH_WATERMARK (table
->num_chunks
* MONO_JIT_INFO_TABLE_CHUNK_SIZE
)) {
561 //printf ("reallocing table\n");
562 return jit_info_table_realloc (table
);
565 /* count the number of non-tombstone elements in the chunk */
567 for (i
= 0; i
< chunk
->num_elements
; ++i
) {
568 if (!IS_JIT_INFO_TOMBSTONE (chunk
->data
[i
]))
572 if (num_elements
== MONO_JIT_INFO_TABLE_CHUNK_SIZE
) {
573 //printf ("splitting chunk\n");
574 return jit_info_table_copy_and_split_chunk (table
, chunk
);
577 //printf ("purifying chunk\n");
578 return jit_info_table_copy_and_purify_chunk (table
, chunk
);
581 /* We add elements to the table by first making space for them by
582 * shifting the elements at the back to the right, one at a time.
583 * This results in duplicate entries during the process, but during
584 * all the time the table is in a sorted state. Also, when an element
585 * is replaced by another one, the element that replaces it has an end
586 * address that is equal to or lower than that of the replaced
587 * element. That property is necessary to guarantee that when
588 * searching for an element we end up at a position not higher than
589 * the one we're looking for (i.e. we either find the element directly
590 * or we end up to the left of it).
593 jit_info_table_add (MonoDomain
*domain
, MonoJitInfoTable
*volatile *table_ptr
, MonoJitInfo
*ji
)
595 MonoJitInfoTable
*table
;
596 MonoJitInfoTableChunk
*chunk
;
604 chunk_pos
= jit_info_table_index (table
, (gint8
*)ji
->code_start
+ ji
->code_size
);
605 g_assert (chunk_pos
< table
->num_chunks
);
606 chunk
= table
->chunks
[chunk_pos
];
608 if (chunk
->num_elements
>= MONO_JIT_INFO_TABLE_CHUNK_SIZE
) {
609 MonoJitInfoTable
*new_table
= jit_info_table_chunk_overflow (table
, chunk
);
611 /* Debugging code, should be removed. */
612 //jit_info_table_check (new_table);
614 *table_ptr
= new_table
;
615 mono_memory_barrier ();
616 domain
->num_jit_info_tables
++;
617 mono_thread_hazardous_try_free (table
, (MonoHazardousFreeFunc
)mono_jit_info_table_free
);
623 /* Debugging code, should be removed. */
624 //jit_info_table_check (table);
626 num_elements
= chunk
->num_elements
;
628 pos
= jit_info_table_chunk_index (chunk
, NULL
, (gint8
*)ji
->code_start
+ ji
->code_size
);
630 /* First we need to size up the chunk by one, by copying the
631 last item, or inserting the first one, if the table is
633 if (num_elements
> 0)
634 chunk
->data
[num_elements
] = chunk
->data
[num_elements
- 1];
636 chunk
->data
[0] = ji
;
637 mono_memory_write_barrier ();
638 chunk
->num_elements
= ++num_elements
;
640 /* Shift the elements up one by one. */
641 for (i
= num_elements
- 2; i
>= pos
; --i
) {
642 mono_memory_write_barrier ();
643 chunk
->data
[i
+ 1] = chunk
->data
[i
];
646 /* Now we have room and can insert the new item. */
647 mono_memory_write_barrier ();
648 chunk
->data
[pos
] = ji
;
650 /* Set the high code end address chunk entry. */
651 chunk
->last_code_end
= (gint8
*)chunk
->data
[chunk
->num_elements
- 1]->code_start
652 + chunk
->data
[chunk
->num_elements
- 1]->code_size
;
654 /* Debugging code, should be removed. */
655 //jit_info_table_check (table);
659 mono_jit_info_table_add (MonoDomain
*domain
, MonoJitInfo
*ji
)
661 g_assert (ji
->d
.method
!= NULL
);
663 mono_domain_lock (domain
);
665 ++mono_stats
.jit_info_table_insert_count
;
667 jit_info_table_add (domain
, &domain
->jit_info_table
, ji
);
669 mono_domain_unlock (domain
);
673 mono_jit_info_make_tombstone (MonoJitInfoTableChunk
*chunk
, MonoJitInfo
*ji
)
675 MonoJitInfo
*tombstone
= g_new0 (MonoJitInfo
, 1);
677 tombstone
->code_start
= ji
->code_start
;
678 tombstone
->code_size
= ji
->code_size
;
679 tombstone
->d
.method
= JIT_INFO_TOMBSTONE_MARKER
;
680 tombstone
->n
.next_tombstone
= chunk
->next_tombstone
;
681 chunk
->next_tombstone
= tombstone
;
687 * LOCKING: domain lock
690 mono_jit_info_free_or_queue (MonoDomain
*domain
, MonoJitInfo
*ji
)
692 if (domain
->num_jit_info_tables
<= 1) {
693 /* Can it actually happen that we only have one table
694 but ji is still hazardous? */
695 mono_thread_hazardous_try_free (ji
, g_free
);
697 domain
->jit_info_free_queue
= g_slist_prepend (domain
->jit_info_free_queue
, ji
);
702 jit_info_table_remove (MonoJitInfoTable
*table
, MonoJitInfo
*ji
)
704 MonoJitInfoTableChunk
*chunk
;
705 gpointer start
= ji
->code_start
;
708 chunk_pos
= jit_info_table_index (table
, (gint8
*)start
);
709 g_assert (chunk_pos
< table
->num_chunks
);
711 pos
= jit_info_table_chunk_index (table
->chunks
[chunk_pos
], NULL
, (gint8
*)start
);
714 chunk
= table
->chunks
[chunk_pos
];
716 while (pos
< chunk
->num_elements
) {
717 if (chunk
->data
[pos
] == ji
)
720 g_assert (IS_JIT_INFO_TOMBSTONE (chunk
->data
[pos
]));
721 g_assert ((guint8
*)chunk
->data
[pos
]->code_start
+ chunk
->data
[pos
]->code_size
722 <= (guint8
*)ji
->code_start
+ ji
->code_size
);
729 } while (chunk_pos
< table
->num_chunks
);
732 g_assert (chunk
->data
[pos
] == ji
);
734 chunk
->data
[pos
] = mono_jit_info_make_tombstone (chunk
, ji
);
736 /* Debugging code, should be removed. */
737 //jit_info_table_check (table);
741 mono_jit_info_table_remove (MonoDomain
*domain
, MonoJitInfo
*ji
)
743 MonoJitInfoTable
*table
;
745 mono_domain_lock (domain
);
746 table
= domain
->jit_info_table
;
748 ++mono_stats
.jit_info_table_remove_count
;
750 jit_info_table_remove (table
, ji
);
752 mono_jit_info_free_or_queue (domain
, ji
);
754 mono_domain_unlock (domain
);
758 mono_jit_info_add_aot_module (MonoImage
*image
, gpointer start
, gpointer end
)
761 MonoDomain
*domain
= mono_get_root_domain ();
764 mono_domain_lock (domain
);
767 * We reuse MonoJitInfoTable to store AOT module info,
768 * this gives us async-safe lookup.
770 if (!domain
->aot_modules
) {
771 domain
->num_jit_info_tables
++;
772 domain
->aot_modules
= mono_jit_info_table_new (domain
);
775 ji
= g_new0 (MonoJitInfo
, 1);
777 ji
->code_start
= start
;
778 ji
->code_size
= (guint8
*)end
- (guint8
*)start
;
779 jit_info_table_add (domain
, &domain
->aot_modules
, ji
);
781 mono_domain_unlock (domain
);
785 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func
)
787 jit_info_find_in_aot_func
= func
;
791 mono_jit_info_size (MonoJitInfoFlags flags
, int num_clauses
, int num_holes
)
793 int size
= MONO_SIZEOF_JIT_INFO
;
795 size
+= num_clauses
* sizeof (MonoJitExceptionInfo
);
796 if (flags
& JIT_INFO_HAS_GENERIC_JIT_INFO
)
797 size
+= sizeof (MonoGenericJitInfo
);
798 if (flags
& JIT_INFO_HAS_TRY_BLOCK_HOLES
)
799 size
+= sizeof (MonoTryBlockHoleTableJitInfo
) + num_holes
* sizeof (MonoTryBlockHoleJitInfo
);
800 if (flags
& JIT_INFO_HAS_ARCH_EH_INFO
)
801 size
+= sizeof (MonoArchEHJitInfo
);
802 if (flags
& JIT_INFO_HAS_THUNK_INFO
)
803 size
+= sizeof (MonoThunkJitInfo
);
808 mono_jit_info_init (MonoJitInfo
*ji
, MonoMethod
*method
, guint8
*code
, int code_size
,
809 MonoJitInfoFlags flags
, int num_clauses
, int num_holes
)
811 ji
->d
.method
= method
;
812 ji
->code_start
= code
;
813 ji
->code_size
= code_size
;
814 ji
->num_clauses
= num_clauses
;
815 if (flags
& JIT_INFO_HAS_GENERIC_JIT_INFO
)
816 ji
->has_generic_jit_info
= 1;
817 if (flags
& JIT_INFO_HAS_TRY_BLOCK_HOLES
)
818 ji
->has_try_block_holes
= 1;
819 if (flags
& JIT_INFO_HAS_ARCH_EH_INFO
)
820 ji
->has_arch_eh_info
= 1;
821 if (flags
& JIT_INFO_HAS_THUNK_INFO
)
822 ji
->has_thunk_info
= 1;
826 * mono_jit_info_get_code_start:
827 * @ji: the JIT information handle
829 * Use this function to get the starting address for the method described by
830 * the @ji object. You can use this plus the `mono_jit_info_get_code_size`
831 * to determine the start and end of the native code.
833 * Returns: Starting address with the native code.
836 mono_jit_info_get_code_start (MonoJitInfo
* ji
)
838 return ji
->code_start
;
842 * mono_jit_info_get_code_size:
843 * @ji: the JIT information handle
845 * Use this function to get the code size for the method described by
846 * the @ji object. You can use this plus the `mono_jit_info_get_code_start`
847 * to determine the start and end of the native code.
849 * Returns: Starting address with the native code.
852 mono_jit_info_get_code_size (MonoJitInfo
* ji
)
854 return ji
->code_size
;
858 * mono_jit_info_get_method:
859 * @ji: the JIT information handle
861 * Use this function to get the `MonoMethod *` that backs
864 * Returns: The MonoMethod that represents the code tracked
868 mono_jit_info_get_method (MonoJitInfo
* ji
)
870 g_assert (!ji
->async
);
871 g_assert (!ji
->is_trampoline
);
876 jit_info_key_extract (gpointer value
)
878 MonoJitInfo
*info
= (MonoJitInfo
*)value
;
880 return info
->d
.method
;
884 jit_info_next_value (gpointer value
)
886 MonoJitInfo
*info
= (MonoJitInfo
*)value
;
888 return (gpointer
*)&info
->n
.next_jit_code_hash
;
892 mono_jit_code_hash_init (MonoInternalHashTable
*jit_code_hash
)
894 mono_internal_hash_table_init (jit_code_hash
,
895 mono_aligned_addr_hash
,
896 jit_info_key_extract
,
897 jit_info_next_value
);
901 mono_jit_info_get_generic_jit_info (MonoJitInfo
*ji
)
903 if (ji
->has_generic_jit_info
)
904 return (MonoGenericJitInfo
*)&ji
->clauses
[ji
->num_clauses
];
910 * mono_jit_info_get_generic_sharing_context:
913 * Returns the jit info's generic sharing context, or NULL if it
916 MonoGenericSharingContext
*
917 mono_jit_info_get_generic_sharing_context (MonoJitInfo
*ji
)
919 MonoGenericJitInfo
*gi
= mono_jit_info_get_generic_jit_info (ji
);
922 return gi
->generic_sharing_context
;
928 * mono_jit_info_set_generic_sharing_context:
930 * @gsctx: a generic sharing context
932 * Sets the jit info's generic sharing context. The jit info must
933 * have memory allocated for the context.
936 mono_jit_info_set_generic_sharing_context (MonoJitInfo
*ji
, MonoGenericSharingContext
*gsctx
)
938 MonoGenericJitInfo
*gi
= mono_jit_info_get_generic_jit_info (ji
);
942 gi
->generic_sharing_context
= gsctx
;
945 MonoTryBlockHoleTableJitInfo
*
946 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo
*ji
)
948 if (ji
->has_try_block_holes
) {
949 char *ptr
= (char*)&ji
->clauses
[ji
->num_clauses
];
950 if (ji
->has_generic_jit_info
)
951 ptr
+= sizeof (MonoGenericJitInfo
);
952 return (MonoTryBlockHoleTableJitInfo
*)ptr
;
959 try_block_hole_table_size (MonoJitInfo
*ji
)
961 MonoTryBlockHoleTableJitInfo
*table
;
963 table
= mono_jit_info_get_try_block_hole_table_info (ji
);
965 return sizeof (MonoTryBlockHoleTableJitInfo
) + table
->num_holes
* sizeof (MonoTryBlockHoleJitInfo
);
969 mono_jit_info_get_arch_eh_info (MonoJitInfo
*ji
)
971 if (ji
->has_arch_eh_info
) {
972 char *ptr
= (char*)&ji
->clauses
[ji
->num_clauses
];
973 if (ji
->has_generic_jit_info
)
974 ptr
+= sizeof (MonoGenericJitInfo
);
975 if (ji
->has_try_block_holes
)
976 ptr
+= try_block_hole_table_size (ji
);
977 return (MonoArchEHJitInfo
*)ptr
;
984 mono_jit_info_get_thunk_info (MonoJitInfo
*ji
)
986 if (ji
->has_thunk_info
) {
987 char *ptr
= (char*)&ji
->clauses
[ji
->num_clauses
];
988 if (ji
->has_generic_jit_info
)
989 ptr
+= sizeof (MonoGenericJitInfo
);
990 if (ji
->has_try_block_holes
)
991 ptr
+= try_block_hole_table_size (ji
);
992 if (ji
->has_arch_eh_info
)
993 ptr
+= sizeof (MonoArchEHJitInfo
);
994 return (MonoThunkJitInfo
*)ptr
;