Pass the --clr-memory-model flag on the command line instead of MONO_DEBUG so its...
[mono-project.git] / mono / metadata / jit-info.c
blob2ad7d2c9f4e1c6269d42f39086b84ba262ea26c6
1 /**
2 * \file
3 * MonoJitInfo functionality
5 * Author:
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Patrik Torstensson
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #include <config.h>
16 #include <glib.h>
17 #include <string.h>
18 #include <sys/stat.h>
20 #include <mono/metadata/gc-internals.h>
22 #include <mono/utils/atomic.h>
23 #include <mono/utils/mono-compiler.h>
24 #include <mono/utils/mono-logger-internals.h>
25 #include <mono/utils/mono-membar.h>
26 #include <mono/utils/mono-counters.h>
27 #include <mono/utils/hazard-pointer.h>
28 #include <mono/utils/mono-tls.h>
29 #include <mono/utils/mono-mmap.h>
30 #include <mono/utils/mono-threads.h>
31 #include <mono/utils/unlocked.h>
32 #include <mono/metadata/object.h>
33 #include <mono/metadata/object-internals.h>
34 #include <mono/metadata/domain-internals.h>
35 #include <mono/metadata/class-internals.h>
36 #include <mono/metadata/assembly.h>
37 #include <mono/metadata/exception.h>
38 #include <mono/metadata/metadata-internals.h>
39 #include <mono/metadata/appdomain.h>
40 #include <mono/metadata/debug-internals.h>
41 #include <mono/metadata/mono-config.h>
42 #include <mono/metadata/threads-types.h>
43 #include <mono/metadata/runtime.h>
44 #include <mono/metadata/threads.h>
45 #include <mono/metadata/profiler-private.h>
46 #include <mono/metadata/coree.h>
48 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
50 #define JIT_INFO_TABLE_FILL_RATIO_NOM 3
51 #define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
52 #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)
54 #define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
55 #define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
57 #define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
58 #define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
60 #define JIT_INFO_TABLE_HAZARD_INDEX 0
61 #define JIT_INFO_HAZARD_INDEX 1
63 static int
64 jit_info_table_num_elements (MonoJitInfoTable *table)
66 return table->num_valid;
69 static MonoJitInfoTableChunk*
70 jit_info_table_new_chunk (void)
72 MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
73 chunk->refcount = 1;
75 return chunk;
78 MonoJitInfoTable *
79 mono_jit_info_table_new (MonoDomain *domain)
81 MonoJitInfoTable *table = (MonoJitInfoTable *)g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
83 table->domain = domain;
84 table->num_chunks = 1;
85 table->chunks [0] = jit_info_table_new_chunk ();
86 table->num_valid = 0;
88 return table;
91 static void
92 jit_info_table_free (MonoJitInfoTable *table, gboolean duplicate)
94 int i;
95 int num_chunks = table->num_chunks;
96 MonoDomain *domain = table->domain;
98 mono_domain_lock (domain);
100 if (duplicate) {
101 table->domain->num_jit_info_table_duplicates--;
102 if (!table->domain->num_jit_info_table_duplicates) {
103 GSList *list;
105 for (list = table->domain->jit_info_free_queue; list; list = list->next)
106 g_free (list->data);
108 g_slist_free (table->domain->jit_info_free_queue);
109 table->domain->jit_info_free_queue = NULL;
113 /* At this point we assume that there are no other threads
114 still accessing the table, so we don't have to worry about
115 hazardous pointers. */
117 for (i = 0; i < num_chunks; ++i) {
118 MonoJitInfoTableChunk *chunk = table->chunks [i];
119 MonoJitInfo *tombstone;
121 if (--chunk->refcount > 0)
122 continue;
124 for (tombstone = chunk->next_tombstone; tombstone; ) {
125 MonoJitInfo *next = tombstone->n.next_tombstone;
126 g_free (tombstone);
127 tombstone = next;
130 g_free (chunk);
133 mono_domain_unlock (domain);
135 g_free (table);
138 static void
139 jit_info_table_free_duplicate (MonoJitInfoTable *table)
141 jit_info_table_free (table, TRUE);
144 void
145 mono_jit_info_table_free (MonoJitInfoTable *table)
147 jit_info_table_free (table, FALSE);
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
155 * an entry.
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.
170 static int
171 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
173 int left = 0, right = table->num_chunks;
175 g_assert (left < right);
177 do {
178 int pos = (left + right) / 2;
179 MonoJitInfoTableChunk *chunk = table->chunks [pos];
181 if (addr < chunk->last_code_end)
182 right = pos;
183 else
184 left = pos + 1;
185 } while (left < right);
186 g_assert (left == right);
188 if (left >= table->num_chunks)
189 return table->num_chunks - 1;
190 return left;
193 static int
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 = (MonoJitInfo *)mono_get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
201 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
203 if (addr < code_end)
204 right = pos;
205 else
206 left = pos + 1;
208 g_assert (left == right);
210 return left;
213 static MonoJitInfo*
214 jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
216 MonoJitInfo *ji;
217 int chunk_pos, pos;
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. */
229 do {
230 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
232 while (pos < chunk->num_elements) {
233 ji = (MonoJitInfo *)mono_get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
235 ++pos;
237 if (IS_JIT_INFO_TOMBSTONE (ji)) {
238 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
239 continue;
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);
244 return ji;
247 /* If we find a non-tombstone element which is already
248 beyond what we're looking for, we have to end the
249 search. */
250 if ((gint8*)addr < (gint8*)ji->code_start)
251 goto not_found;
254 ++chunk_pos;
255 pos = 0;
256 } while (chunk_pos < table->num_chunks);
258 not_found:
259 if (hp)
260 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
261 return NULL;
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.
274 MonoJitInfo*
275 mono_jit_info_table_find_internal (MonoDomain *domain, gpointer addr, gboolean try_aot, gboolean allow_trampolines)
277 MonoJitInfoTable *table;
278 MonoJitInfo *ji, *module_ji;
279 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
281 UnlockedIncrement (&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 = (MonoJitInfoTable *)mono_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);
294 if (hp)
295 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
296 if (ji && ji->is_trampoline && !allow_trampolines)
297 return NULL;
298 if (ji)
299 return ji;
301 /* Maybe its an AOT module */
302 if (try_aot && mono_get_root_domain () && mono_get_root_domain ()->aot_modules) {
303 table = (MonoJitInfoTable *)mono_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);
305 if (module_ji)
306 ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
307 if (hp)
308 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
311 if (ji && ji->is_trampoline && !allow_trampolines)
312 return NULL;
314 return ji;
318 * mono_jit_info_table_find:
319 * \param domain Domain that you want to look up
320 * \param addr Points to an address with JITed code.
322 * Use this function to obtain a \c MonoJitInfo* object that can be used to get
323 * some statistics. You should provide both the \p domain on which you will be
324 * performing the probe, and an address. Since application domains can share code
325 * the same address can be in use by multiple domains at once.
327 * This does not return any results for trampolines.
329 * \returns NULL if the address does not belong to JITed code (it might be native
330 * code or a trampoline) or a valid pointer to a \c MonoJitInfo* .
332 MonoJitInfo*
333 mono_jit_info_table_find (MonoDomain *domain, gpointer addr)
335 return mono_jit_info_table_find_internal (domain, addr, TRUE, FALSE);
338 static G_GNUC_UNUSED void
339 jit_info_table_check (MonoJitInfoTable *table)
341 int i;
343 for (i = 0; i < table->num_chunks; ++i) {
344 MonoJitInfoTableChunk *chunk = table->chunks [i];
345 int j;
347 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
348 if (chunk->refcount > 10)
349 printf("warning: chunk refcount is %d\n", chunk->refcount);
350 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
352 for (j = 0; j < chunk->num_elements; ++j) {
353 MonoJitInfo *this_ji = chunk->data [j];
354 MonoJitInfo *next;
356 g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= chunk->last_code_end);
358 if (j < chunk->num_elements - 1)
359 next = chunk->data [j + 1];
360 else if (i < table->num_chunks - 1) {
361 int k;
363 for (k = i + 1; k < table->num_chunks; ++k)
364 if (table->chunks [k]->num_elements > 0)
365 break;
367 if (k >= table->num_chunks)
368 return;
370 g_assert (table->chunks [k]->num_elements > 0);
371 next = table->chunks [k]->data [0];
372 } else
373 return;
375 g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= (gint8*)next->code_start + next->code_size);
380 static MonoJitInfoTable*
381 jit_info_table_realloc (MonoJitInfoTable *old)
383 int i;
384 int num_elements = jit_info_table_num_elements (old);
385 int required_size;
386 int num_chunks;
387 int new_chunk, new_element;
388 MonoJitInfoTable *result;
390 /* number of needed places for elements needed */
391 required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
392 num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
393 if (num_chunks == 0) {
394 g_assert (num_elements == 0);
395 return mono_jit_info_table_new (old->domain);
397 g_assert (num_chunks > 0);
399 result = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
400 result->domain = old->domain;
401 result->num_chunks = num_chunks;
402 result->num_valid = old->num_valid;
404 for (i = 0; i < num_chunks; ++i)
405 result->chunks [i] = jit_info_table_new_chunk ();
407 new_chunk = 0;
408 new_element = 0;
409 for (i = 0; i < old->num_chunks; ++i) {
410 MonoJitInfoTableChunk *chunk = old->chunks [i];
411 int chunk_num_elements = chunk->num_elements;
412 int j;
414 for (j = 0; j < chunk_num_elements; ++j) {
415 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
416 g_assert (new_chunk < num_chunks);
417 result->chunks [new_chunk]->data [new_element] = chunk->data [j];
418 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
419 result->chunks [new_chunk]->num_elements = new_element;
420 ++new_chunk;
421 new_element = 0;
427 if (new_chunk < num_chunks) {
428 g_assert (new_chunk == num_chunks - 1);
429 result->chunks [new_chunk]->num_elements = new_element;
430 g_assert (result->chunks [new_chunk]->num_elements > 0);
433 for (i = 0; i < num_chunks; ++i) {
434 MonoJitInfoTableChunk *chunk = result->chunks [i];
435 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
437 result->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
440 return result;
443 static void
444 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
446 MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
447 MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
449 g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
451 new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
452 new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
454 memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
455 memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
457 new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
458 + new1->data [new1->num_elements - 1]->code_size;
459 new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
460 + new2->data [new2->num_elements - 1]->code_size;
462 *new1p = new1;
463 *new2p = new2;
466 static MonoJitInfoTable*
467 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
469 MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
470 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
471 int i, j;
473 new_table->domain = table->domain;
474 new_table->num_chunks = table->num_chunks + 1;
475 new_table->num_valid = table->num_valid;
477 j = 0;
478 for (i = 0; i < table->num_chunks; ++i) {
479 if (table->chunks [i] == chunk) {
480 jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
481 j += 2;
482 } else {
483 new_table->chunks [j] = table->chunks [i];
484 ++new_table->chunks [j]->refcount;
485 ++j;
489 g_assert (j == new_table->num_chunks);
491 return new_table;
494 static MonoJitInfoTableChunk*
495 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
497 MonoJitInfoTableChunk *result = jit_info_table_new_chunk ();
498 int i, j;
500 j = 0;
501 for (i = 0; i < old->num_elements; ++i) {
502 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
503 result->data [j++] = old->data [i];
506 result->num_elements = j;
507 if (result->num_elements > 0)
508 result->last_code_end = (gint8*)result->data [j - 1]->code_start + result->data [j - 1]->code_size;
509 else
510 result->last_code_end = old->last_code_end;
512 return result;
515 static MonoJitInfoTable*
516 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
518 MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
519 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
520 int i, j;
522 new_table->domain = table->domain;
523 new_table->num_chunks = table->num_chunks;
524 new_table->num_valid = table->num_valid;
526 j = 0;
527 for (i = 0; i < table->num_chunks; ++i) {
528 if (table->chunks [i] == chunk)
529 new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
530 else {
531 new_table->chunks [j] = table->chunks [i];
532 ++new_table->chunks [j]->refcount;
533 ++j;
537 g_assert (j == new_table->num_chunks);
539 return new_table;
542 /* As we add an element to the table the case can arise that the chunk
543 * to which we need to add is already full. In that case we have to
544 * allocate a new table and do something about that chunk. We have
545 * several strategies:
547 * If the number of elements in the table is below the low watermark
548 * or above the high watermark, we reallocate the whole table.
549 * Otherwise we only concern ourselves with the overflowing chunk:
551 * If there are no tombstones in the chunk then we split the chunk in
552 * two, each half full.
554 * If the chunk does contain tombstones, we just make a new copy of
555 * the chunk without the tombstones, which will have room for at least
556 * the one element we have to add.
558 static MonoJitInfoTable*
559 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
561 int num_elements = jit_info_table_num_elements (table);
562 int i;
564 if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
565 || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
566 //printf ("reallocing table\n");
567 return jit_info_table_realloc (table);
570 /* count the number of non-tombstone elements in the chunk */
571 num_elements = 0;
572 for (i = 0; i < chunk->num_elements; ++i) {
573 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
574 ++num_elements;
577 if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
578 //printf ("splitting chunk\n");
579 return jit_info_table_copy_and_split_chunk (table, chunk);
582 //printf ("purifying chunk\n");
583 return jit_info_table_copy_and_purify_chunk (table, chunk);
586 /* We add elements to the table by first making space for them by
587 * shifting the elements at the back to the right, one at a time.
588 * This results in duplicate entries during the process, but during
589 * all the time the table is in a sorted state. Also, when an element
590 * is replaced by another one, the element that replaces it has an end
591 * address that is equal to or lower than that of the replaced
592 * element. That property is necessary to guarantee that when
593 * searching for an element we end up at a position not higher than
594 * the one we're looking for (i.e. we either find the element directly
595 * or we end up to the left of it).
597 static void
598 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
600 MonoJitInfoTable *table;
601 MonoJitInfoTableChunk *chunk;
602 int chunk_pos, pos;
603 int num_elements;
604 int i;
606 table = *table_ptr;
608 restart:
609 chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
610 g_assert (chunk_pos < table->num_chunks);
611 chunk = table->chunks [chunk_pos];
613 if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
614 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
616 /* Debugging code, should be removed. */
617 //jit_info_table_check (new_table);
619 *table_ptr = new_table;
620 mono_memory_barrier ();
621 domain->num_jit_info_table_duplicates++;
622 mono_thread_hazardous_try_free (table, (MonoHazardousFreeFunc)jit_info_table_free_duplicate);
623 table = new_table;
625 goto restart;
628 /* Debugging code, should be removed. */
629 //jit_info_table_check (table);
631 num_elements = chunk->num_elements;
633 pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
635 /* First we need to size up the chunk by one, by copying the
636 last item, or inserting the first one, if the table is
637 empty. */
638 if (num_elements > 0)
639 chunk->data [num_elements] = chunk->data [num_elements - 1];
640 else
641 chunk->data [0] = ji;
642 mono_memory_write_barrier ();
643 chunk->num_elements = ++num_elements;
645 /* Shift the elements up one by one. */
646 for (i = num_elements - 2; i >= pos; --i) {
647 mono_memory_write_barrier ();
648 chunk->data [i + 1] = chunk->data [i];
651 /* Now we have room and can insert the new item. */
652 mono_memory_write_barrier ();
653 chunk->data [pos] = ji;
655 /* Set the high code end address chunk entry. */
656 chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
657 + chunk->data [chunk->num_elements - 1]->code_size;
659 ++table->num_valid;
661 /* Debugging code, should be removed. */
662 //jit_info_table_check (table);
665 void
666 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
668 g_assert (ji->d.method != NULL);
670 mono_domain_lock (domain);
672 UnlockedIncrement (&mono_stats.jit_info_table_insert_count);
674 jit_info_table_add (domain, &domain->jit_info_table, ji);
676 mono_domain_unlock (domain);
679 static MonoJitInfo*
680 mono_jit_info_make_tombstone (MonoJitInfoTableChunk *chunk, MonoJitInfo *ji)
682 MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
684 tombstone->code_start = ji->code_start;
685 tombstone->code_size = ji->code_size;
686 tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
687 tombstone->n.next_tombstone = chunk->next_tombstone;
688 chunk->next_tombstone = tombstone;
690 return tombstone;
694 * LOCKING: domain lock
696 static void
697 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
700 * When we run out of space in a jit info table and we reallocate it, a
701 * ji structure can be temporary present in multiple tables. If the ji
702 * structure is freed while another thread is doing a jit lookup and still
703 * accessing the old table, it might be accessing this jit info (which
704 * would have been removed and freed only from the new table). The hazard
705 * pointer doesn't stop this since the jinfo would have been freed before
706 * we get to set the hazard pointer for ji. Delay the free-ing for when
707 * there are no jit info table duplicates.
709 if (!domain->num_jit_info_table_duplicates)
710 mono_thread_hazardous_try_free (ji, g_free);
711 else
712 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
715 static void
716 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
718 MonoJitInfoTableChunk *chunk;
719 gpointer start = ji->code_start;
720 int chunk_pos, pos;
722 chunk_pos = jit_info_table_index (table, (gint8 *)start);
723 g_assert (chunk_pos < table->num_chunks);
725 pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, (gint8 *)start);
727 do {
728 chunk = table->chunks [chunk_pos];
730 while (pos < chunk->num_elements) {
731 if (chunk->data [pos] == ji)
732 goto found;
734 g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
735 g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
736 <= (guint8*)ji->code_start + ji->code_size);
738 ++pos;
741 ++chunk_pos;
742 pos = 0;
743 } while (chunk_pos < table->num_chunks);
745 found:
746 g_assert (chunk->data [pos] == ji);
748 chunk->data [pos] = mono_jit_info_make_tombstone (chunk, ji);
749 --table->num_valid;
751 /* Debugging code, should be removed. */
752 //jit_info_table_check (table);
755 void
756 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
758 MonoJitInfoTable *table;
760 mono_domain_lock (domain);
761 table = domain->jit_info_table;
763 UnlockedIncrement (&mono_stats.jit_info_table_remove_count);
765 jit_info_table_remove (table, ji);
767 mono_jit_info_free_or_queue (domain, ji);
769 mono_domain_unlock (domain);
772 void
773 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
775 MonoJitInfo *ji;
776 MonoDomain *domain = mono_get_root_domain ();
778 g_assert (domain);
779 mono_domain_lock (domain);
782 * We reuse MonoJitInfoTable to store AOT module info,
783 * this gives us async-safe lookup.
785 if (!domain->aot_modules)
786 domain->aot_modules = mono_jit_info_table_new (domain);
788 ji = g_new0 (MonoJitInfo, 1);
789 ji->d.image = image;
790 ji->code_start = start;
791 ji->code_size = (guint8*)end - (guint8*)start;
792 jit_info_table_add (domain, &domain->aot_modules, ji);
794 mono_domain_unlock (domain);
797 void
798 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
800 jit_info_find_in_aot_func = func;
804 mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
806 int size = MONO_SIZEOF_JIT_INFO;
808 size += num_clauses * sizeof (MonoJitExceptionInfo);
809 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
810 size += sizeof (MonoGenericJitInfo);
811 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
812 size += sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
813 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
814 size += sizeof (MonoArchEHJitInfo);
815 if (flags & JIT_INFO_HAS_THUNK_INFO)
816 size += sizeof (MonoThunkJitInfo);
817 if (flags & JIT_INFO_HAS_UNWIND_INFO)
818 size += sizeof (MonoUnwindJitInfo);
819 return size;
822 void
823 mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
824 MonoJitInfoFlags flags, int num_clauses, int num_holes)
826 ji->d.method = method;
827 ji->code_start = code;
828 ji->code_size = code_size;
829 ji->num_clauses = num_clauses;
830 if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
831 ji->has_generic_jit_info = 1;
832 if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
833 ji->has_try_block_holes = 1;
834 if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
835 ji->has_arch_eh_info = 1;
836 if (flags & JIT_INFO_HAS_THUNK_INFO)
837 ji->has_thunk_info = 1;
838 if (flags & JIT_INFO_HAS_UNWIND_INFO)
839 ji->has_unwind_info = 1;
843 * mono_jit_info_get_code_start:
844 * \param ji the JIT information handle
846 * Use this function to get the starting address for the method described by
847 * the \p ji object. You can use this plus the \c mono_jit_info_get_code_size
848 * to determine the start and end of the native code.
850 * \returns Starting address with the native code.
852 gpointer
853 mono_jit_info_get_code_start (MonoJitInfo* ji)
855 return ji->code_start;
859 * mono_jit_info_get_code_size:
860 * \param ji the JIT information handle
862 * Use this function to get the code size for the method described by
863 * the \p ji object. You can use this plus the \c mono_jit_info_get_code_start
864 * to determine the start and end of the native code.
866 * \returns Starting address with the native code.
869 mono_jit_info_get_code_size (MonoJitInfo* ji)
871 return ji->code_size;
875 * mono_jit_info_get_method:
876 * \param ji the JIT information handle
878 * Use this function to get the \c MonoMethod* that backs
879 * the \p ji object.
881 * \returns The \c MonoMethod that represents the code tracked
882 * by \p ji.
884 MonoMethod*
885 mono_jit_info_get_method (MonoJitInfo* ji)
887 g_assert (!ji->async);
888 g_assert (!ji->is_trampoline);
889 return ji->d.method;
892 static gpointer
893 jit_info_key_extract (gpointer value)
895 MonoJitInfo *info = (MonoJitInfo*)value;
897 return info->d.method;
900 static gpointer*
901 jit_info_next_value (gpointer value)
903 MonoJitInfo *info = (MonoJitInfo*)value;
905 return (gpointer*)&info->n.next_jit_code_hash;
908 void
909 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
911 mono_internal_hash_table_init (jit_code_hash,
912 mono_aligned_addr_hash,
913 jit_info_key_extract,
914 jit_info_next_value);
917 MonoGenericJitInfo*
918 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
920 if (ji->has_generic_jit_info)
921 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
922 else
923 return NULL;
927 * mono_jit_info_get_generic_sharing_context:
928 * @ji: a jit info
930 * Returns the jit info's generic sharing context, or NULL if it
931 * doesn't have one.
933 MonoGenericSharingContext*
934 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
936 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
938 if (gi)
939 return gi->generic_sharing_context;
940 else
941 return NULL;
945 * mono_jit_info_set_generic_sharing_context:
946 * @ji: a jit info
947 * @gsctx: a generic sharing context
949 * Sets the jit info's generic sharing context. The jit info must
950 * have memory allocated for the context.
952 void
953 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
955 MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
957 g_assert (gi);
959 gi->generic_sharing_context = gsctx;
962 MonoTryBlockHoleTableJitInfo*
963 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
965 if (ji->has_try_block_holes) {
966 char *ptr = (char*)&ji->clauses [ji->num_clauses];
967 if (ji->has_generic_jit_info)
968 ptr += sizeof (MonoGenericJitInfo);
969 return (MonoTryBlockHoleTableJitInfo*)ptr;
970 } else {
971 return NULL;
975 static int
976 try_block_hole_table_size (MonoJitInfo *ji)
978 MonoTryBlockHoleTableJitInfo *table;
980 table = mono_jit_info_get_try_block_hole_table_info (ji);
981 g_assert (table);
982 return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
985 MonoArchEHJitInfo*
986 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
988 if (ji->has_arch_eh_info) {
989 char *ptr = (char*)&ji->clauses [ji->num_clauses];
990 if (ji->has_generic_jit_info)
991 ptr += sizeof (MonoGenericJitInfo);
992 if (ji->has_try_block_holes)
993 ptr += try_block_hole_table_size (ji);
994 return (MonoArchEHJitInfo*)ptr;
995 } else {
996 return NULL;
1000 MonoThunkJitInfo*
1001 mono_jit_info_get_thunk_info (MonoJitInfo *ji)
1003 if (ji->has_thunk_info) {
1004 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1005 if (ji->has_generic_jit_info)
1006 ptr += sizeof (MonoGenericJitInfo);
1007 if (ji->has_try_block_holes)
1008 ptr += try_block_hole_table_size (ji);
1009 if (ji->has_arch_eh_info)
1010 ptr += sizeof (MonoArchEHJitInfo);
1011 return (MonoThunkJitInfo*)ptr;
1012 } else {
1013 return NULL;
1017 MonoUnwindJitInfo*
1018 mono_jit_info_get_unwind_info (MonoJitInfo *ji)
1020 if (ji->has_unwind_info) {
1021 char *ptr = (char*)&ji->clauses [ji->num_clauses];
1022 if (ji->has_generic_jit_info)
1023 ptr += sizeof (MonoGenericJitInfo);
1024 if (ji->has_try_block_holes)
1025 ptr += try_block_hole_table_size (ji);
1026 if (ji->has_arch_eh_info)
1027 ptr += sizeof (MonoArchEHJitInfo);
1028 if (ji->has_thunk_info)
1029 ptr += sizeof (MonoThunkJitInfo);
1030 return (MonoUnwindJitInfo*)ptr;
1031 } else {
1032 return NULL;