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