2f4be6663ff503b84ec0f3f1983d4587fca2d875
[mono.git] / mono / metadata / jit-info.c
1 /*
2  * jit-info.c: MonoJitInfo functionality
3  *
4  * Author:
5  *      Dietmar Maurer (dietmar@ximian.com)
6  *      Patrik Torstensson
7  *
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  */
12
13 #include <config.h>
14 #include <glib.h>
15 #include <string.h>
16 #include <sys/stat.h>
17
18 #include <mono/metadata/gc-internals.h>
19
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>
45
46 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
47
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)
51
52 #define JIT_INFO_TABLE_LOW_WATERMARK(n)         ((n) / 2)
53 #define JIT_INFO_TABLE_HIGH_WATERMARK(n)        ((n) * 5 / 6)
54
55 #define JIT_INFO_TOMBSTONE_MARKER       ((MonoMethod*)NULL)
56 #define IS_JIT_INFO_TOMBSTONE(ji)       ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
57
58 #define JIT_INFO_TABLE_HAZARD_INDEX             0
59 #define JIT_INFO_HAZARD_INDEX                   1
60
61 static int
62 jit_info_table_num_elements (MonoJitInfoTable *table)
63 {
64         int i;
65         int num_elements = 0;
66
67         for (i = 0; i < table->num_chunks; ++i) {
68                 MonoJitInfoTableChunk *chunk = table->chunks [i];
69                 int chunk_num_elements = chunk->num_elements;
70                 int j;
71
72                 for (j = 0; j < chunk_num_elements; ++j) {
73                         if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
74                                 ++num_elements;
75                 }
76         }
77
78         return num_elements;
79 }
80
81 static MonoJitInfoTableChunk*
82 jit_info_table_new_chunk (void)
83 {
84         MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
85         chunk->refcount = 1;
86
87         return chunk;
88 }
89
90 MonoJitInfoTable *
91 mono_jit_info_table_new (MonoDomain *domain)
92 {
93         MonoJitInfoTable *table = (MonoJitInfoTable *)g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
94
95         table->domain = domain;
96         table->num_chunks = 1;
97         table->chunks [0] = jit_info_table_new_chunk ();
98
99         return table;
100 }
101
102 void
103 mono_jit_info_table_free (MonoJitInfoTable *table)
104 {
105         int i;
106         int num_chunks = table->num_chunks;
107         MonoDomain *domain = table->domain;
108
109         mono_domain_lock (domain);
110
111         table->domain->num_jit_info_tables--;
112         if (table->domain->num_jit_info_tables <= 1) {
113                 GSList *list;
114
115                 for (list = table->domain->jit_info_free_queue; list; list = list->next)
116                         g_free (list->data);
117
118                 g_slist_free (table->domain->jit_info_free_queue);
119                 table->domain->jit_info_free_queue = NULL;
120         }
121
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. */
125
126         for (i = 0; i < num_chunks; ++i) {
127                 MonoJitInfoTableChunk *chunk = table->chunks [i];
128                 MonoJitInfo *tombstone;
129
130                 if (--chunk->refcount > 0)
131                         continue;
132
133                 for (tombstone = chunk->next_tombstone; tombstone; ) {
134                         MonoJitInfo *next = tombstone->n.next_tombstone;
135                         g_free (tombstone);
136                         tombstone = next;
137                 }
138
139                 g_free (chunk);
140         }
141
142         mono_domain_unlock (domain);
143
144         g_free (table);
145 }
146
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
152  * an entry.
153  *
154  * There are actually two possible ways to do the sorting and
155  * inserting which work with our lock-free mechanism:
156  *
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.
160  *
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.
164  *
165  * We chose the latter out of convenience.
166  */
167 static int
168 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
169 {
170         int left = 0, right = table->num_chunks;
171
172         g_assert (left < right);
173
174         do {
175                 int pos = (left + right) / 2;
176                 MonoJitInfoTableChunk *chunk = table->chunks [pos];
177
178                 if (addr < chunk->last_code_end)
179                         right = pos;
180                 else
181                         left = pos + 1;
182         } while (left < right);
183         g_assert (left == right);
184
185         if (left >= table->num_chunks)
186                 return table->num_chunks - 1;
187         return left;
188 }
189
190 static int
191 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
192 {
193         int left = 0, right = chunk->num_elements;
194
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;
199
200                 if (addr < code_end)
201                         right = pos;
202                 else
203                         left = pos + 1;
204         }
205         g_assert (left == right);
206
207         return left;
208 }
209
210 static MonoJitInfo*
211 jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
212 {
213         MonoJitInfo *ji;
214         int chunk_pos, pos;
215
216         chunk_pos = jit_info_table_index (table, (gint8*)addr);
217         g_assert (chunk_pos < table->num_chunks);
218
219         pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
220
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. */
226         do {
227                 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
228
229                 while (pos < chunk->num_elements) {
230                         ji = (MonoJitInfo *)get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
231
232                         ++pos;
233
234                         if (IS_JIT_INFO_TOMBSTONE (ji)) {
235                                 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
236                                 continue;
237                         }
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);
241                                 return ji;
242                         }
243
244                         /* If we find a non-tombstone element which is already
245                            beyond what we're looking for, we have to end the
246                            search. */
247                         if ((gint8*)addr < (gint8*)ji->code_start)
248                                 goto not_found;
249                 }
250
251                 ++chunk_pos;
252                 pos = 0;
253         } while (chunk_pos < table->num_chunks);
254
255  not_found:
256         if (hp)
257                 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
258         return NULL;
259 }
260
261 /*
262  * mono_jit_info_table_find_internal:
263  *
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.
270  */
271 MonoJitInfo*
272 mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot, gboolean allow_trampolines)
273 {
274         MonoJitInfoTable *table;
275         MonoJitInfo *ji, *module_ji;
276         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
277
278         ++mono_stats.jit_info_table_lookup_count;
279
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);
289
290         ji = jit_info_table_find (table, hp, (gint8*)addr);
291         if (hp)
292                 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
293         if (ji && ji->is_trampoline && !allow_trampolines)
294                 return NULL;
295         if (ji)
296                 return ji;
297
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);
302                 if (module_ji)
303                         ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
304                 if (hp)
305                         mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
306         }
307
308         if (ji && ji->is_trampoline && !allow_trampolines)
309                 return NULL;
310         
311         return ji;
312 }
313
314 /**
315  * mono_jit_info_table_find:
316  * @domain: Domain that you want to look up
317  * @addr: Points to an address with JITed code.
318  *
319  * Use this function to obtain a `MonoJitInfo*` object that can be used to get
320  * some statistics.   You should provide both the @domain on which you will be
321  * performing the probe, and an address.   Since application domains can share code
322  * the same address can be in use by multiple domains at once.
323  *
324  * This does not return any results for trampolines.
325  *
326  * Returns: NULL if the address does not belong to JITed code (it might be native
327  * code or a trampoline) or a valid pointer to a `MonoJitInfo*`.
328  */
329 MonoJitInfo*
330 mono_jit_info_table_find (MonoDomain *domain, char *addr)
331 {
332         return mono_jit_info_table_find_internal (domain, addr, TRUE, FALSE);
333 }
334
335 static G_GNUC_UNUSED void
336 jit_info_table_check (MonoJitInfoTable *table)
337 {
338         int i;
339
340         for (i = 0; i < table->num_chunks; ++i) {
341                 MonoJitInfoTableChunk *chunk = table->chunks [i];
342                 int j;
343
344                 g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
345                 if (chunk->refcount > 10)
346                         printf("warning: chunk refcount is %d\n", chunk->refcount);
347                 g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
348
349                 for (j = 0; j < chunk->num_elements; ++j) {
350                         MonoJitInfo *this_ji = chunk->data [j];
351                         MonoJitInfo *next;
352
353                         g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= chunk->last_code_end);
354
355                         if (j < chunk->num_elements - 1)
356                                 next = chunk->data [j + 1];
357                         else if (i < table->num_chunks - 1) {
358                                 int k;
359
360                                 for (k = i + 1; k < table->num_chunks; ++k)
361                                         if (table->chunks [k]->num_elements > 0)
362                                                 break;
363
364                                 if (k >= table->num_chunks)
365                                         return;
366
367                                 g_assert (table->chunks [k]->num_elements > 0);
368                                 next = table->chunks [k]->data [0];
369                         } else
370                                 return;
371
372                         g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= (gint8*)next->code_start + next->code_size);
373                 }
374         }
375 }
376
377 static MonoJitInfoTable*
378 jit_info_table_realloc (MonoJitInfoTable *old)
379 {
380         int i;
381         int num_elements = jit_info_table_num_elements (old);
382         int required_size;
383         int num_chunks;
384         int new_chunk, new_element;
385         MonoJitInfoTable *result;
386
387         /* number of needed places for elements needed */
388         required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
389         num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
390         if (num_chunks == 0) {
391                 g_assert (num_elements == 0);
392                 return mono_jit_info_table_new (old->domain);
393         }
394         g_assert (num_chunks > 0);
395
396         result = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
397         result->domain = old->domain;
398         result->num_chunks = num_chunks;
399
400         for (i = 0; i < num_chunks; ++i)
401                 result->chunks [i] = jit_info_table_new_chunk ();
402
403         new_chunk = 0;
404         new_element = 0;
405         for (i = 0; i < old->num_chunks; ++i) {
406                 MonoJitInfoTableChunk *chunk = old->chunks [i];
407                 int chunk_num_elements = chunk->num_elements;
408                 int j;
409
410                 for (j = 0; j < chunk_num_elements; ++j) {
411                         if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
412                                 g_assert (new_chunk < num_chunks);
413                                 result->chunks [new_chunk]->data [new_element] = chunk->data [j];
414                                 if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
415                                         result->chunks [new_chunk]->num_elements = new_element;
416                                         ++new_chunk;
417                                         new_element = 0;
418                                 }
419                         }
420                 }
421         }
422
423         if (new_chunk < num_chunks) {
424                 g_assert (new_chunk == num_chunks - 1);
425                 result->chunks [new_chunk]->num_elements = new_element;
426                 g_assert (result->chunks [new_chunk]->num_elements > 0);
427         }
428
429         for (i = 0; i < num_chunks; ++i) {
430                 MonoJitInfoTableChunk *chunk = result->chunks [i];
431                 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
432
433                 result->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
434         }
435
436         return result;
437 }
438
439 static void
440 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
441 {
442         MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
443         MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
444
445         g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
446
447         new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
448         new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
449
450         memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
451         memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
452
453         new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
454                 + new1->data [new1->num_elements - 1]->code_size;
455         new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
456                 + new2->data [new2->num_elements - 1]->code_size;
457
458         *new1p = new1;
459         *new2p = new2;
460 }
461
462 static MonoJitInfoTable*
463 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
464 {
465         MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
466                 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
467         int i, j;
468
469         new_table->domain = table->domain;
470         new_table->num_chunks = table->num_chunks + 1;
471
472         j = 0;
473         for (i = 0; i < table->num_chunks; ++i) {
474                 if (table->chunks [i] == chunk) {
475                         jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
476                         j += 2;
477                 } else {
478                         new_table->chunks [j] = table->chunks [i];
479                         ++new_table->chunks [j]->refcount;
480                         ++j;
481                 }
482         }
483
484         g_assert (j == new_table->num_chunks);
485
486         return new_table;
487 }
488
489 static MonoJitInfoTableChunk*
490 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
491 {
492         MonoJitInfoTableChunk *result = jit_info_table_new_chunk ();
493         int i, j;
494
495         j = 0;
496         for (i = 0; i < old->num_elements; ++i) {
497                 if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
498                         result->data [j++] = old->data [i];
499         }
500
501         result->num_elements = j;
502         if (result->num_elements > 0)
503                 result->last_code_end = (gint8*)result->data [j - 1]->code_start + result->data [j - 1]->code_size;
504         else
505                 result->last_code_end = old->last_code_end;
506
507         return result;
508 }
509
510 static MonoJitInfoTable*
511 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
512 {
513         MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
514                 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
515         int i, j;
516
517         new_table->domain = table->domain;
518         new_table->num_chunks = table->num_chunks;
519
520         j = 0;
521         for (i = 0; i < table->num_chunks; ++i) {
522                 if (table->chunks [i] == chunk)
523                         new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
524                 else {
525                         new_table->chunks [j] = table->chunks [i];
526                         ++new_table->chunks [j]->refcount;
527                         ++j;
528                 }
529         }
530
531         g_assert (j == new_table->num_chunks);
532
533         return new_table;
534 }
535
536 /* As we add an element to the table the case can arise that the chunk
537  * to which we need to add is already full.  In that case we have to
538  * allocate a new table and do something about that chunk.  We have
539  * several strategies:
540  *
541  * If the number of elements in the table is below the low watermark
542  * or above the high watermark, we reallocate the whole table.
543  * Otherwise we only concern ourselves with the overflowing chunk:
544  *
545  * If there are no tombstones in the chunk then we split the chunk in
546  * two, each half full.
547  *
548  * If the chunk does contain tombstones, we just make a new copy of
549  * the chunk without the tombstones, which will have room for at least
550  * the one element we have to add.
551  */
552 static MonoJitInfoTable*
553 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
554 {
555         int num_elements = jit_info_table_num_elements (table);
556         int i;
557
558         if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
559                         || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
560                 //printf ("reallocing table\n");
561                 return jit_info_table_realloc (table);
562         }
563
564         /* count the number of non-tombstone elements in the chunk */
565         num_elements = 0;
566         for (i = 0; i < chunk->num_elements; ++i) {
567                 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
568                         ++num_elements;
569         }
570
571         if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
572                 //printf ("splitting chunk\n");
573                 return jit_info_table_copy_and_split_chunk (table, chunk);
574         }
575
576         //printf ("purifying chunk\n");
577         return jit_info_table_copy_and_purify_chunk (table, chunk);
578 }
579
580 /* We add elements to the table by first making space for them by
581  * shifting the elements at the back to the right, one at a time.
582  * This results in duplicate entries during the process, but during
583  * all the time the table is in a sorted state.  Also, when an element
584  * is replaced by another one, the element that replaces it has an end
585  * address that is equal to or lower than that of the replaced
586  * element.  That property is necessary to guarantee that when
587  * searching for an element we end up at a position not higher than
588  * the one we're looking for (i.e. we either find the element directly
589  * or we end up to the left of it).
590  */
591 static void
592 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
593 {
594         MonoJitInfoTable *table;
595         MonoJitInfoTableChunk *chunk;
596         int chunk_pos, pos;
597         int num_elements;
598         int i;
599
600         table = *table_ptr;
601
602  restart:
603         chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
604         g_assert (chunk_pos < table->num_chunks);
605         chunk = table->chunks [chunk_pos];
606
607         if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
608                 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
609
610                 /* Debugging code, should be removed. */
611                 //jit_info_table_check (new_table);
612
613                 *table_ptr = new_table;
614                 mono_memory_barrier ();
615                 domain->num_jit_info_tables++;
616                 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)mono_jit_info_table_free, HAZARD_FREE_MAY_LOCK, HAZARD_FREE_SAFE_CTX);
617                 table = new_table;
618
619                 goto restart;
620         }
621
622         /* Debugging code, should be removed. */
623         //jit_info_table_check (table);
624
625         num_elements = chunk->num_elements;
626
627         pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
628
629         /* First we need to size up the chunk by one, by copying the
630            last item, or inserting the first one, if the table is
631            empty. */
632         if (num_elements > 0)
633                 chunk->data [num_elements] = chunk->data [num_elements - 1];
634         else
635                 chunk->data [0] = ji;
636         mono_memory_write_barrier ();
637         chunk->num_elements = ++num_elements;
638
639         /* Shift the elements up one by one. */
640         for (i = num_elements - 2; i >= pos; --i) {
641                 mono_memory_write_barrier ();
642                 chunk->data [i + 1] = chunk->data [i];
643         }
644
645         /* Now we have room and can insert the new item. */
646         mono_memory_write_barrier ();
647         chunk->data [pos] = ji;
648
649         /* Set the high code end address chunk entry. */
650         chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
651                 + chunk->data [chunk->num_elements - 1]->code_size;
652
653         /* Debugging code, should be removed. */
654         //jit_info_table_check (table);
655 }
656
657 void
658 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
659 {
660         g_assert (ji->d.method != NULL);
661
662         mono_domain_lock (domain);
663
664         ++mono_stats.jit_info_table_insert_count;
665
666         jit_info_table_add (domain, &domain->jit_info_table, ji);
667
668         mono_domain_unlock (domain);
669 }
670
671 static MonoJitInfo*
672 mono_jit_info_make_tombstone (MonoJitInfoTableChunk *chunk, MonoJitInfo *ji)
673 {
674         MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
675
676         tombstone->code_start = ji->code_start;
677         tombstone->code_size = ji->code_size;
678         tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
679         tombstone->n.next_tombstone = chunk->next_tombstone;
680         chunk->next_tombstone = tombstone;
681
682         return tombstone;
683 }
684
685 /*
686  * LOCKING: domain lock
687  */
688 static void
689 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
690 {
691         if (domain->num_jit_info_tables <= 1) {
692                 /* Can it actually happen that we only have one table
693                    but ji is still hazardous? */
694                 mono_thread_hazardous_free_or_queue (ji, g_free, HAZARD_FREE_MAY_LOCK, HAZARD_FREE_SAFE_CTX);
695         } else {
696                 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
697         }
698 }
699
700 static void
701 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
702 {
703         MonoJitInfoTableChunk *chunk;
704         gpointer start = ji->code_start;
705         int chunk_pos, pos;
706
707         chunk_pos = jit_info_table_index (table, (gint8 *)start);
708         g_assert (chunk_pos < table->num_chunks);
709
710         pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, (gint8 *)start);
711
712         do {
713                 chunk = table->chunks [chunk_pos];
714
715                 while (pos < chunk->num_elements) {
716                         if (chunk->data [pos] == ji)
717                                 goto found;
718
719                         g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
720                         g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
721                                 <= (guint8*)ji->code_start + ji->code_size);
722
723                         ++pos;
724                 }
725
726                 ++chunk_pos;
727                 pos = 0;
728         } while (chunk_pos < table->num_chunks);
729
730  found:
731         g_assert (chunk->data [pos] == ji);
732
733         chunk->data [pos] = mono_jit_info_make_tombstone (chunk, ji);
734
735         /* Debugging code, should be removed. */
736         //jit_info_table_check (table);
737 }
738
739 void
740 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
741 {
742         MonoJitInfoTable *table;
743
744         mono_domain_lock (domain);
745         table = domain->jit_info_table;
746
747         ++mono_stats.jit_info_table_remove_count;
748
749         jit_info_table_remove (table, ji);
750
751         mono_jit_info_free_or_queue (domain, ji);
752
753         mono_domain_unlock (domain);
754 }
755
756 void
757 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
758 {
759         MonoJitInfo *ji;
760         MonoDomain *domain = mono_get_root_domain ();
761
762         g_assert (domain);
763         mono_domain_lock (domain);
764
765         /*
766          * We reuse MonoJitInfoTable to store AOT module info,
767          * this gives us async-safe lookup.
768          */
769         if (!domain->aot_modules) {
770                 domain->num_jit_info_tables ++;
771                 domain->aot_modules = mono_jit_info_table_new (domain);
772         }
773
774         ji = g_new0 (MonoJitInfo, 1);
775         ji->d.image = image;
776         ji->code_start = start;
777         ji->code_size = (guint8*)end - (guint8*)start;
778         jit_info_table_add (domain, &domain->aot_modules, ji);
779
780         mono_domain_unlock (domain);
781 }
782
783 void
784 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
785 {
786         jit_info_find_in_aot_func = func;
787 }
788
789 int
790 mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
791 {
792         int size = MONO_SIZEOF_JIT_INFO;
793
794         size += num_clauses * sizeof (MonoJitExceptionInfo);
795         if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
796                 size += sizeof (MonoGenericJitInfo);
797         if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
798                 size += sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
799         if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
800                 size += sizeof (MonoArchEHJitInfo);
801         if (flags & JIT_INFO_HAS_THUNK_INFO)
802                 size += sizeof (MonoThunkJitInfo);
803         return size;
804 }
805
806 void
807 mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
808                                         MonoJitInfoFlags flags, int num_clauses, int num_holes)
809 {
810         ji->d.method = method;
811         ji->code_start = code;
812         ji->code_size = code_size;
813         ji->num_clauses = num_clauses;
814         if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
815                 ji->has_generic_jit_info = 1;
816         if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
817                 ji->has_try_block_holes = 1;
818         if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
819                 ji->has_arch_eh_info = 1;
820         if (flags & JIT_INFO_HAS_THUNK_INFO)
821                 ji->has_thunk_info = 1;
822 }
823
824 /**
825  * mono_jit_info_get_code_start:
826  * @ji: the JIT information handle
827  *
828  * Use this function to get the starting address for the method described by
829  * the @ji object.  You can use this plus the `mono_jit_info_get_code_size`
830  * to determine the start and end of the native code.
831  *
832  * Returns: Starting address with the native code.
833  */
834 gpointer
835 mono_jit_info_get_code_start (MonoJitInfo* ji)
836 {
837         return ji->code_start;
838 }
839
840 /**
841  * mono_jit_info_get_code_size:
842  * @ji: the JIT information handle
843  *
844  * Use this function to get the code size for the method described by
845  * the @ji object.   You can use this plus the `mono_jit_info_get_code_start`
846  * to determine the start and end of the native code.
847  *
848  * Returns: Starting address with the native code.
849  */
850 int
851 mono_jit_info_get_code_size (MonoJitInfo* ji)
852 {
853         return ji->code_size;
854 }
855
856 /**
857  * mono_jit_info_get_method:
858  * @ji: the JIT information handle
859  *
860  * Use this function to get the `MonoMethod *` that backs
861  * the @ji object.
862  *
863  * Returns: The MonoMethod that represents the code tracked
864  * by @ji.
865  */
866 MonoMethod*
867 mono_jit_info_get_method (MonoJitInfo* ji)
868 {
869         g_assert (!ji->async);
870         g_assert (!ji->is_trampoline);
871         return ji->d.method;
872 }
873
874 static gpointer
875 jit_info_key_extract (gpointer value)
876 {
877         MonoJitInfo *info = (MonoJitInfo*)value;
878
879         return info->d.method;
880 }
881
882 static gpointer*
883 jit_info_next_value (gpointer value)
884 {
885         MonoJitInfo *info = (MonoJitInfo*)value;
886
887         return (gpointer*)&info->n.next_jit_code_hash;
888 }
889
890 void
891 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
892 {
893         mono_internal_hash_table_init (jit_code_hash,
894                                        mono_aligned_addr_hash,
895                                        jit_info_key_extract,
896                                        jit_info_next_value);
897 }
898
899 MonoGenericJitInfo*
900 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
901 {
902         if (ji->has_generic_jit_info)
903                 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
904         else
905                 return NULL;
906 }
907
908 /*
909  * mono_jit_info_get_generic_sharing_context:
910  * @ji: a jit info
911  *
912  * Returns the jit info's generic sharing context, or NULL if it
913  * doesn't have one.
914  */
915 MonoGenericSharingContext*
916 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
917 {
918         MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
919
920         if (gi)
921                 return gi->generic_sharing_context;
922         else
923                 return NULL;
924 }
925
926 /*
927  * mono_jit_info_set_generic_sharing_context:
928  * @ji: a jit info
929  * @gsctx: a generic sharing context
930  *
931  * Sets the jit info's generic sharing context.  The jit info must
932  * have memory allocated for the context.
933  */
934 void
935 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
936 {
937         MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
938
939         g_assert (gi);
940
941         gi->generic_sharing_context = gsctx;
942 }
943
944 MonoTryBlockHoleTableJitInfo*
945 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
946 {
947         if (ji->has_try_block_holes) {
948                 char *ptr = (char*)&ji->clauses [ji->num_clauses];
949                 if (ji->has_generic_jit_info)
950                         ptr += sizeof (MonoGenericJitInfo);
951                 return (MonoTryBlockHoleTableJitInfo*)ptr;
952         } else {
953                 return NULL;
954         }
955 }
956
957 static int
958 try_block_hole_table_size (MonoJitInfo *ji)
959 {
960         MonoTryBlockHoleTableJitInfo *table;
961
962         table = mono_jit_info_get_try_block_hole_table_info (ji);
963         g_assert (table);
964         return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
965 }
966
967 MonoArchEHJitInfo*
968 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
969 {
970         if (ji->has_arch_eh_info) {
971                 char *ptr = (char*)&ji->clauses [ji->num_clauses];
972                 if (ji->has_generic_jit_info)
973                         ptr += sizeof (MonoGenericJitInfo);
974                 if (ji->has_try_block_holes)
975                         ptr += try_block_hole_table_size (ji);
976                 return (MonoArchEHJitInfo*)ptr;
977         } else {
978                 return NULL;
979         }
980 }
981
982 MonoThunkJitInfo*
983 mono_jit_info_get_thunk_info (MonoJitInfo *ji)
984 {
985         if (ji->has_thunk_info) {
986                 char *ptr = (char*)&ji->clauses [ji->num_clauses];
987                 if (ji->has_generic_jit_info)
988                         ptr += sizeof (MonoGenericJitInfo);
989                 if (ji->has_try_block_holes)
990                         ptr += try_block_hole_table_size (ji);
991                 if (ji->has_arch_eh_info)
992                         ptr += sizeof (MonoArchEHJitInfo);
993                 return (MonoThunkJitInfo*)ptr;
994         } else {
995                 return NULL;
996         }
997 }