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