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