b10423120d43a649f8fd9a0c160a0fb3f307523f
[mono.git] / mono / metadata / profiler.c
1 /*
2  * Licensed to the .NET Foundation under one or more agreements.
3  * The .NET Foundation licenses this file to you under the MIT license.
4  * See the LICENSE file in the project root for more information.
5  */
6
7 #include <mono/metadata/assembly.h>
8 #include <mono/metadata/gc-internals.h>
9 #include <mono/metadata/mono-config-dirs.h>
10 #include <mono/metadata/mono-debug.h>
11 #include <mono/metadata/profiler-private.h>
12 #include <mono/utils/mono-dl.h>
13 #include <mono/utils/mono-error-internals.h>
14 #include <mono/utils/mono-logger-internals.h>
15
16 MonoProfilerState mono_profiler_state;
17
18 typedef void (*MonoProfilerInitializer) (const char *);
19
20 #define OLD_INITIALIZER_NAME "mono_profiler_startup"
21 #define NEW_INITIALIZER_NAME "mono_profiler_init"
22
23 static gboolean
24 load_profiler (MonoDl *module, const char *name, const char *desc)
25 {
26         if (!module)
27                 return FALSE;
28
29         char *err, *old_name = g_strdup_printf (OLD_INITIALIZER_NAME);
30         MonoProfilerInitializer func;
31
32         if (!(err = mono_dl_symbol (module, old_name, (gpointer) &func))) {
33                 mono_profiler_printf_err ("Found old-style startup symbol '%s' for the '%s' profiler; it has not been migrated to the new API.", old_name, name);
34                 g_free (old_name);
35                 return FALSE;
36         }
37
38         g_free (err);
39         g_free (old_name);
40
41         char *new_name = g_strdup_printf (NEW_INITIALIZER_NAME "_%s", name);
42
43         if ((err = mono_dl_symbol (module, new_name, (gpointer *) &func))) {
44                 g_free (err);
45                 g_free (new_name);
46                 return FALSE;
47         }
48
49         g_free (new_name);
50
51         func (desc);
52
53         return TRUE;
54 }
55
56 static gboolean
57 load_profiler_from_executable (const char *name, const char *desc)
58 {
59         char *err;
60
61         /*
62          * Some profilers (such as ours) may need to call back into the runtime
63          * from their sampling callback (which is called in async-signal context).
64          * They need to be able to know that all references back to the runtime
65          * have been resolved; otherwise, calling runtime functions may result in
66          * invoking the dynamic linker which is not async-signal-safe. Passing
67          * MONO_DL_EAGER will ask the dynamic linker to resolve everything upfront.
68          */
69         MonoDl *module = mono_dl_open (NULL, MONO_DL_EAGER, &err);
70
71         if (!module) {
72                 mono_profiler_printf_err ("Could not open main executable: %s", err);
73                 g_free (err);
74                 return FALSE;
75         }
76
77         return load_profiler (module, name, desc);
78 }
79
80 static gboolean
81 load_profiler_from_directory (const char *directory, const char *libname, const char *name, const char *desc)
82 {
83         char* path;
84         void *iter = NULL;
85
86         while ((path = mono_dl_build_path (directory, libname, &iter))) {
87                 // See the comment in load_embedded_profiler ().
88                 MonoDl *module = mono_dl_open (path, MONO_DL_EAGER, NULL);
89
90                 g_free (path);
91
92                 if (module)
93                         return load_profiler (module, name, desc);
94         }
95
96         return FALSE;
97 }
98
99 static gboolean
100 load_profiler_from_installation (const char *libname, const char *name, const char *desc)
101 {
102         char *err;
103         MonoDl *module = mono_dl_open_runtime_lib (libname, MONO_DL_EAGER, &err);
104
105         g_free (err);
106
107         if (module)
108                 return load_profiler (module, name, desc);
109
110         return FALSE;
111 }
112
113 void
114 mono_profiler_load (const char *desc)
115 {
116         if (!desc || !strcmp ("default", desc))
117                 desc = "log:report";
118
119         const char *col = strchr (desc, ':');
120         char *mname;
121
122         if (col != NULL) {
123                 mname = (char *) g_memdup (desc, col - desc + 1);
124                 mname [col - desc] = 0;
125         } else
126                 mname = g_strdup (desc);
127
128         if (!load_profiler_from_executable (mname, desc)) {
129                 char *libname = g_strdup_printf ("mono-profiler-%s", mname);
130                 gboolean res = load_profiler_from_installation (libname, mname, desc);
131
132                 if (!res && mono_config_get_assemblies_dir ())
133                         res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, mname, desc);
134
135                 if (!res)
136                         res = load_profiler_from_directory (NULL, libname, mname, desc);
137
138                 if (!res)
139                         mono_profiler_printf_err ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
140
141                 g_free (libname);
142         }
143
144         g_free (mname);
145 }
146
147 MonoProfilerHandle
148 mono_profiler_create (MonoProfiler *prof)
149 {
150         MonoProfilerHandle handle = g_new0 (struct _MonoProfilerDesc, 1);
151
152         handle->prof = prof;
153         handle->next = mono_profiler_state.profilers;
154
155         mono_profiler_state.profilers = handle;
156
157         return handle;
158 }
159
160 void
161 mono_profiler_set_cleanup_callback (MonoProfilerHandle handle, MonoProfilerCleanupCallback cb)
162 {
163         InterlockedWritePointer (&handle->cleanup_callback, (gpointer) cb);
164 }
165
166 void
167 mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfilerCoverageFilterCallback cb)
168 {
169         InterlockedWritePointer (&handle->coverage_filter, (gpointer) cb);
170 }
171
172 mono_bool
173 mono_profiler_enable_coverage (void)
174 {
175         if (mono_profiler_state.startup_done)
176                 return FALSE;
177
178         mono_os_mutex_init (&mono_profiler_state.coverage_mutex);
179         mono_profiler_state.coverage_hash = g_hash_table_new (NULL, NULL);
180
181         if (!mono_debug_enabled ())
182                 mono_debug_init (MONO_DEBUG_FORMAT_MONO);
183
184         return mono_profiler_state.code_coverage = TRUE;
185 }
186
187 static void
188 coverage_lock (void)
189 {
190         mono_os_mutex_lock (&mono_profiler_state.coverage_mutex);
191 }
192
193 static void
194 coverage_unlock (void)
195 {
196         mono_os_mutex_unlock (&mono_profiler_state.coverage_mutex);
197 }
198
199 mono_bool
200 mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb)
201 {
202         if (!mono_profiler_state.code_coverage)
203                 return FALSE;
204
205         coverage_lock ();
206
207         MonoProfilerCoverageInfo *info = g_hash_table_lookup (mono_profiler_state.coverage_hash, method);
208
209         coverage_unlock ();
210
211         if (!info)
212                 return FALSE;
213
214         MonoError error;
215         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
216         mono_error_assert_ok (&error);
217
218         guint32 size;
219
220         const unsigned char *start = mono_method_header_get_code (header, &size, NULL);
221         const unsigned char *end = start + size;
222         MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
223
224         for (guint32 i = 0; i < info->entries; i++) {
225                 guchar *cil_code = info->data [i].cil_code;
226
227                 if (cil_code && cil_code >= start && cil_code < end) {
228                         guint32 offset = cil_code - start;
229
230                         MonoProfilerCoverageData data = {
231                                 .method = method,
232                                 .il_offset = offset,
233                                 .counter = info->data [i].count,
234                                 .line = 1,
235                                 .column = 1,
236                         };
237
238                         if (minfo) {
239                                 MonoDebugSourceLocation *loc = mono_debug_method_lookup_location (minfo, offset);
240
241                                 if (loc) {
242                                         data.file_name = g_strdup (loc->source_file);
243                                         data.line = loc->row;
244                                         data.column = loc->column;
245
246                                         mono_debug_free_source_location (loc);
247                                 }
248                         }
249
250                         cb (handle->prof, &data);
251
252                         g_free ((char *) data.file_name);
253                 }
254         }
255
256         mono_metadata_free_mh (header);
257
258         return TRUE;
259 }
260
261 MonoProfilerCoverageInfo *
262 mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries)
263 {
264         if (!mono_profiler_state.code_coverage)
265                 return FALSE;
266
267         gboolean cover = FALSE;
268
269         for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
270                 MonoProfilerCoverageFilterCallback cb = handle->coverage_filter;
271
272                 if (cb)
273                         cover |= cb (handle->prof, method);
274         }
275
276         if (!cover)
277                 return NULL;
278
279         coverage_lock ();
280
281         MonoProfilerCoverageInfo *info = g_malloc0 (sizeof (MonoProfilerCoverageInfo) + SIZEOF_VOID_P * 2 * entries);
282
283         info->entries = entries;
284
285         g_hash_table_insert (mono_profiler_state.coverage_hash, method, info);
286
287         coverage_unlock ();
288
289         return info;
290 }
291
292 mono_bool
293 mono_profiler_enable_sampling (MonoProfilerHandle handle)
294 {
295         if (mono_profiler_state.startup_done)
296                 return FALSE;
297
298         if (mono_profiler_state.sampling_owner)
299                 return TRUE;
300
301         mono_profiler_state.sampling_owner = handle;
302         mono_profiler_state.sample_mode = MONO_PROFILER_SAMPLE_MODE_NONE;
303         mono_profiler_state.sample_freq = 100;
304         mono_os_sem_init (&mono_profiler_state.sampling_semaphore, 0);
305
306         return TRUE;
307 }
308
309 mono_bool
310 mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint32_t freq)
311 {
312         if (handle != mono_profiler_state.sampling_owner)
313                 return FALSE;
314
315         mono_profiler_state.sample_mode = mode;
316         mono_profiler_state.sample_freq = freq;
317
318         mono_profiler_sampling_thread_post ();
319
320         return TRUE;
321 }
322
323 mono_bool
324 mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint32_t *freq)
325 {
326         if (mode)
327                 *mode = mono_profiler_state.sample_mode;
328
329         if (freq)
330                 *freq = mono_profiler_state.sample_freq;
331
332         return handle == mono_profiler_state.sampling_owner;
333 }
334
335 gboolean
336 mono_profiler_sampling_enabled (void)
337 {
338         return !!mono_profiler_state.sampling_owner;
339 }
340
341 void
342 mono_profiler_sampling_thread_post (void)
343 {
344         mono_os_sem_post (&mono_profiler_state.sampling_semaphore);
345 }
346
347 void
348 mono_profiler_sampling_thread_wait (void)
349 {
350         mono_os_sem_wait (&mono_profiler_state.sampling_semaphore, MONO_SEM_FLAGS_NONE);
351 }
352
353 mono_bool
354 mono_profiler_enable_allocations (void)
355 {
356         if (mono_profiler_state.startup_done)
357                 return FALSE;
358
359         return mono_profiler_state.allocations = TRUE;
360 }
361
362 void
363 mono_profiler_set_call_instrumentation_filter_callback (MonoProfilerHandle handle, MonoProfilerCallInstrumentationFilterCallback cb)
364 {
365         InterlockedWritePointer (&handle->call_instrumentation_filter, (gpointer) cb);
366 }
367
368 mono_bool
369 mono_profiler_enable_call_context_introspection (void)
370 {
371         if (mono_profiler_state.startup_done)
372                 return FALSE;
373
374         mono_profiler_state.context_enable ();
375
376         return mono_profiler_state.call_contexts = TRUE;
377 }
378
379 void *
380 mono_profiler_call_context_get_this (MonoProfilerCallContext *context)
381 {
382         if (!mono_profiler_state.call_contexts)
383                 return NULL;
384
385         return mono_profiler_state.context_get_this (context);
386 }
387
388 void *
389 mono_profiler_call_context_get_argument (MonoProfilerCallContext *context, uint32_t position)
390 {
391         if (!mono_profiler_state.call_contexts)
392                 return NULL;
393
394         return mono_profiler_state.context_get_argument (context, position);
395 }
396
397 void *
398 mono_profiler_call_context_get_local (MonoProfilerCallContext *context, uint32_t position)
399 {
400         if (!mono_profiler_state.call_contexts)
401                 return NULL;
402
403         return mono_profiler_state.context_get_local (context, position);
404 }
405
406 void *
407 mono_profiler_call_context_get_result (MonoProfilerCallContext *context)
408 {
409         if (!mono_profiler_state.call_contexts)
410                 return NULL;
411
412         return mono_profiler_state.context_get_result (context);
413 }
414
415 void
416 mono_profiler_call_context_free_buffer (void *buffer)
417 {
418         mono_profiler_state.context_free_buffer (buffer);
419 }
420
421 MonoProfilerCallInstrumentationFlags
422 mono_profiler_get_call_instrumentation_flags (MonoMethod *method)
423 {
424         MonoProfilerCallInstrumentationFlags flags = MONO_PROFILER_CALL_INSTRUMENTATION_NONE;
425
426         for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
427                 MonoProfilerCallInstrumentationFilterCallback cb = handle->call_instrumentation_filter;
428
429                 if (cb)
430                         flags |= cb (handle->prof, method);
431         }
432
433         return flags;
434 }
435
436 void
437 mono_profiler_started (void)
438 {
439         mono_profiler_state.startup_done = TRUE;
440 }
441
442 void
443 mono_profiler_cleanup (void)
444 {
445         for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
446 #define _MONO_PROFILER_EVENT(name) \
447         mono_profiler_set_ ## name ## _callback (handle, NULL); \
448         g_assert (!handle->name ## _cb);
449 #define MONO_PROFILER_EVENT_0(name, type) \
450         _MONO_PROFILER_EVENT(name)
451 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
452         _MONO_PROFILER_EVENT(name)
453 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
454         _MONO_PROFILER_EVENT(name)
455 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
456         _MONO_PROFILER_EVENT(name)
457 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
458         _MONO_PROFILER_EVENT(name)
459 #include <mono/metadata/profiler-events.h>
460 #undef MONO_PROFILER_EVENT_0
461 #undef MONO_PROFILER_EVENT_1
462 #undef MONO_PROFILER_EVENT_2
463 #undef MONO_PROFILER_EVENT_3
464 #undef MONO_PROFILER_EVENT_4
465 #undef _MONO_PROFILER_EVENT
466         }
467
468 #define _MONO_PROFILER_EVENT(name, type) \
469         g_assert (!mono_profiler_state.name ## _count);
470 #define MONO_PROFILER_EVENT_0(name, type) \
471         _MONO_PROFILER_EVENT(name, type)
472 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
473         _MONO_PROFILER_EVENT(name, type)
474 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
475         _MONO_PROFILER_EVENT(name, type)
476 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
477         _MONO_PROFILER_EVENT(name, type)
478 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
479         _MONO_PROFILER_EVENT(name, type)
480 #include <mono/metadata/profiler-events.h>
481 #undef MONO_PROFILER_EVENT_0
482 #undef MONO_PROFILER_EVENT_1
483 #undef MONO_PROFILER_EVENT_2
484 #undef MONO_PROFILER_EVENT_3
485 #undef MONO_PROFILER_EVENT_4
486 #undef _MONO_PROFILER_EVENT
487
488         MonoProfilerHandle head = mono_profiler_state.profilers;
489
490         while (head) {
491                 MonoProfilerCleanupCallback cb = head->cleanup_callback;
492
493                 if (cb)
494                         cb (head->prof);
495
496                 MonoProfilerHandle cur = head;
497                 head = head->next;
498
499                 g_free (cur);
500         }
501
502         if (mono_profiler_state.code_coverage) {
503                 mono_os_mutex_destroy (&mono_profiler_state.coverage_mutex);
504
505                 GHashTableIter iter;
506
507                 g_hash_table_iter_init (&iter, mono_profiler_state.coverage_hash);
508
509                 MonoProfilerCoverageInfo *info;
510
511                 while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info))
512                         g_free (info);
513
514                 g_hash_table_destroy (mono_profiler_state.coverage_hash);
515         }
516
517         if (mono_profiler_state.sampling_owner)
518                 mono_os_sem_destroy (&mono_profiler_state.sampling_semaphore);
519 }
520
521 static void
522 update_callback (volatile gpointer *location, gpointer new_, volatile gint32 *counter)
523 {
524         gpointer old;
525
526         do {
527                 old = InterlockedReadPointer (location);
528         } while (InterlockedCompareExchangePointer (location, new_, old) != old);
529
530         /*
531          * At this point, we could have installed a NULL callback while the counter
532          * is still non-zero, i.e. setting the callback and modifying the counter
533          * is not a single atomic operation. This is fine as we make sure callbacks
534          * are non-NULL before invoking them (see the code below that generates the
535          * raise functions), and besides, updating callbacks at runtime is an
536          * inherently racy operation.
537          */
538
539         if (old)
540                 InterlockedDecrement (counter);
541
542         if (new_)
543                 InterlockedIncrement (counter);
544 }
545
546 #define _MONO_PROFILER_EVENT(name, type) \
547         void \
548         mono_profiler_set_ ## name ## _callback (MonoProfilerHandle handle, MonoProfiler ## type ## Callback cb) \
549         { \
550                 update_callback (&handle->name ## _cb, (gpointer) cb, &mono_profiler_state.name ## _count); \
551         }
552 #define MONO_PROFILER_EVENT_0(name, type) \
553         _MONO_PROFILER_EVENT(name, type)
554 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
555         _MONO_PROFILER_EVENT(name, type)
556 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
557         _MONO_PROFILER_EVENT(name, type)
558 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
559         _MONO_PROFILER_EVENT(name, type)
560 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
561         _MONO_PROFILER_EVENT(name, type)
562 #include <mono/metadata/profiler-events.h>
563 #undef MONO_PROFILER_EVENT_0
564 #undef MONO_PROFILER_EVENT_1
565 #undef MONO_PROFILER_EVENT_2
566 #undef MONO_PROFILER_EVENT_3
567 #undef MONO_PROFILER_EVENT_4
568 #undef _MONO_PROFILER_EVENT
569
570 #define _MONO_PROFILER_EVENT(name, type, params, args) \
571         void \
572         mono_profiler_raise_ ## name params \
573         { \
574                 for (MonoProfilerHandle h = mono_profiler_state.profilers; h; h = h->next) { \
575                         MonoProfiler ## type ## Callback cb = h->name ## _cb; \
576                         if (cb) \
577                                 cb args; \
578                 } \
579         }
580 #define MONO_PROFILER_EVENT_0(name, type) \
581         _MONO_PROFILER_EVENT(name, type, (void), (h->prof))
582 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
583         _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name), (h->prof, arg1_name))
584 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
585         _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name), (h->prof, arg1_name, arg2_name))
586 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
587         _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name), (h->prof, arg1_name, arg2_name, arg3_name))
588 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
589         _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name), (h->prof, arg1_name, arg2_name, arg3_name, arg4_name))
590 #include <mono/metadata/profiler-events.h>
591 #undef MONO_PROFILER_EVENT_0
592 #undef MONO_PROFILER_EVENT_1
593 #undef MONO_PROFILER_EVENT_2
594 #undef MONO_PROFILER_EVENT_3
595 #undef MONO_PROFILER_EVENT_4
596 #undef _MONO_PROFILER_EVENT
597
598 /*
599  * The following code is here to maintain compatibility with a few profiler API
600  * functions used by Xamarin.{Android,iOS,Mac} so that they keep working
601  * regardless of which system Mono version is used.
602  *
603  * TODO: Remove this some day if we're OK with breaking compatibility.
604  */
605
606 typedef void *MonoLegacyProfiler;
607
608 typedef void (*MonoLegacyProfileFunc) (MonoLegacyProfiler *prof);
609 typedef void (*MonoLegacyProfileThreadFunc) (MonoLegacyProfiler *prof, uintptr_t tid);
610 typedef void (*MonoLegacyProfileGCFunc) (MonoLegacyProfiler *prof, MonoProfilerGCEvent event, int generation);
611 typedef void (*MonoLegacyProfileGCResizeFunc) (MonoLegacyProfiler *prof, int64_t new_size);
612 typedef void (*MonoLegacyProfileJitResult) (MonoLegacyProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result);
613
614 struct _MonoProfiler {
615         MonoProfilerHandle handle;
616         MonoLegacyProfiler *profiler;
617         MonoLegacyProfileFunc shutdown_callback;
618         MonoLegacyProfileThreadFunc thread_start, thread_end;
619         MonoLegacyProfileGCFunc gc_event;
620         MonoLegacyProfileGCResizeFunc gc_heap_resize;
621         MonoLegacyProfileJitResult jit_end2;
622 };
623
624 static MonoProfiler *current;
625
626 MONO_API void mono_profiler_install (MonoLegacyProfiler *prof, MonoLegacyProfileFunc callback);
627 MONO_API void mono_profiler_install_thread (MonoLegacyProfileThreadFunc start, MonoLegacyProfileThreadFunc end);
628 MONO_API void mono_profiler_install_gc (MonoLegacyProfileGCFunc callback, MonoLegacyProfileGCResizeFunc heap_resize_callback);
629 MONO_API void mono_profiler_install_jit_end (MonoLegacyProfileJitResult end);
630 MONO_API void mono_profiler_set_events (int flags);
631
632 static void
633 shutdown_cb (MonoProfiler *prof)
634 {
635         prof->shutdown_callback (prof->profiler);
636 }
637
638 void
639 mono_profiler_install (MonoLegacyProfiler *prof, MonoLegacyProfileFunc callback)
640 {
641         current = g_new0 (MonoProfiler, 1);
642         current->handle = mono_profiler_create (current);
643         current->profiler = prof;
644         current->shutdown_callback = callback;
645
646         if (callback)
647                 mono_profiler_set_runtime_shutdown_end_callback (current->handle, shutdown_cb);
648 }
649
650 static void
651 thread_start_cb (MonoProfiler *prof, uintptr_t tid)
652 {
653         prof->thread_start (prof->profiler, tid);
654 }
655
656 static void
657 thread_stop_cb (MonoProfiler *prof, uintptr_t tid)
658 {
659         prof->thread_end (prof->profiler, tid);
660 }
661
662 void
663 mono_profiler_install_thread (MonoLegacyProfileThreadFunc start, MonoLegacyProfileThreadFunc end)
664 {
665         current->thread_start = start;
666         current->thread_end = end;
667
668         if (start)
669                 mono_profiler_set_thread_started_callback (current->handle, thread_start_cb);
670
671         if (end)
672                 mono_profiler_set_thread_stopped_callback (current->handle, thread_stop_cb);
673 }
674
675 static void
676 gc_event_cb (MonoProfiler *prof, MonoProfilerGCEvent event, uint32_t generation)
677 {
678         prof->gc_event (prof->profiler, event, generation);
679 }
680
681 static void
682 gc_resize_cb (MonoProfiler *prof, uintptr_t size)
683 {
684         prof->gc_heap_resize (prof->profiler, size);
685 }
686
687 void
688 mono_profiler_install_gc (MonoLegacyProfileGCFunc callback, MonoLegacyProfileGCResizeFunc heap_resize_callback)
689 {
690         current->gc_event = callback;
691         current->gc_heap_resize = heap_resize_callback;
692
693         if (callback)
694                 mono_profiler_set_gc_event_callback (current->handle, gc_event_cb);
695
696         if (heap_resize_callback)
697                 mono_profiler_set_gc_resize_callback (current->handle, gc_resize_cb);
698 }
699
700 static void
701 jit_done_cb (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
702 {
703         prof->jit_end2 (prof->profiler, method, jinfo, 0);
704 }
705
706 static void
707 jit_failed_cb (MonoProfiler *prof, MonoMethod *method)
708 {
709         prof->jit_end2 (prof->profiler, method, NULL, 1);
710 }
711
712 void
713 mono_profiler_install_jit_end (MonoLegacyProfileJitResult end)
714 {
715         current->jit_end2 = end;
716
717         if (end) {
718                 mono_profiler_set_jit_done_callback (current->handle, jit_done_cb);
719                 mono_profiler_set_jit_failed_callback (current->handle, jit_failed_cb);
720         }
721 }
722
723 void
724 mono_profiler_set_events (int flags)
725 {
726         /* Do nothing. */
727 }