First set of licensing changes
[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  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12  */
13
14 #include <config.h>
15 #include <glib.h>
16 #include <string.h>
17 #include <sys/stat.h>
18
19 #include <mono/metadata/gc-internals.h>
20
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>
46
47 static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
48
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)
52
53 #define JIT_INFO_TABLE_LOW_WATERMARK(n)         ((n) / 2)
54 #define JIT_INFO_TABLE_HIGH_WATERMARK(n)        ((n) * 5 / 6)
55
56 #define JIT_INFO_TOMBSTONE_MARKER       ((MonoMethod*)NULL)
57 #define IS_JIT_INFO_TOMBSTONE(ji)       ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
58
59 #define JIT_INFO_TABLE_HAZARD_INDEX             0
60 #define JIT_INFO_HAZARD_INDEX                   1
61
62 static int
63 jit_info_table_num_elements (MonoJitInfoTable *table)
64 {
65         int i;
66         int num_elements = 0;
67
68         for (i = 0; i < table->num_chunks; ++i) {
69                 MonoJitInfoTableChunk *chunk = table->chunks [i];
70                 int chunk_num_elements = chunk->num_elements;
71                 int j;
72
73                 for (j = 0; j < chunk_num_elements; ++j) {
74                         if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
75                                 ++num_elements;
76                 }
77         }
78
79         return num_elements;
80 }
81
82 static MonoJitInfoTableChunk*
83 jit_info_table_new_chunk (void)
84 {
85         MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
86         chunk->refcount = 1;
87
88         return chunk;
89 }
90
91 MonoJitInfoTable *
92 mono_jit_info_table_new (MonoDomain *domain)
93 {
94         MonoJitInfoTable *table = (MonoJitInfoTable *)g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
95
96         table->domain = domain;
97         table->num_chunks = 1;
98         table->chunks [0] = jit_info_table_new_chunk ();
99
100         return table;
101 }
102
103 void
104 mono_jit_info_table_free (MonoJitInfoTable *table)
105 {
106         int i;
107         int num_chunks = table->num_chunks;
108         MonoDomain *domain = table->domain;
109
110         mono_domain_lock (domain);
111
112         table->domain->num_jit_info_tables--;
113         if (table->domain->num_jit_info_tables <= 1) {
114                 GSList *list;
115
116                 for (list = table->domain->jit_info_free_queue; list; list = list->next)
117                         g_free (list->data);
118
119                 g_slist_free (table->domain->jit_info_free_queue);
120                 table->domain->jit_info_free_queue = NULL;
121         }
122
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. */
126
127         for (i = 0; i < num_chunks; ++i) {
128                 MonoJitInfoTableChunk *chunk = table->chunks [i];
129                 MonoJitInfo *tombstone;
130
131                 if (--chunk->refcount > 0)
132                         continue;
133
134                 for (tombstone = chunk->next_tombstone; tombstone; ) {
135                         MonoJitInfo *next = tombstone->n.next_tombstone;
136                         g_free (tombstone);
137                         tombstone = next;
138                 }
139
140                 g_free (chunk);
141         }
142
143         mono_domain_unlock (domain);
144
145         g_free (table);
146 }
147
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
153  * an entry.
154  *
155  * There are actually two possible ways to do the sorting and
156  * inserting which work with our lock-free mechanism:
157  *
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.
161  *
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.
165  *
166  * We chose the latter out of convenience.
167  */
168 static int
169 jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
170 {
171         int left = 0, right = table->num_chunks;
172
173         g_assert (left < right);
174
175         do {
176                 int pos = (left + right) / 2;
177                 MonoJitInfoTableChunk *chunk = table->chunks [pos];
178
179                 if (addr < chunk->last_code_end)
180                         right = pos;
181                 else
182                         left = pos + 1;
183         } while (left < right);
184         g_assert (left == right);
185
186         if (left >= table->num_chunks)
187                 return table->num_chunks - 1;
188         return left;
189 }
190
191 static int
192 jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
193 {
194         int left = 0, right = chunk->num_elements;
195
196         while (left < right) {
197                 int pos = (left + right) / 2;
198                 MonoJitInfo *ji = (MonoJitInfo *)get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
199                 gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
200
201                 if (addr < code_end)
202                         right = pos;
203                 else
204                         left = pos + 1;
205         }
206         g_assert (left == right);
207
208         return left;
209 }
210
211 static MonoJitInfo*
212 jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
213 {
214         MonoJitInfo *ji;
215         int chunk_pos, pos;
216
217         chunk_pos = jit_info_table_index (table, (gint8*)addr);
218         g_assert (chunk_pos < table->num_chunks);
219
220         pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
221
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. */
227         do {
228                 MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
229
230                 while (pos < chunk->num_elements) {
231                         ji = (MonoJitInfo *)get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
232
233                         ++pos;
234
235                         if (IS_JIT_INFO_TOMBSTONE (ji)) {
236                                 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
237                                 continue;
238                         }
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);
242                                 return ji;
243                         }
244
245                         /* If we find a non-tombstone element which is already
246                            beyond what we're looking for, we have to end the
247                            search. */
248                         if ((gint8*)addr < (gint8*)ji->code_start)
249                                 goto not_found;
250                 }
251
252                 ++chunk_pos;
253                 pos = 0;
254         } while (chunk_pos < table->num_chunks);
255
256  not_found:
257         if (hp)
258                 mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
259         return NULL;
260 }
261
262 /*
263  * mono_jit_info_table_find_internal:
264  *
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.
271  */
272 MonoJitInfo*
273 mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot, gboolean allow_trampolines)
274 {
275         MonoJitInfoTable *table;
276         MonoJitInfo *ji, *module_ji;
277         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
278
279         ++mono_stats.jit_info_table_lookup_count;
280
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 *)get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
290
291         ji = jit_info_table_find (table, hp, (gint8*)addr);
292         if (hp)
293                 mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
294         if (ji && ji->is_trampoline && !allow_trampolines)
295                 return NULL;
296         if (ji)
297                 return ji;
298
299         /* Maybe its an AOT module */
300         if (try_aot && mono_get_root_domain () && mono_get_root_domain ()->aot_modules) {
301                 table = (MonoJitInfoTable *)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);
303                 if (module_ji)
304                         ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
305                 if (hp)
306                         mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
307         }
308
309         if (ji && ji->is_trampoline && !allow_trampolines)
310                 return NULL;
311         
312         return ji;
313 }
314
315 /**
316  * mono_jit_info_table_find:
317  * @domain: Domain that you want to look up
318  * @addr: Points to an address with JITed code.
319  *
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.
324  *
325  * This does not return any results for trampolines.
326  *
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*`.
329  */
330 MonoJitInfo*
331 mono_jit_info_table_find (MonoDomain *domain, char *addr)
332 {
333         return mono_jit_info_table_find_internal (domain, addr, TRUE, FALSE);
334 }
335
336 static G_GNUC_UNUSED void
337 jit_info_table_check (MonoJitInfoTable *table)
338 {
339         int i;
340
341         for (i = 0; i < table->num_chunks; ++i) {
342                 MonoJitInfoTableChunk *chunk = table->chunks [i];
343                 int j;
344
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);
349
350                 for (j = 0; j < chunk->num_elements; ++j) {
351                         MonoJitInfo *this_ji = chunk->data [j];
352                         MonoJitInfo *next;
353
354                         g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= chunk->last_code_end);
355
356                         if (j < chunk->num_elements - 1)
357                                 next = chunk->data [j + 1];
358                         else if (i < table->num_chunks - 1) {
359                                 int k;
360
361                                 for (k = i + 1; k < table->num_chunks; ++k)
362                                         if (table->chunks [k]->num_elements > 0)
363                                                 break;
364
365                                 if (k >= table->num_chunks)
366                                         return;
367
368                                 g_assert (table->chunks [k]->num_elements > 0);
369                                 next = table->chunks [k]->data [0];
370                         } else
371                                 return;
372
373                         g_assert ((gint8*)this_ji->code_start + this_ji->code_size <= (gint8*)next->code_start + next->code_size);
374                 }
375         }
376 }
377
378 static MonoJitInfoTable*
379 jit_info_table_realloc (MonoJitInfoTable *old)
380 {
381         int i;
382         int num_elements = jit_info_table_num_elements (old);
383         int required_size;
384         int num_chunks;
385         int new_chunk, new_element;
386         MonoJitInfoTable *result;
387
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);
394         }
395         g_assert (num_chunks > 0);
396
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;
400
401         for (i = 0; i < num_chunks; ++i)
402                 result->chunks [i] = jit_info_table_new_chunk ();
403
404         new_chunk = 0;
405         new_element = 0;
406         for (i = 0; i < old->num_chunks; ++i) {
407                 MonoJitInfoTableChunk *chunk = old->chunks [i];
408                 int chunk_num_elements = chunk->num_elements;
409                 int j;
410
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;
417                                         ++new_chunk;
418                                         new_element = 0;
419                                 }
420                         }
421                 }
422         }
423
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);
428         }
429
430         for (i = 0; i < num_chunks; ++i) {
431                 MonoJitInfoTableChunk *chunk = result->chunks [i];
432                 MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
433
434                 result->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
435         }
436
437         return result;
438 }
439
440 static void
441 jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
442 {
443         MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
444         MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
445
446         g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
447
448         new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
449         new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
450
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);
453
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;
458
459         *new1p = new1;
460         *new2p = new2;
461 }
462
463 static MonoJitInfoTable*
464 jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
465 {
466         MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
467                 + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
468         int i, j;
469
470         new_table->domain = table->domain;
471         new_table->num_chunks = table->num_chunks + 1;
472
473         j = 0;
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]);
477                         j += 2;
478                 } else {
479                         new_table->chunks [j] = table->chunks [i];
480                         ++new_table->chunks [j]->refcount;
481                         ++j;
482                 }
483         }
484
485         g_assert (j == new_table->num_chunks);
486
487         return new_table;
488 }
489
490 static MonoJitInfoTableChunk*
491 jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
492 {
493         MonoJitInfoTableChunk *result = jit_info_table_new_chunk ();
494         int i, j;
495
496         j = 0;
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];
500         }
501
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;
505         else
506                 result->last_code_end = old->last_code_end;
507
508         return result;
509 }
510
511 static MonoJitInfoTable*
512 jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
513 {
514         MonoJitInfoTable *new_table = (MonoJitInfoTable *)g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
515                 + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
516         int i, j;
517
518         new_table->domain = table->domain;
519         new_table->num_chunks = table->num_chunks;
520
521         j = 0;
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]);
525                 else {
526                         new_table->chunks [j] = table->chunks [i];
527                         ++new_table->chunks [j]->refcount;
528                         ++j;
529                 }
530         }
531
532         g_assert (j == new_table->num_chunks);
533
534         return new_table;
535 }
536
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:
541  *
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:
545  *
546  * If there are no tombstones in the chunk then we split the chunk in
547  * two, each half full.
548  *
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.
552  */
553 static MonoJitInfoTable*
554 jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
555 {
556         int num_elements = jit_info_table_num_elements (table);
557         int i;
558
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);
563         }
564
565         /* count the number of non-tombstone elements in the chunk */
566         num_elements = 0;
567         for (i = 0; i < chunk->num_elements; ++i) {
568                 if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
569                         ++num_elements;
570         }
571
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);
575         }
576
577         //printf ("purifying chunk\n");
578         return jit_info_table_copy_and_purify_chunk (table, chunk);
579 }
580
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).
591  */
592 static void
593 jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
594 {
595         MonoJitInfoTable *table;
596         MonoJitInfoTableChunk *chunk;
597         int chunk_pos, pos;
598         int num_elements;
599         int i;
600
601         table = *table_ptr;
602
603  restart:
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];
607
608         if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
609                 MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
610
611                 /* Debugging code, should be removed. */
612                 //jit_info_table_check (new_table);
613
614                 *table_ptr = new_table;
615                 mono_memory_barrier ();
616                 domain->num_jit_info_tables++;
617                 mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)mono_jit_info_table_free, HAZARD_FREE_MAY_LOCK, HAZARD_FREE_SAFE_CTX);
618                 table = new_table;
619
620                 goto restart;
621         }
622
623         /* Debugging code, should be removed. */
624         //jit_info_table_check (table);
625
626         num_elements = chunk->num_elements;
627
628         pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
629
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
632            empty. */
633         if (num_elements > 0)
634                 chunk->data [num_elements] = chunk->data [num_elements - 1];
635         else
636                 chunk->data [0] = ji;
637         mono_memory_write_barrier ();
638         chunk->num_elements = ++num_elements;
639
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];
644         }
645
646         /* Now we have room and can insert the new item. */
647         mono_memory_write_barrier ();
648         chunk->data [pos] = ji;
649
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;
653
654         /* Debugging code, should be removed. */
655         //jit_info_table_check (table);
656 }
657
658 void
659 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
660 {
661         g_assert (ji->d.method != NULL);
662
663         mono_domain_lock (domain);
664
665         ++mono_stats.jit_info_table_insert_count;
666
667         jit_info_table_add (domain, &domain->jit_info_table, ji);
668
669         mono_domain_unlock (domain);
670 }
671
672 static MonoJitInfo*
673 mono_jit_info_make_tombstone (MonoJitInfoTableChunk *chunk, MonoJitInfo *ji)
674 {
675         MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
676
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;
682
683         return tombstone;
684 }
685
686 /*
687  * LOCKING: domain lock
688  */
689 static void
690 mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
691 {
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_free_or_queue (ji, g_free, HAZARD_FREE_MAY_LOCK, HAZARD_FREE_SAFE_CTX);
696         } else {
697                 domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
698         }
699 }
700
701 static void
702 jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
703 {
704         MonoJitInfoTableChunk *chunk;
705         gpointer start = ji->code_start;
706         int chunk_pos, pos;
707
708         chunk_pos = jit_info_table_index (table, (gint8 *)start);
709         g_assert (chunk_pos < table->num_chunks);
710
711         pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, (gint8 *)start);
712
713         do {
714                 chunk = table->chunks [chunk_pos];
715
716                 while (pos < chunk->num_elements) {
717                         if (chunk->data [pos] == ji)
718                                 goto found;
719
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);
723
724                         ++pos;
725                 }
726
727                 ++chunk_pos;
728                 pos = 0;
729         } while (chunk_pos < table->num_chunks);
730
731  found:
732         g_assert (chunk->data [pos] == ji);
733
734         chunk->data [pos] = mono_jit_info_make_tombstone (chunk, ji);
735
736         /* Debugging code, should be removed. */
737         //jit_info_table_check (table);
738 }
739
740 void
741 mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
742 {
743         MonoJitInfoTable *table;
744
745         mono_domain_lock (domain);
746         table = domain->jit_info_table;
747
748         ++mono_stats.jit_info_table_remove_count;
749
750         jit_info_table_remove (table, ji);
751
752         mono_jit_info_free_or_queue (domain, ji);
753
754         mono_domain_unlock (domain);
755 }
756
757 void
758 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
759 {
760         MonoJitInfo *ji;
761         MonoDomain *domain = mono_get_root_domain ();
762
763         g_assert (domain);
764         mono_domain_lock (domain);
765
766         /*
767          * We reuse MonoJitInfoTable to store AOT module info,
768          * this gives us async-safe lookup.
769          */
770         if (!domain->aot_modules) {
771                 domain->num_jit_info_tables ++;
772                 domain->aot_modules = mono_jit_info_table_new (domain);
773         }
774
775         ji = g_new0 (MonoJitInfo, 1);
776         ji->d.image = image;
777         ji->code_start = start;
778         ji->code_size = (guint8*)end - (guint8*)start;
779         jit_info_table_add (domain, &domain->aot_modules, ji);
780
781         mono_domain_unlock (domain);
782 }
783
784 void
785 mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
786 {
787         jit_info_find_in_aot_func = func;
788 }
789
790 int
791 mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
792 {
793         int size = MONO_SIZEOF_JIT_INFO;
794
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);
804         return size;
805 }
806
807 void
808 mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
809                                         MonoJitInfoFlags flags, int num_clauses, int num_holes)
810 {
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;
823 }
824
825 /**
826  * mono_jit_info_get_code_start:
827  * @ji: the JIT information handle
828  *
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.
832  *
833  * Returns: Starting address with the native code.
834  */
835 gpointer
836 mono_jit_info_get_code_start (MonoJitInfo* ji)
837 {
838         return ji->code_start;
839 }
840
841 /**
842  * mono_jit_info_get_code_size:
843  * @ji: the JIT information handle
844  *
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.
848  *
849  * Returns: Starting address with the native code.
850  */
851 int
852 mono_jit_info_get_code_size (MonoJitInfo* ji)
853 {
854         return ji->code_size;
855 }
856
857 /**
858  * mono_jit_info_get_method:
859  * @ji: the JIT information handle
860  *
861  * Use this function to get the `MonoMethod *` that backs
862  * the @ji object.
863  *
864  * Returns: The MonoMethod that represents the code tracked
865  * by @ji.
866  */
867 MonoMethod*
868 mono_jit_info_get_method (MonoJitInfo* ji)
869 {
870         g_assert (!ji->async);
871         g_assert (!ji->is_trampoline);
872         return ji->d.method;
873 }
874
875 static gpointer
876 jit_info_key_extract (gpointer value)
877 {
878         MonoJitInfo *info = (MonoJitInfo*)value;
879
880         return info->d.method;
881 }
882
883 static gpointer*
884 jit_info_next_value (gpointer value)
885 {
886         MonoJitInfo *info = (MonoJitInfo*)value;
887
888         return (gpointer*)&info->n.next_jit_code_hash;
889 }
890
891 void
892 mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
893 {
894         mono_internal_hash_table_init (jit_code_hash,
895                                        mono_aligned_addr_hash,
896                                        jit_info_key_extract,
897                                        jit_info_next_value);
898 }
899
900 MonoGenericJitInfo*
901 mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
902 {
903         if (ji->has_generic_jit_info)
904                 return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
905         else
906                 return NULL;
907 }
908
909 /*
910  * mono_jit_info_get_generic_sharing_context:
911  * @ji: a jit info
912  *
913  * Returns the jit info's generic sharing context, or NULL if it
914  * doesn't have one.
915  */
916 MonoGenericSharingContext*
917 mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
918 {
919         MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
920
921         if (gi)
922                 return gi->generic_sharing_context;
923         else
924                 return NULL;
925 }
926
927 /*
928  * mono_jit_info_set_generic_sharing_context:
929  * @ji: a jit info
930  * @gsctx: a generic sharing context
931  *
932  * Sets the jit info's generic sharing context.  The jit info must
933  * have memory allocated for the context.
934  */
935 void
936 mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
937 {
938         MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
939
940         g_assert (gi);
941
942         gi->generic_sharing_context = gsctx;
943 }
944
945 MonoTryBlockHoleTableJitInfo*
946 mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
947 {
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;
953         } else {
954                 return NULL;
955         }
956 }
957
958 static int
959 try_block_hole_table_size (MonoJitInfo *ji)
960 {
961         MonoTryBlockHoleTableJitInfo *table;
962
963         table = mono_jit_info_get_try_block_hole_table_info (ji);
964         g_assert (table);
965         return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
966 }
967
968 MonoArchEHJitInfo*
969 mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
970 {
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;
978         } else {
979                 return NULL;
980         }
981 }
982
983 MonoThunkJitInfo*
984 mono_jit_info_get_thunk_info (MonoJitInfo *ji)
985 {
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;
995         } else {
996                 return NULL;
997         }
998 }