[runtime] Coverage profiler fixes (#5698)
[mono.git] / mono / metadata / profiler.c
index c69f55ec6dc258a3c36fee4dfe93045afdd48bec..9f65059f806699088b673fcf01a1896ae59a7576 100644 (file)
-/**
- * \file
- * Profiler interface for Mono
- *
- * Author:
- *   Paolo Molaro (lupus@ximian.com)
- *   Alex Rønne Petersen (alexrp@xamarin.com)
- *
- * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
- * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
- * Copyright 2011 Xamarin Inc (http://www.xamarin.com).
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-
-#include "config.h"
-#include "mono/metadata/profiler-private.h"
-#include "mono/metadata/assembly.h"
-#include "mono/metadata/debug-helpers.h"
-#include "mono/metadata/mono-debug.h"
-#include "mono/metadata/debug-internals.h"
-#include "mono/metadata/metadata-internals.h"
-#include "mono/metadata/class-internals.h"
-#include "mono/metadata/domain-internals.h"
-#include "mono/metadata/gc-internals.h"
-#include "mono/metadata/mono-config-dirs.h"
-#include "mono/utils/mono-dl.h"
+/*
+ * Licensed to the .NET Foundation under one or more agreements.
+ * The .NET Foundation licenses this file to you under the MIT license.
+ * See the LICENSE file in the project root for more information.
+ */
+
+#include <mono/metadata/assembly.h>
+#include <mono/metadata/gc-internals.h>
+#include <mono/metadata/mono-config-dirs.h>
+#include <mono/metadata/mono-debug.h>
+#include <mono/metadata/profiler-private.h>
+#include <mono/metadata/debug-internals.h>
+#include <mono/utils/mono-dl.h>
+#include <mono/utils/mono-error-internals.h>
 #include <mono/utils/mono-logger-internals.h>
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_BACKTRACE_SYMBOLS
-#include <execinfo.h>
-#endif
-
-typedef struct _ProfilerDesc ProfilerDesc;
-struct _ProfilerDesc {
-       ProfilerDesc *next;
-       MonoProfiler *profiler;
-       MonoProfileFlags events;
-
-       MonoProfileAppDomainFunc   domain_start_load;
-       MonoProfileAppDomainResult domain_end_load;
-       MonoProfileAppDomainFunc   domain_start_unload;
-       MonoProfileAppDomainFunc   domain_end_unload;
-       MonoProfileAppDomainFriendlyNameFunc   domain_name;
-
-       MonoProfileContextFunc context_load;
-       MonoProfileContextFunc context_unload;
-
-       MonoProfileAssemblyFunc   assembly_start_load;
-       MonoProfileAssemblyResult assembly_end_load;
-       MonoProfileAssemblyFunc   assembly_start_unload;
-       MonoProfileAssemblyFunc   assembly_end_unload;
-
-       MonoProfileModuleFunc   module_start_load;
-       MonoProfileModuleResult module_end_load;
-       MonoProfileModuleFunc   module_start_unload;
-       MonoProfileModuleFunc   module_end_unload;
-
-       MonoProfileClassFunc   class_start_load;
-       MonoProfileClassResult class_end_load;
-       MonoProfileClassFunc   class_start_unload;
-       MonoProfileClassFunc   class_end_unload;
-
-       MonoProfileMethodFunc   jit_start;
-       MonoProfileMethodResult jit_end;
-       MonoProfileJitResult    jit_end2;
-       MonoProfileMethodFunc   method_free;
-       MonoProfileMethodFunc   method_start_invoke;
-       MonoProfileMethodFunc   method_end_invoke;
-       MonoProfileMethodResult man_unman_transition;
-       MonoProfileAllocFunc    allocation_cb;
-       MonoProfileMonitorFunc  monitor_event_cb;
-       MonoProfileStatFunc     statistical_cb;
-       MonoProfileStatCallChainFunc statistical_call_chain_cb;
-       int                     statistical_call_chain_depth;
-       MonoProfilerCallChainStrategy  statistical_call_chain_strategy;
-       MonoProfileMethodFunc   method_enter;
-       MonoProfileMethodFunc   method_leave;
-
-       MonoProfileExceptionFunc        exception_throw_cb;
-       MonoProfileMethodFunc exception_method_leave_cb;
-       MonoProfileExceptionClauseFunc exception_clause_cb;
-       MonoProfileExceptionClauseFunc2 exception_clause_cb2;
-
-       MonoProfileIomapFunc iomap_cb;
-
-       MonoProfileThreadFunc   thread_start;
-       MonoProfileThreadFunc   thread_end;
-       MonoProfileThreadNameFunc   thread_name;
-
-       MonoProfileCoverageFilterFunc coverage_filter_cb;
-
-       MonoProfileFunc shutdown_callback;
-
-       MonoProfileGCFunc        gc_event;
-       MonoProfileGCResizeFunc  gc_heap_resize;
-       MonoProfileGCMoveFunc    gc_moves;
-       MonoProfileGCHandleFunc  gc_handle;
-       MonoProfileGCRootFunc    gc_roots;
-
-       MonoProfileGCFinalizeFunc gc_finalize_begin;
-       MonoProfileGCFinalizeObjectFunc gc_finalize_object_begin;
-       MonoProfileGCFinalizeObjectFunc gc_finalize_object_end;
-       MonoProfileGCFinalizeFunc gc_finalize_end;
-
-       MonoProfileFunc          runtime_initialized_event;
-
-       MonoProfilerCodeChunkNew code_chunk_new;
-       MonoProfilerCodeChunkDestroy code_chunk_destroy;
-       MonoProfilerCodeBufferNew code_buffer_new;
-};
 
-static ProfilerDesc *prof_list = NULL;
+MonoProfilerState mono_profiler_state;
 
-#define mono_profiler_coverage_lock() mono_os_mutex_lock (&profiler_coverage_mutex)
-#define mono_profiler_coverage_unlock() mono_os_mutex_unlock (&profiler_coverage_mutex)
-static mono_mutex_t profiler_coverage_mutex;
+typedef void (*MonoProfilerInitializer) (const char *);
 
-/* this is directly accessible to other mono libs.
- * It is the ORed value of all the profiler's events.
- */
-MonoProfileFlags mono_profiler_events;
-
-/**
- * mono_profiler_install:
- * \param prof a \c MonoProfiler structure pointer, or a pointer to a derived structure.
- * \param callback the function to invoke at shutdown
- * Use \c mono_profiler_install to activate profiling in the Mono runtime.
- * Typically developers of new profilers will create a new structure whose
- * first field is a \c MonoProfiler and put any extra information that they need
- * to access from the various profiling callbacks there.
- */
-void
-mono_profiler_install (MonoProfiler *prof, MonoProfileFunc callback)
-{
-       ProfilerDesc *desc = g_new0 (ProfilerDesc, 1);
-       if (!prof_list)
-               mono_os_mutex_init_recursive (&profiler_coverage_mutex);
-       desc->profiler = prof;
-       desc->shutdown_callback = callback;
-       desc->next = prof_list;
-       prof_list = desc;
-}
+#define OLD_INITIALIZER_NAME "mono_profiler_startup"
+#define NEW_INITIALIZER_NAME "mono_profiler_init"
 
-/**
- * mono_profiler_set_events:
- * \param events an ORed set of values made up of \c MONO_PROFILER_ flags
- * The events described in the \p events argument is a set of flags
- * that represent which profiling events must be triggered.  For
- * example if you have registered a set of methods for tracking
- * JIT compilation start and end with \c mono_profiler_install_jit_compile,
- * you will want to pass the \c MONO_PROFILE_JIT_COMPILATION flag to
- * this routine.
- *
- * You can call \c mono_profile_set_events more than once and you can
- * do this at runtime to modify which methods are invoked.
- */
-void
-mono_profiler_set_events (MonoProfileFlags events)
+static gboolean
+load_profiler (MonoDl *module, const char *name, const char *desc)
 {
-       ProfilerDesc *prof;
-       MonoProfileFlags value = (MonoProfileFlags)0;
-       if (prof_list)
-               prof_list->events = events;
-       for (prof = prof_list; prof; prof = prof->next)
-               value = (MonoProfileFlags)(value | prof->events);
-       mono_profiler_events = value;
-}
+       if (!module)
+               return FALSE;
 
-/**
- * mono_profiler_get_events:
- *
- * Returns a list of active events that will be intercepted. 
- */
-MonoProfileFlags
-mono_profiler_get_events (void)
-{
-       return mono_profiler_events;
-}
+       char *err, *old_name = g_strdup_printf (OLD_INITIALIZER_NAME);
+       MonoProfilerInitializer func;
 
-/**
- * mono_profiler_install_enter_leave:
- * \param enter the routine to be called on each method entry
- * \param fleave the routine to be called each time a method returns
- *
- * Use this routine to install routines that will be called everytime
- * a method enters and leaves.   The routines will receive as an argument
- * the \c MonoMethod representing the method that is entering or leaving.
- */
-void
-mono_profiler_install_enter_leave (MonoProfileMethodFunc enter, MonoProfileMethodFunc fleave)
-{
-       if (!prof_list)
-               return;
-       prof_list->method_enter = enter;
-       prof_list->method_leave = fleave;
-}
+       if (!(err = mono_dl_symbol (module, old_name, (gpointer) &func))) {
+               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);
+               g_free (old_name);
+               return FALSE;
+       }
 
-/**
- * mono_profiler_install_jit_compile:
- * \param start the routine to be called when the JIT process starts.
- * \param end the routine to be called when the JIT process ends.
- *
- * Use this routine to install routines that will be called when JIT 
- * compilation of a method starts and completes.
- */
-void 
-mono_profiler_install_jit_compile (MonoProfileMethodFunc start, MonoProfileMethodResult end)
-{
-       if (!prof_list)
-               return;
-       prof_list->jit_start = start;
-       prof_list->jit_end = end;
-}
+       g_free (err);
+       g_free (old_name);
 
-void 
-mono_profiler_install_jit_end (MonoProfileJitResult end)
-{
-       if (!prof_list)
-               return;
-       prof_list->jit_end2 = end;
-}
+       char *new_name = g_strdup_printf (NEW_INITIALIZER_NAME "_%s", name);
 
-void 
-mono_profiler_install_method_free (MonoProfileMethodFunc callback)
-{
-       if (!prof_list)
-               return;
-       prof_list->method_free = callback;
-}
+       if ((err = mono_dl_symbol (module, new_name, (gpointer *) &func))) {
+               g_free (err);
+               g_free (new_name);
+               return FALSE;
+       }
 
-void
-mono_profiler_install_method_invoke (MonoProfileMethodFunc start, MonoProfileMethodFunc end)
-{
-       if (!prof_list)
-               return;
-       prof_list->method_start_invoke = start;
-       prof_list->method_end_invoke = end;
-}
+       g_free (new_name);
 
-/**
- * mono_profiler_install_thread:
- */
-void 
-mono_profiler_install_thread (MonoProfileThreadFunc start, MonoProfileThreadFunc end)
-{
-       if (!prof_list)
-               return;
-       prof_list->thread_start = start;
-       prof_list->thread_end = end;
-}
+       func (desc);
 
-void 
-mono_profiler_install_thread_name (MonoProfileThreadNameFunc thread_name_cb)
-{
-       if (!prof_list)
-               return;
-       prof_list->thread_name = thread_name_cb;
+       return TRUE;
 }
 
-/**
- * mono_profiler_install_transition:
- */
-void 
-mono_profiler_install_transition (MonoProfileMethodResult callback)
+static gboolean
+load_profiler_from_executable (const char *name, const char *desc)
 {
-       if (!prof_list)
-               return;
-       prof_list->man_unman_transition = callback;
-}
+       char *err;
 
-/**
- * mono_profiler_install_allocation:
- */
-void 
-mono_profiler_install_allocation (MonoProfileAllocFunc callback)
-{
-       if (!prof_list)
-               return;
-       prof_list->allocation_cb = callback;
+       /*
+        * Some profilers (such as ours) may need to call back into the runtime
+        * from their sampling callback (which is called in async-signal context).
+        * They need to be able to know that all references back to the runtime
+        * have been resolved; otherwise, calling runtime functions may result in
+        * invoking the dynamic linker which is not async-signal-safe. Passing
+        * MONO_DL_EAGER will ask the dynamic linker to resolve everything upfront.
+        */
+       MonoDl *module = mono_dl_open (NULL, MONO_DL_EAGER, &err);
+
+       if (!module) {
+               mono_profiler_printf_err ("Could not open main executable: %s", err);
+               g_free (err);
+               return FALSE;
+       }
+
+       return load_profiler (module, name, desc);
 }
 
-void
-mono_profiler_install_monitor  (MonoProfileMonitorFunc callback)
+static gboolean
+load_profiler_from_directory (const char *directory, const char *libname, const char *name, const char *desc)
 {
-       if (!prof_list)
-               return;
-       prof_list->monitor_event_cb = callback;
-}
+       char* path;
+       void *iter = NULL;
 
-static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
-static int64_t sampling_frequency = 100; // Hz
+       while ((path = mono_dl_build_path (directory, libname, &iter))) {
+               // See the comment in load_embedded_profiler ().
+               MonoDl *module = mono_dl_open (path, MONO_DL_EAGER, NULL);
 
-/**
- * mono_profiler_set_statistical_mode:
- * \param mode the sampling mode used.
- * \param sample_frequency_is_us the sampling frequency in microseconds.
- *
- * Set the sampling parameters for the profiler. Sampling mode affects the effective sampling rate as in samples/s you'll witness.
- * The default sampling mode is process mode, which only reports samples when there's activity in the process.
- *
- * Sampling frequency should be interpreted as a suggestion that can't always be honored due to how most kernels expose alarms.
- *
- * Said that, when using statistical sampling, always assume variable rate sampling as all sort of external factors can interfere.
- */
-void
-mono_profiler_set_statistical_mode (MonoProfileSamplingMode mode, int64_t sampling_frequency_hz)
-{
-       sampling_mode = mode;
-       sampling_frequency = sampling_frequency_hz;
-}
+               g_free (path);
 
-/**
- * mono_profiler_install_statistical:
- */
-void 
-mono_profiler_install_statistical (MonoProfileStatFunc callback)
-{
-       if (!prof_list)
-               return;
-       prof_list->statistical_cb = callback;
-}
+               if (module)
+                       return load_profiler (module, name, desc);
+       }
 
-int64_t
-mono_profiler_get_sampling_rate (void)
-{
-       return sampling_frequency;
+       return FALSE;
 }
 
-MonoProfileSamplingMode
-mono_profiler_get_sampling_mode (void)
+static gboolean
+load_profiler_from_installation (const char *libname, const char *name, const char *desc)
 {
-       return sampling_mode;
-}
+       char *err;
+       MonoDl *module = mono_dl_open_runtime_lib (libname, MONO_DL_EAGER, &err);
 
-void 
-mono_profiler_install_statistical_call_chain (MonoProfileStatCallChainFunc callback, int call_chain_depth, MonoProfilerCallChainStrategy call_chain_strategy) {
-       if (!prof_list)
-               return;
-       if (call_chain_depth > MONO_PROFILER_MAX_STAT_CALL_CHAIN_DEPTH) {
-               call_chain_depth = MONO_PROFILER_MAX_STAT_CALL_CHAIN_DEPTH;
-       }
-       if ((call_chain_strategy >= MONO_PROFILER_CALL_CHAIN_INVALID) || (call_chain_strategy < MONO_PROFILER_CALL_CHAIN_NONE)) {
-               call_chain_strategy = MONO_PROFILER_CALL_CHAIN_NONE;
-       }
-       prof_list->statistical_call_chain_cb = callback;
-       prof_list->statistical_call_chain_depth = call_chain_depth;
-       prof_list->statistical_call_chain_strategy = call_chain_strategy;
-}
+       g_free (err);
 
-int
-mono_profiler_stat_get_call_chain_depth (void) {
-       if (prof_list && prof_list->statistical_call_chain_cb != NULL) {
-               return prof_list->statistical_call_chain_depth;
-       } else {
-               return 0;
-       }
-}
+       if (module)
+               return load_profiler (module, name, desc);
 
-MonoProfilerCallChainStrategy
-mono_profiler_stat_get_call_chain_strategy (void) {
-       if (prof_list && prof_list->statistical_call_chain_cb != NULL) {
-               return prof_list->statistical_call_chain_strategy;
-       } else {
-               return MONO_PROFILER_CALL_CHAIN_NONE;
-       }
+       return FALSE;
 }
 
-void mono_profiler_install_exception (MonoProfileExceptionFunc throw_callback, MonoProfileMethodFunc exc_method_leave, MonoProfileExceptionClauseFunc clause_callback)
+void
+mono_profiler_load (const char *desc)
 {
-       if (!prof_list)
-               return;
-       prof_list->exception_throw_cb = throw_callback;
-       prof_list->exception_method_leave_cb = exc_method_leave;
-       prof_list->exception_clause_cb = clause_callback;
-}
+       if (!desc || !strcmp ("default", desc))
+               desc = "log:report";
 
-void mono_profiler_install_exception_clause (MonoProfileExceptionClauseFunc2 clause_callback)
-{
-       if (!prof_list)
-               return;
+       const char *col = strchr (desc, ':');
+       char *mname;
 
-       prof_list->exception_clause_cb2 = clause_callback;
-}
+       if (col != NULL) {
+               mname = (char *) g_memdup (desc, col - desc + 1);
+               mname [col - desc] = 0;
+       } else
+               mname = g_strdup (desc);
 
-/**
- * mono_profiler_install_coverage_filter:
- */
-void 
-mono_profiler_install_coverage_filter (MonoProfileCoverageFilterFunc callback)
-{
-       if (!prof_list)
-               return;
-       prof_list->coverage_filter_cb = callback;
-}
+       if (!load_profiler_from_executable (mname, desc)) {
+               char *libname = g_strdup_printf ("mono-profiler-%s", mname);
+               gboolean res = load_profiler_from_installation (libname, mname, desc);
 
-/**
- * mono_profiler_install_appdomain:
- */
-void 
-mono_profiler_install_appdomain   (MonoProfileAppDomainFunc start_load, MonoProfileAppDomainResult end_load,
-                                   MonoProfileAppDomainFunc start_unload, MonoProfileAppDomainFunc end_unload)
+               if (!res && mono_config_get_assemblies_dir ())
+                       res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, mname, desc);
 
-{
-       if (!prof_list)
-               return;
-       prof_list->domain_start_load = start_load;
-       prof_list->domain_end_load = end_load;
-       prof_list->domain_start_unload = start_unload;
-       prof_list->domain_end_unload = end_unload;
-}
+               if (!res)
+                       res = load_profiler_from_directory (NULL, libname, mname, desc);
 
-void
-mono_profiler_install_appdomain_name (MonoProfileAppDomainFriendlyNameFunc domain_name_cb)
-{
-       if (!prof_list)
-               return;
+               if (!res)
+                       mono_profiler_printf_err ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
 
-       prof_list->domain_name = domain_name_cb;
+               g_free (libname);
+       }
+
+       g_free (mname);
 }
 
-void
-mono_profiler_install_context (MonoProfileContextFunc load, MonoProfileContextFunc unload)
+MonoProfilerHandle
+mono_profiler_create (MonoProfiler *prof)
 {
-       if (!prof_list)
-               return;
+       MonoProfilerHandle handle = g_new0 (struct _MonoProfilerDesc, 1);
 
-       prof_list->context_load = load;
-       prof_list->context_unload = unload;
-}
+       handle->prof = prof;
+       handle->next = mono_profiler_state.profilers;
 
-/**
- * mono_profiler_install_assembly:
- */
-void 
-mono_profiler_install_assembly    (MonoProfileAssemblyFunc start_load, MonoProfileAssemblyResult end_load,
-                                   MonoProfileAssemblyFunc start_unload, MonoProfileAssemblyFunc end_unload)
-{
-       if (!prof_list)
-               return;
-       prof_list->assembly_start_load = start_load;
-       prof_list->assembly_end_load = end_load;
-       prof_list->assembly_start_unload = start_unload;
-       prof_list->assembly_end_unload = end_unload;
-}
+       mono_profiler_state.profilers = handle;
 
-/**
- * mono_profiler_install_module:
- */
-void 
-mono_profiler_install_module      (MonoProfileModuleFunc start_load, MonoProfileModuleResult end_load,
-                                   MonoProfileModuleFunc start_unload, MonoProfileModuleFunc end_unload)
-{
-       if (!prof_list)
-               return;
-       prof_list->module_start_load = start_load;
-       prof_list->module_end_load = end_load;
-       prof_list->module_start_unload = start_unload;
-       prof_list->module_end_unload = end_unload;
+       return handle;
 }
 
-/**
- * mono_profiler_install_class:
- */
 void
-mono_profiler_install_class       (MonoProfileClassFunc start_load, MonoProfileClassResult end_load,
-                                   MonoProfileClassFunc start_unload, MonoProfileClassFunc end_unload)
+mono_profiler_set_cleanup_callback (MonoProfilerHandle handle, MonoProfilerCleanupCallback cb)
 {
-       if (!prof_list)
-               return;
-       prof_list->class_start_load = start_load;
-       prof_list->class_end_load = end_load;
-       prof_list->class_start_unload = start_unload;
-       prof_list->class_end_unload = end_unload;
+       InterlockedWritePointer (&handle->cleanup_callback, (gpointer) cb);
 }
 
-/**
- * mono_profiler_method_enter:
- */
 void
-mono_profiler_method_enter (MonoMethod *method)
+mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfilerCoverageFilterCallback cb)
 {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_ENTER_LEAVE) && prof->method_enter)
-                       prof->method_enter (prof->profiler, method);
-       }
+       InterlockedWritePointer (&handle->coverage_filter, (gpointer) cb);
 }
 
-/**
- * mono_profiler_method_leave:
- */
-void
-mono_profiler_method_leave (MonoMethod *method)
+mono_bool
+mono_profiler_enable_coverage (void)
 {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_ENTER_LEAVE) && prof->method_leave)
-                       prof->method_leave (prof->profiler, method);
-       }
-}
+       if (mono_profiler_state.startup_done)
+               return FALSE;
 
-/**
- * mono_profiler_method_jit:
- */
-void 
-mono_profiler_method_jit (MonoMethod *method)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_JIT_COMPILATION) && prof->jit_start)
-                       prof->jit_start (prof->profiler, method);
-       }
-}
+       mono_os_mutex_init (&mono_profiler_state.coverage_mutex);
+       mono_profiler_state.coverage_hash = g_hash_table_new (NULL, NULL);
 
-/**
- * mono_profiler_method_end_jit:
- */
-void 
-mono_profiler_method_end_jit (MonoMethod *method, MonoJitInfo* jinfo, int result)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_JIT_COMPILATION)) {
-                       if (prof->jit_end)
-                               prof->jit_end (prof->profiler, method, result);
-                       if (prof->jit_end2)
-                               prof->jit_end2 (prof->profiler, method, jinfo, result);
-               }
-       }
-}
+       if (!mono_debug_enabled ())
+               mono_debug_init (MONO_DEBUG_FORMAT_MONO);
 
-void 
-mono_profiler_method_free (MonoMethod *method)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_free)
-                       prof->method_free (prof->profiler, method);
-       }
+       return mono_profiler_state.code_coverage = TRUE;
 }
 
-void
-mono_profiler_method_start_invoke (MonoMethod *method)
+static void
+coverage_lock (void)
 {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_start_invoke)
-                       prof->method_start_invoke (prof->profiler, method);
-       }
+       mono_os_mutex_lock (&mono_profiler_state.coverage_mutex);
 }
 
-void
-mono_profiler_method_end_invoke (MonoMethod *method)
+static void
+coverage_unlock (void)
 {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_end_invoke)
-                       prof->method_end_invoke (prof->profiler, method);
-       }
+       mono_os_mutex_unlock (&mono_profiler_state.coverage_mutex);
 }
 
-/**
- * mono_profiler_code_transition:
- */
-void 
-mono_profiler_code_transition (MonoMethod *method, int result)
+mono_bool
+mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb)
 {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_TRANSITIONS) && prof->man_unman_transition)
-                       prof->man_unman_transition (prof->profiler, method, result);
-       }
-}
+       if (!mono_profiler_state.code_coverage)
+               return FALSE;
 
-/**
- * mono_profiler_allocation:
- */
-void 
-mono_profiler_allocation (MonoObject *obj)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_ALLOCATIONS) && prof->allocation_cb)
-                       prof->allocation_cb (prof->profiler, obj, obj->vtable->klass);
-       }
-}
+       coverage_lock ();
 
-void
-mono_profiler_monitor_event      (MonoObject *obj, MonoProfilerMonitorEvent event) {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_MONITOR_EVENTS) && prof->monitor_event_cb)
-                       prof->monitor_event_cb (prof->profiler, obj, event);
-       }
-}
+       MonoProfilerCoverageInfo *info = g_hash_table_lookup (mono_profiler_state.coverage_hash, method);
 
-/**
- * mono_profiler_stat_hit:
- */
-void
-mono_profiler_stat_hit (guchar *ip, void *context)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_STATISTICAL) && prof->statistical_cb)
-                       prof->statistical_cb (prof->profiler, ip, context);
-       }
-}
+       coverage_unlock ();
 
-void
-mono_profiler_stat_call_chain (int call_chain_depth, guchar **ips, void *context)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_STATISTICAL) && prof->statistical_call_chain_cb)
-                       prof->statistical_call_chain_cb (prof->profiler, call_chain_depth, ips, context);
-       }
-}
+       MonoError error;
+       MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
+       mono_error_assert_ok (&error);
 
-void
-mono_profiler_exception_thrown (MonoObject *exception)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_EXCEPTIONS) && prof->exception_throw_cb)
-                       prof->exception_throw_cb (prof->profiler, exception);
-       }
-}
+       guint32 size;
 
-void
-mono_profiler_exception_method_leave (MonoMethod *method)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_EXCEPTIONS) && prof->exception_method_leave_cb)
-                       prof->exception_method_leave_cb (prof->profiler, method);
-       }
-}
+       const unsigned char *start = mono_method_header_get_code (header, &size, NULL);
+       const unsigned char *end = start + size;
+       MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
 
-void
-mono_profiler_exception_clause_handler (MonoMethod *method, int clause_type, int clause_num, MonoObject *exc)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if (prof->events & MONO_PROFILE_EXCEPTIONS) {
-                       if (prof->exception_clause_cb)
-                               prof->exception_clause_cb (prof->profiler, method, clause_type, clause_num);
-
-                       if (prof->exception_clause_cb2)
-                               prof->exception_clause_cb2 (prof->profiler, method, clause_type, clause_num, exc);
-               }
-       }
-}
+       if (!info) {
+               char *source_file;
+               int i, n_il_offsets;
+               int *source_files;
+               GPtrArray *source_file_list;
+               MonoSymSeqPoint *sym_seq_points;
 
-/**
- * mono_profiler_thread_start:
- */
-void
-mono_profiler_thread_start (gsize tid)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_start)
-                       prof->thread_start (prof->profiler, tid);
-       }
-}
+               /* Return 0 counts for all locations */
 
-/**
- * mono_profiler_thread_end:
- */
-void 
-mono_profiler_thread_end (gsize tid)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_end)
-                       prof->thread_end (prof->profiler, tid);
-       }
-}
+               mono_debug_get_seq_points (minfo, &source_file, &source_file_list, &source_files, &sym_seq_points, &n_il_offsets);
+               for (i = 0; i < n_il_offsets; ++i) {
+                       MonoSymSeqPoint *sp = &sym_seq_points [i];
+                       const char *srcfile = "";
 
-void
-mono_profiler_thread_name (gsize tid, const char *name)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_name)
-                       prof->thread_name (prof->profiler, tid, name);
-       }
-}
+                       if (source_files [i] != -1) {
+                               MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, source_files [i]);
+                               srcfile = sinfo->source_file;
+                       }
 
-/**
- * mono_profiler_assembly_event:
- */
-void 
-mono_profiler_assembly_event  (MonoAssembly *assembly, int code)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if (!(prof->events & MONO_PROFILE_ASSEMBLY_EVENTS))
-                       continue;
-
-               switch (code) {
-               case MONO_PROFILE_START_LOAD:
-                       if (prof->assembly_start_load)
-                               prof->assembly_start_load (prof->profiler, assembly);
-                       break;
-               case MONO_PROFILE_START_UNLOAD:
-                       if (prof->assembly_start_unload)
-                               prof->assembly_start_unload (prof->profiler, assembly);
-                       break;
-               case MONO_PROFILE_END_UNLOAD:
-                       if (prof->assembly_end_unload)
-                               prof->assembly_end_unload (prof->profiler, assembly);
-                       break;
-               default:
-                       g_assert_not_reached ();
+                       MonoProfilerCoverageData data = {
+                               .method = method,
+                               .il_offset = sp->il_offset,
+                               .counter = 0,
+                               .file_name = srcfile,
+                               .line = sp->line,
+                               .column = 0,
+                       };
+
+                       cb (handle->prof, &data);
                }
-       }
-}
 
-/**
- * mono_profiler_assembly_loaded:
- */
-void 
-mono_profiler_assembly_loaded (MonoAssembly *assembly, int result)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_ASSEMBLY_EVENTS) && prof->assembly_end_load)
-                       prof->assembly_end_load (prof->profiler, assembly, result);
-       }
-}
+               g_free (source_files);
+               g_free (sym_seq_points);
+               g_ptr_array_free (source_file_list, TRUE);
 
-void mono_profiler_iomap (char *report, const char *pathname, const char *new_pathname)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_IOMAP_EVENTS) && prof->iomap_cb)
-                       prof->iomap_cb (prof->profiler, report, pathname, new_pathname);
+               mono_metadata_free_mh (header);
+               return TRUE;
        }
-}
 
-/**
- * mono_profiler_module_event:
- */
-void 
-mono_profiler_module_event  (MonoImage *module, int code)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if (!(prof->events & MONO_PROFILE_MODULE_EVENTS))
-                       continue;
-
-               switch (code) {
-               case MONO_PROFILE_START_LOAD:
-                       if (prof->module_start_load)
-                               prof->module_start_load (prof->profiler, module);
-                       break;
-               case MONO_PROFILE_START_UNLOAD:
-                       if (prof->module_start_unload)
-                               prof->module_start_unload (prof->profiler, module);
-                       break;
-               case MONO_PROFILE_END_UNLOAD:
-                       if (prof->module_end_unload)
-                               prof->module_end_unload (prof->profiler, module);
-                       break;
-               default:
-                       g_assert_not_reached ();
-               }
-       }
-}
+       for (guint32 i = 0; i < info->entries; i++) {
+               guchar *cil_code = info->data [i].cil_code;
 
-/**
- * mono_profiler_module_loaded:
- */
-void 
-mono_profiler_module_loaded (MonoImage *module, int result)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_MODULE_EVENTS) && prof->module_end_load)
-                       prof->module_end_load (prof->profiler, module, result);
-       }
-}
+               if (cil_code && cil_code >= start && cil_code < end) {
+                       guint32 offset = cil_code - start;
 
-/**
- * mono_profiler_class_event:
- */
-void 
-mono_profiler_class_event  (MonoClass *klass, int code)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if (!(prof->events & MONO_PROFILE_CLASS_EVENTS))
-                       continue;
-
-               switch (code) {
-               case MONO_PROFILE_START_LOAD:
-                       if (prof->class_start_load)
-                               prof->class_start_load (prof->profiler, klass);
-                       break;
-               case MONO_PROFILE_START_UNLOAD:
-                       if (prof->class_start_unload)
-                               prof->class_start_unload (prof->profiler, klass);
-                       break;
-               case MONO_PROFILE_END_UNLOAD:
-                       if (prof->class_end_unload)
-                               prof->class_end_unload (prof->profiler, klass);
-                       break;
-               default:
-                       g_assert_not_reached ();
-               }
-       }
-}
+                       MonoProfilerCoverageData data = {
+                               .method = method,
+                               .il_offset = offset,
+                               .counter = info->data [i].count,
+                               .line = 1,
+                               .column = 1,
+                       };
 
-/**
- * mono_profiler_class_loaded:
- */
-void 
-mono_profiler_class_loaded (MonoClass *klass, int result)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_CLASS_EVENTS) && prof->class_end_load)
-                       prof->class_end_load (prof->profiler, klass, result);
-       }
-}
+                       if (minfo) {
+                               MonoDebugSourceLocation *loc = mono_debug_method_lookup_location (minfo, offset);
 
-/**
- * mono_profiler_appdomain_event:
- */
-void 
-mono_profiler_appdomain_event  (MonoDomain *domain, int code)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if (!(prof->events & MONO_PROFILE_APPDOMAIN_EVENTS))
-                       continue;
-
-               switch (code) {
-               case MONO_PROFILE_START_LOAD:
-                       if (prof->domain_start_load)
-                               prof->domain_start_load (prof->profiler, domain);
-                       break;
-               case MONO_PROFILE_START_UNLOAD:
-                       if (prof->domain_start_unload)
-                               prof->domain_start_unload (prof->profiler, domain);
-                       break;
-               case MONO_PROFILE_END_UNLOAD:
-                       if (prof->domain_end_unload)
-                               prof->domain_end_unload (prof->profiler, domain);
-                       break;
-               default:
-                       g_assert_not_reached ();
+                               if (loc) {
+                                       data.file_name = g_strdup (loc->source_file);
+                                       data.line = loc->row;
+                                       data.column = loc->column;
+
+                                       mono_debug_free_source_location (loc);
+                               }
+                       }
+
+                       cb (handle->prof, &data);
+
+                       g_free ((char *) data.file_name);
                }
        }
-}
 
-/**
- * mono_profiler_appdomain_loaded:
- */
-void 
-mono_profiler_appdomain_loaded (MonoDomain *domain, int result)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_APPDOMAIN_EVENTS) && prof->domain_end_load)
-                       prof->domain_end_load (prof->profiler, domain, result);
-       }
-}
+       mono_metadata_free_mh (header);
 
-void
-mono_profiler_appdomain_name (MonoDomain *domain, const char *name)
-{
-       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
-               if ((prof->events & MONO_PROFILE_APPDOMAIN_EVENTS) && prof->domain_name)
-                       prof->domain_name (prof->profiler, domain, name);
+       return TRUE;
 }
 
-void
-mono_profiler_context_loaded (MonoAppContext *context)
+MonoProfilerCoverageInfo *
+mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries)
 {
-       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
-               if ((prof->events & MONO_PROFILE_CONTEXT_EVENTS) && prof->context_load)
-                       prof->context_load (prof->profiler, context);
-}
+       if (!mono_profiler_state.code_coverage)
+               return FALSE;
 
-void
-mono_profiler_context_unloaded (MonoAppContext *context)
-{
-       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
-               if ((prof->events & MONO_PROFILE_CONTEXT_EVENTS) && prof->context_unload)
-                       prof->context_unload (prof->profiler, context);
-}
+       if (method->wrapper_type)
+               return FALSE;
 
-/**
- * mono_profiler_shutdown:
- */
-void 
-mono_profiler_shutdown (void)
-{
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if (prof->shutdown_callback)
-                       prof->shutdown_callback (prof->profiler);
+       gboolean cover = FALSE;
+
+       for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
+               MonoProfilerCoverageFilterCallback cb = handle->coverage_filter;
+
+               if (cb)
+                       cover |= cb (handle->prof, method);
        }
 
-       mono_profiler_set_events ((MonoProfileFlags)0);
+       if (!cover)
+               return NULL;
+
+       coverage_lock ();
+
+       MonoProfilerCoverageInfo *info = g_malloc0 (sizeof (MonoProfilerCoverageInfo) + SIZEOF_VOID_P * 2 * entries);
+
+       info->entries = entries;
+
+       g_hash_table_insert (mono_profiler_state.coverage_hash, method, info);
+
+       coverage_unlock ();
+
+       return info;
 }
 
-/**
- * mono_profiler_gc_heap_resize:
- */
-void
-mono_profiler_gc_heap_resize (gint64 new_size)
+mono_bool
+mono_profiler_enable_sampling (MonoProfilerHandle handle)
 {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_GC) && prof->gc_heap_resize)
-                       prof->gc_heap_resize (prof->profiler, new_size);
-       }
+       if (mono_profiler_state.startup_done)
+               return FALSE;
+
+       if (mono_profiler_state.sampling_owner)
+               return TRUE;
+
+       mono_profiler_state.sampling_owner = handle;
+       mono_profiler_state.sample_mode = MONO_PROFILER_SAMPLE_MODE_NONE;
+       mono_profiler_state.sample_freq = 100;
+       mono_os_sem_init (&mono_profiler_state.sampling_semaphore, 0);
+
+       return TRUE;
 }
 
-/**
- * mono_profiler_gc_event:
- */
-void
-mono_profiler_gc_event (MonoGCEvent event, int generation)
+mono_bool
+mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint32_t freq)
 {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_GC) && prof->gc_event)
-                       prof->gc_event (prof->profiler, event, generation);
-       }
+       if (handle != mono_profiler_state.sampling_owner)
+               return FALSE;
+
+       mono_profiler_state.sample_mode = mode;
+       mono_profiler_state.sample_freq = freq;
+
+       mono_profiler_sampling_thread_post ();
+
+       return TRUE;
 }
 
-void
-mono_profiler_gc_moves (void **objects, int num)
+mono_bool
+mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint32_t *freq)
 {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_GC_MOVES) && prof->gc_moves)
-                       prof->gc_moves (prof->profiler, objects, num);
-       }
+       if (mode)
+               *mode = mono_profiler_state.sample_mode;
+
+       if (freq)
+               *freq = mono_profiler_state.sample_freq;
+
+       return handle == mono_profiler_state.sampling_owner;
 }
 
-void
-mono_profiler_gc_handle (int op, int type, uintptr_t handle, MonoObject *obj)
+gboolean
+mono_profiler_sampling_enabled (void)
 {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_GC_ROOTS) && prof->gc_handle)
-                       prof->gc_handle (prof->profiler, op, type, handle, obj);
-       }
+       return !!mono_profiler_state.sampling_owner;
 }
 
 void
-mono_profiler_gc_roots (int num, void **objects, int *root_types, uintptr_t *extra_info)
+mono_profiler_sampling_thread_post (void)
 {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if ((prof->events & MONO_PROFILE_GC_ROOTS) && prof->gc_roots)
-                       prof->gc_roots (prof->profiler, num, objects, root_types, extra_info);
-       }
+       mono_os_sem_post (&mono_profiler_state.sampling_semaphore);
 }
 
-/**
- * mono_profiler_install_gc:
- */
 void
-mono_profiler_install_gc (MonoProfileGCFunc callback, MonoProfileGCResizeFunc heap_resize_callback)
+mono_profiler_sampling_thread_wait (void)
 {
-       if (!prof_list)
-               return;
-       prof_list->gc_event = callback;
-       prof_list->gc_heap_resize = heap_resize_callback;
+       mono_os_sem_wait (&mono_profiler_state.sampling_semaphore, MONO_SEM_FLAGS_NONE);
 }
 
-/**
- * mono_profiler_install_gc_moves:
- * \param callback callback function
- *
- * Install the \p callback function that the GC will call when moving objects.
- * The callback receives an array of pointers and the number of elements
- * in the array. Every even element in the array is the original object location
- * and the following odd element is the new location of the object in memory.
- * So the number of elements argument will always be a multiple of 2.
- * Since this callback happens during the GC, it is a restricted environment:
- * no locks can be taken and the object pointers can be inspected only once
- * the GC is finished (of course the original location pointers will not
- * point to valid objects anymore).
- */
-void
-mono_profiler_install_gc_moves (MonoProfileGCMoveFunc callback)
+mono_bool
+mono_profiler_enable_allocations (void)
 {
-       if (!prof_list)
-               return;
-       prof_list->gc_moves = callback;
+       if (mono_profiler_state.startup_done)
+               return FALSE;
+
+       return mono_profiler_state.allocations = TRUE;
 }
 
-/**
- * mono_profiler_install_gc_roots:
- * \param handle_callback callback function
- * \param roots_callback callback function
- *
- * Install the \p handle_callback function that the GC will call when GC
- * handles are created or destroyed.
- * The callback receives an operation, which is either \c MONO_PROFILER_GC_HANDLE_CREATED
- * or \c MONO_PROFILER_GC_HANDLE_DESTROYED, the handle type, the handle value and the
- * object pointer, if present.
- * Install the \p roots_callback function that the GC will call when tracing
- * the roots for a collection.
- * The callback receives the number of elements and three arrays: an array
- * of objects, an array of root types and flags and an array of extra info.
- * The size of each array is given by the first argument.
- */
 void
-mono_profiler_install_gc_roots (MonoProfileGCHandleFunc handle_callback, MonoProfileGCRootFunc roots_callback)
+mono_profiler_set_call_instrumentation_filter_callback (MonoProfilerHandle handle, MonoProfilerCallInstrumentationFilterCallback cb)
 {
-       if (!prof_list)
-               return;
-       prof_list->gc_handle = handle_callback;
-       prof_list->gc_roots = roots_callback;
+       InterlockedWritePointer (&handle->call_instrumentation_filter, (gpointer) cb);
 }
 
-void
-mono_profiler_gc_finalize_begin (void)
+mono_bool
+mono_profiler_enable_call_context_introspection (void)
 {
-       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
-               if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_begin)
-                       prof->gc_finalize_begin (prof->profiler);
+       if (mono_profiler_state.startup_done)
+               return FALSE;
+
+       mono_profiler_state.context_enable ();
+
+       return mono_profiler_state.call_contexts = TRUE;
 }
 
-void
-mono_profiler_gc_finalize_object_begin (MonoObject *obj)
+void *
+mono_profiler_call_context_get_this (MonoProfilerCallContext *context)
 {
-       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
-               if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_object_begin)
-                       prof->gc_finalize_object_begin (prof->profiler, obj);
+       if (!mono_profiler_state.call_contexts)
+               return NULL;
+
+       return mono_profiler_state.context_get_this (context);
 }
 
-void
-mono_profiler_gc_finalize_object_end (MonoObject *obj)
+void *
+mono_profiler_call_context_get_argument (MonoProfilerCallContext *context, uint32_t position)
 {
-       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
-               if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_object_end)
-                       prof->gc_finalize_object_end (prof->profiler, obj);
+       if (!mono_profiler_state.call_contexts)
+               return NULL;
+
+       return mono_profiler_state.context_get_argument (context, position);
 }
 
-void
-mono_profiler_gc_finalize_end (void)
+void *
+mono_profiler_call_context_get_local (MonoProfilerCallContext *context, uint32_t position)
 {
-       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
-               if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_end)
-                       prof->gc_finalize_end (prof->profiler);
+       if (!mono_profiler_state.call_contexts)
+               return NULL;
+
+       return mono_profiler_state.context_get_local (context, position);
 }
 
-void
-mono_profiler_install_gc_finalize (MonoProfileGCFinalizeFunc begin, MonoProfileGCFinalizeObjectFunc begin_obj, MonoProfileGCFinalizeObjectFunc end_obj, MonoProfileGCFinalizeFunc end)
+void *
+mono_profiler_call_context_get_result (MonoProfilerCallContext *context)
 {
-       if (!prof_list)
-               return;
+       if (!mono_profiler_state.call_contexts)
+               return NULL;
 
-       prof_list->gc_finalize_begin = begin;
-       prof_list->gc_finalize_object_begin = begin_obj;
-       prof_list->gc_finalize_object_end = end_obj;
-       prof_list->gc_finalize_end = end;
+       return mono_profiler_state.context_get_result (context);
 }
 
 void
-mono_profiler_install_runtime_initialized (MonoProfileFunc runtime_initialized_callback)
+mono_profiler_call_context_free_buffer (void *buffer)
 {
-       if (!prof_list)
-               return;
-       prof_list->runtime_initialized_event = runtime_initialized_callback;
+       mono_profiler_state.context_free_buffer (buffer);
 }
 
-void
-mono_profiler_runtime_initialized (void) {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if (prof->runtime_initialized_event)
-                       prof->runtime_initialized_event (prof->profiler);
-       }
-}
+MonoProfilerCallInstrumentationFlags
+mono_profiler_get_call_instrumentation_flags (MonoMethod *method)
+{
+       MonoProfilerCallInstrumentationFlags flags = MONO_PROFILER_CALL_INSTRUMENTATION_NONE;
 
-void
-mono_profiler_install_code_chunk_new (MonoProfilerCodeChunkNew callback) {
-       if (!prof_list)
-               return;
-       prof_list->code_chunk_new = callback;
-}
-void
-mono_profiler_code_chunk_new (gpointer chunk, int size) {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if (prof->code_chunk_new)
-                       prof->code_chunk_new (prof->profiler, chunk, size);
-       }
-}
+       for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
+               MonoProfilerCallInstrumentationFilterCallback cb = handle->call_instrumentation_filter;
 
-void
-mono_profiler_install_code_chunk_destroy (MonoProfilerCodeChunkDestroy callback) {
-       if (!prof_list)
-               return;
-       prof_list->code_chunk_destroy = callback;
-}
-void
-mono_profiler_code_chunk_destroy (gpointer chunk) {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if (prof->code_chunk_destroy)
-                       prof->code_chunk_destroy (prof->profiler, chunk);
+               if (cb)
+                       flags |= cb (handle->prof, method);
        }
-}
 
-void
-mono_profiler_install_code_buffer_new (MonoProfilerCodeBufferNew callback) {
-       if (!prof_list)
-               return;
-       prof_list->code_buffer_new = callback;
+       return flags;
 }
 
 void
-mono_profiler_install_iomap (MonoProfileIomapFunc callback)
+mono_profiler_started (void)
 {
-       if (!prof_list)
-               return;
-       prof_list->iomap_cb = callback;
+       mono_profiler_state.startup_done = TRUE;
 }
 
 void
-mono_profiler_code_buffer_new (gpointer buffer, int size, MonoProfilerCodeBufferType type, gconstpointer data) {
-       ProfilerDesc *prof;
-       for (prof = prof_list; prof; prof = prof->next) {
-               if (prof->code_buffer_new)
-                       prof->code_buffer_new (prof->profiler, buffer, size, type, (void*)data);
+mono_profiler_cleanup (void)
+{
+       for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
+#define _MONO_PROFILER_EVENT(name) \
+       mono_profiler_set_ ## name ## _callback (handle, NULL); \
+       g_assert (!handle->name ## _cb);
+#define MONO_PROFILER_EVENT_0(name, type) \
+       _MONO_PROFILER_EVENT(name)
+#define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
+       _MONO_PROFILER_EVENT(name)
+#define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
+       _MONO_PROFILER_EVENT(name)
+#define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
+       _MONO_PROFILER_EVENT(name)
+#define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
+       _MONO_PROFILER_EVENT(name)
+#include <mono/metadata/profiler-events.h>
+#undef MONO_PROFILER_EVENT_0
+#undef MONO_PROFILER_EVENT_1
+#undef MONO_PROFILER_EVENT_2
+#undef MONO_PROFILER_EVENT_3
+#undef MONO_PROFILER_EVENT_4
+#undef _MONO_PROFILER_EVENT
        }
-}
 
-static GHashTable *coverage_hash = NULL;
+#define _MONO_PROFILER_EVENT(name, type) \
+       g_assert (!mono_profiler_state.name ## _count);
+#define MONO_PROFILER_EVENT_0(name, type) \
+       _MONO_PROFILER_EVENT(name, type)
+#define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
+       _MONO_PROFILER_EVENT(name, type)
+#define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
+       _MONO_PROFILER_EVENT(name, type)
+#define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
+       _MONO_PROFILER_EVENT(name, type)
+#define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
+       _MONO_PROFILER_EVENT(name, type)
+#include <mono/metadata/profiler-events.h>
+#undef MONO_PROFILER_EVENT_0
+#undef MONO_PROFILER_EVENT_1
+#undef MONO_PROFILER_EVENT_2
+#undef MONO_PROFILER_EVENT_3
+#undef MONO_PROFILER_EVENT_4
+#undef _MONO_PROFILER_EVENT
 
-MonoProfileCoverageInfo* 
-mono_profiler_coverage_alloc (MonoMethod *method, int entries)
-{
-       MonoProfileCoverageInfo *res;
-       int instrument = FALSE;
-       ProfilerDesc *prof;
-
-       for (prof = prof_list; prof; prof = prof->next) {
-               /* note that we call the filter on all the profilers even if just
-                * a single one would be enough to instrument a method
-                */
-               if (prof->coverage_filter_cb)
-                       if (prof->coverage_filter_cb (prof->profiler, method))
-                               instrument = TRUE;
+       MonoProfilerHandle head = mono_profiler_state.profilers;
+
+       while (head) {
+               MonoProfilerCleanupCallback cb = head->cleanup_callback;
+
+               if (cb)
+                       cb (head->prof);
+
+               MonoProfilerHandle cur = head;
+               head = head->next;
+
+               g_free (cur);
        }
-       if (!instrument)
-               return NULL;
 
-       mono_profiler_coverage_lock ();
-       if (!coverage_hash)
-               coverage_hash = g_hash_table_new (NULL, NULL);
+       if (mono_profiler_state.code_coverage) {
+               mono_os_mutex_destroy (&mono_profiler_state.coverage_mutex);
+
+               GHashTableIter iter;
 
-       res = (MonoProfileCoverageInfo *)g_malloc0 (sizeof (MonoProfileCoverageInfo) + sizeof (void*) * 2 * entries);
+               g_hash_table_iter_init (&iter, mono_profiler_state.coverage_hash);
 
-       res->entries = entries;
+               MonoProfilerCoverageInfo *info;
 
-       g_hash_table_insert (coverage_hash, method, res);
-       mono_profiler_coverage_unlock ();
+               while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info))
+                       g_free (info);
 
-       return res;
+               g_hash_table_destroy (mono_profiler_state.coverage_hash);
+       }
+
+       if (mono_profiler_state.sampling_owner)
+               mono_os_sem_destroy (&mono_profiler_state.sampling_semaphore);
 }
 
-/* safe only when the method antive code has been unloaded */
-void
-mono_profiler_coverage_free (MonoMethod *method)
+static void
+update_callback (volatile gpointer *location, gpointer new_, volatile gint32 *counter)
 {
-       MonoProfileCoverageInfo* info;
+       gpointer old;
 
-       mono_profiler_coverage_lock ();
-       if (!coverage_hash) {
-               mono_profiler_coverage_unlock ();
-               return;
-       }
+       do {
+               old = InterlockedReadPointer (location);
+       } while (InterlockedCompareExchangePointer (location, new_, old) != old);
 
-       info = (MonoProfileCoverageInfo *)g_hash_table_lookup (coverage_hash, method);
-       if (info) {
-               g_free (info);
-               g_hash_table_remove (coverage_hash, method);
-       }
-       mono_profiler_coverage_unlock ();
-}
+       /*
+        * At this point, we could have installed a NULL callback while the counter
+        * is still non-zero, i.e. setting the callback and modifying the counter
+        * is not a single atomic operation. This is fine as we make sure callbacks
+        * are non-NULL before invoking them (see the code below that generates the
+        * raise functions), and besides, updating callbacks at runtime is an
+        * inherently racy operation.
+        */
 
-/**
- * mono_profiler_coverage_get:
- * \param prof The profiler handle, installed with mono_profiler_install
- * \param method the method to gather information from.
- * \param func A routine that will be called back with the results
- *
- * If the \c MONO_PROFILER_INS_COVERAGE flag was active during JIT compilation
- * it is possible to obtain coverage information about a give method.
+       if (old)
+               InterlockedDecrement (counter);
+
+       if (new_)
+               InterlockedIncrement (counter);
+}
+
+#define _MONO_PROFILER_EVENT(name, type) \
+       void \
+       mono_profiler_set_ ## name ## _callback (MonoProfilerHandle handle, MonoProfiler ## type ## Callback cb) \
+       { \
+               update_callback (&handle->name ## _cb, (gpointer) cb, &mono_profiler_state.name ## _count); \
+       }
+#define MONO_PROFILER_EVENT_0(name, type) \
+       _MONO_PROFILER_EVENT(name, type)
+#define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
+       _MONO_PROFILER_EVENT(name, type)
+#define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
+       _MONO_PROFILER_EVENT(name, type)
+#define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
+       _MONO_PROFILER_EVENT(name, type)
+#define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
+       _MONO_PROFILER_EVENT(name, type)
+#include <mono/metadata/profiler-events.h>
+#undef MONO_PROFILER_EVENT_0
+#undef MONO_PROFILER_EVENT_1
+#undef MONO_PROFILER_EVENT_2
+#undef MONO_PROFILER_EVENT_3
+#undef MONO_PROFILER_EVENT_4
+#undef _MONO_PROFILER_EVENT
+
+#define _MONO_PROFILER_EVENT(name, type, params, args) \
+       void \
+       mono_profiler_raise_ ## name params \
+       { \
+               for (MonoProfilerHandle h = mono_profiler_state.profilers; h; h = h->next) { \
+                       MonoProfiler ## type ## Callback cb = h->name ## _cb; \
+                       if (cb) \
+                               cb args; \
+               } \
+       }
+#define MONO_PROFILER_EVENT_0(name, type) \
+       _MONO_PROFILER_EVENT(name, type, (void), (h->prof))
+#define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
+       _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name), (h->prof, arg1_name))
+#define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
+       _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name), (h->prof, arg1_name, arg2_name))
+#define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
+       _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))
+#define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
+       _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))
+#include <mono/metadata/profiler-events.h>
+#undef MONO_PROFILER_EVENT_0
+#undef MONO_PROFILER_EVENT_1
+#undef MONO_PROFILER_EVENT_2
+#undef MONO_PROFILER_EVENT_3
+#undef MONO_PROFILER_EVENT_4
+#undef _MONO_PROFILER_EVENT
+
+/*
+ * The following code is here to maintain compatibility with a few profiler API
+ * functions used by Xamarin.{Android,iOS,Mac} so that they keep working
+ * regardless of which system Mono version is used.
  *
- * The function \p func will be invoked repeatedly with instances of the
- * \c MonoProfileCoverageEntry structure.
+ * TODO: Remove this some day if we're OK with breaking compatibility.
  */
-void 
-mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileCoverageFunc func)
-{
-       MonoError error;
-       MonoProfileCoverageInfo* info = NULL;
-       int i, offset;
-       guint32 code_size;
-       const unsigned char *start, *end, *cil_code;
-       MonoMethodHeader *header;
-       MonoProfileCoverageEntry entry;
-       MonoDebugMethodInfo *debug_minfo;
-
-       mono_profiler_coverage_lock ();
-       if (coverage_hash)
-               info = (MonoProfileCoverageInfo *)g_hash_table_lookup (coverage_hash, method);
-       mono_profiler_coverage_unlock ();
-
-       if (!info)
-               return;
-
-       header = mono_method_get_header_checked (method, &error);
-       mono_error_assert_ok (&error);
-       start = mono_method_header_get_code (header, &code_size, NULL);
-       debug_minfo = mono_debug_lookup_method (method);
 
-       end = start + code_size;
-       for (i = 0; i < info->entries; ++i) {
-               cil_code = info->data [i].cil_code;
-               if (cil_code && cil_code >= start && cil_code < end) {
-                       char *fname = NULL;
-                       offset = cil_code - start;
-                       entry.iloffset = offset;
-                       entry.method = method;
-                       entry.counter = info->data [i].count;
-                       entry.line = entry.col = 1;
-                       entry.filename = NULL;
-                       if (debug_minfo) {
-                               MonoDebugSourceLocation *location;
-
-                               location = mono_debug_method_lookup_location (debug_minfo, offset);
-                               if (location) {
-                                       entry.line = location->row;
-                                       entry.col = location->column;
-                                       entry.filename = fname = g_strdup (location->source_file);
-                                       mono_debug_free_source_location (location);
-                               }
-                       }
+typedef void *MonoLegacyProfiler;
 
-                       func (prof, &entry);
-                       g_free (fname);
-               }
-       }
-       mono_metadata_free_mh (header);
-}
+typedef void (*MonoLegacyProfileFunc) (MonoLegacyProfiler *prof);
+typedef void (*MonoLegacyProfileThreadFunc) (MonoLegacyProfiler *prof, uintptr_t tid);
+typedef void (*MonoLegacyProfileGCFunc) (MonoLegacyProfiler *prof, MonoProfilerGCEvent event, int generation);
+typedef void (*MonoLegacyProfileGCResizeFunc) (MonoLegacyProfiler *prof, int64_t new_size);
+typedef void (*MonoLegacyProfileJitResult) (MonoLegacyProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result);
 
-typedef void (*ProfilerInitializer) (const char*);
-#define INITIALIZER_NAME "mono_profiler_startup"
+struct _MonoProfiler {
+       MonoProfilerHandle handle;
+       MonoLegacyProfiler *profiler;
+       MonoLegacyProfileFunc shutdown_callback;
+       MonoLegacyProfileThreadFunc thread_start, thread_end;
+       MonoLegacyProfileGCFunc gc_event;
+       MonoLegacyProfileGCResizeFunc gc_heap_resize;
+       MonoLegacyProfileJitResult jit_end2;
+};
 
+static MonoProfiler *current;
 
-static gboolean
-load_profiler (MonoDl *pmodule, const char *desc, const char *symbol)
+MONO_API void mono_profiler_install (MonoLegacyProfiler *prof, MonoLegacyProfileFunc callback);
+MONO_API void mono_profiler_install_thread (MonoLegacyProfileThreadFunc start, MonoLegacyProfileThreadFunc end);
+MONO_API void mono_profiler_install_gc (MonoLegacyProfileGCFunc callback, MonoLegacyProfileGCResizeFunc heap_resize_callback);
+MONO_API void mono_profiler_install_jit_end (MonoLegacyProfileJitResult end);
+MONO_API void mono_profiler_set_events (int flags);
+
+static void
+shutdown_cb (MonoProfiler *prof)
 {
-       char *err;
-       ProfilerInitializer func;
+       prof->shutdown_callback (prof->profiler);
+}
 
-       if (!pmodule)
-               return FALSE;
+void
+mono_profiler_install (MonoLegacyProfiler *prof, MonoLegacyProfileFunc callback)
+{
+       current = g_new0 (MonoProfiler, 1);
+       current->handle = mono_profiler_create (current);
+       current->profiler = prof;
+       current->shutdown_callback = callback;
 
-       if ((err = mono_dl_symbol (pmodule, symbol, (gpointer *) &func))) {
-               g_free (err);
-               return FALSE;
-       } else {
-               func (desc);
-       }
-       return TRUE;
+       if (callback)
+               mono_profiler_set_runtime_shutdown_end_callback (current->handle, shutdown_cb);
 }
 
-static gboolean
-load_embedded_profiler (const char *desc, const char *name)
+static void
+thread_start_cb (MonoProfiler *prof, uintptr_t tid)
 {
-       char *err = NULL;
-       char *symbol;
-       MonoDl *pmodule = NULL;
-       gboolean result;
+       prof->thread_start (prof->profiler, tid);
+}
 
-       /*
-        * Some profilers (such as ours) may need to call back into the runtime
-        * from their sampling callback (which is called in async-signal context).
-        * They need to be able to know that all references back to the runtime
-        * have been resolved; otherwise, calling runtime functions may result in
-        * invoking the dynamic linker which is not async-signal-safe. Passing
-        * MONO_DL_EAGER will ask the dynamic linker to resolve everything upfront.
-        */
-       pmodule = mono_dl_open (NULL, MONO_DL_EAGER, &err);
-       if (!pmodule) {
-               g_warning ("Could not open main executable (%s)", err);
-               g_free (err);
-               return FALSE;
-       }
+static void
+thread_stop_cb (MonoProfiler *prof, uintptr_t tid)
+{
+       prof->thread_end (prof->profiler, tid);
+}
+
+void
+mono_profiler_install_thread (MonoLegacyProfileThreadFunc start, MonoLegacyProfileThreadFunc end)
+{
+       current->thread_start = start;
+       current->thread_end = end;
 
-       symbol = g_strdup_printf (INITIALIZER_NAME "_%s", name);
-       result = load_profiler (pmodule, desc, symbol);
-       g_free (symbol);
+       if (start)
+               mono_profiler_set_thread_started_callback (current->handle, thread_start_cb);
 
-       return result;
+       if (end)
+               mono_profiler_set_thread_stopped_callback (current->handle, thread_stop_cb);
 }
 
-// TODO: Much of the library loading code here is custom. It would be better to merge this with mono-dl
-static gboolean
-load_profiler_from_directory (const char *directory, const char *libname, const char *desc)
+static void
+gc_event_cb (MonoProfiler *prof, MonoProfilerGCEvent event, uint32_t generation)
 {
-       MonoDl *pmodule = NULL;
-       char* path;
-       char *err;
-       void *iter;
+       prof->gc_event (prof->profiler, event, generation);
+}
 
-       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "Attempting to load profiler %s from %s (desc %s)", libname, directory, desc);
+static void
+gc_resize_cb (MonoProfiler *prof, uintptr_t size)
+{
+       prof->gc_heap_resize (prof->profiler, size);
+}
 
-       iter = NULL;
-       err = NULL;
-       while ((path = mono_dl_build_path (directory, libname, &iter))) {
-               pmodule = mono_dl_open (path, MONO_DL_EAGER, &err);
-               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "Attempting to load profiler: %s, %ssuccessful, err: %s", path, pmodule?"":"not ", err);
-               g_free (path);
-               g_free (err);
-               if (pmodule)
-                       return load_profiler (pmodule, desc, INITIALIZER_NAME);
-       }
-               
-       return FALSE;
+void
+mono_profiler_install_gc (MonoLegacyProfileGCFunc callback, MonoLegacyProfileGCResizeFunc heap_resize_callback)
+{
+       current->gc_event = callback;
+       current->gc_heap_resize = heap_resize_callback;
+
+       if (callback)
+               mono_profiler_set_gc_event_callback (current->handle, gc_event_cb);
+
+       if (heap_resize_callback)
+               mono_profiler_set_gc_resize_callback (current->handle, gc_resize_cb);
 }
 
-static gboolean
-load_profiler_from_mono_installation (const char *libname, const char *desc)
+static void
+jit_done_cb (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
 {
-       char *err = NULL;
-       MonoDl *pmodule = mono_dl_open_runtime_lib (libname, MONO_DL_EAGER, &err);
-       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "Attempting to load profiler from runtime libs: %s, %ssuccessful, err: %s", libname, pmodule?"":"not ", err);
-       g_free (err);
-       if (pmodule)
-               return load_profiler (pmodule, desc, INITIALIZER_NAME);
-       return FALSE;
+       prof->jit_end2 (prof->profiler, method, jinfo, 0);
 }
 
-/**
- * mono_profiler_load:
- * \param desc arguments to configure the profiler
- *
- * Invoke this method to initialize the profiler.   This will drive the
- * loading of the internal ("default") or any external profilers.
- *
- * This routine is invoked by Mono's driver, but must be called manually
- * if you embed Mono into your application.
- */
-void 
-mono_profiler_load (const char *desc)
+static void
+jit_failed_cb (MonoProfiler *prof, MonoMethod *method)
 {
-       char *cdesc = NULL;
-       mono_gc_base_init ();
+       prof->jit_end2 (prof->profiler, method, NULL, 1);
+}
 
-       if (!desc || (strcmp ("default", desc) == 0)) {
-               desc = "log:report";
-       }
-       /* we keep command-line compat with the old version here */
-       if (strncmp (desc, "default:", 8) == 0) {
-               gchar **args, **ptr;
-               GString *str = g_string_new ("log:report");
-               args = g_strsplit (desc + 8, ",", -1);
-               for (ptr = args; ptr && *ptr; ptr++) {
-                       const char *arg = *ptr;
-
-                       if (!strcmp (arg, "time"))
-                               g_string_append (str, ",calls");
-                       else if (!strcmp (arg, "alloc"))
-                               g_string_append (str, ",alloc");
-                       else if (!strcmp (arg, "stat"))
-                               g_string_append (str, ",sample");
-                       else if (!strcmp (arg, "jit"))
-                               continue; /* accept and do nothing */
-                       else if (strncmp (arg, "file=", 5) == 0) {
-                               g_string_append_printf (str, ",output=%s", arg + 5);
-                       } else {
-                               fprintf (stderr, "profiler : Unknown argument '%s'.\n", arg);
-                               return;
-                       }
-               }
-               desc = cdesc = g_string_free (str, FALSE);
-       }
-       {
-               const char* col = strchr (desc, ':');
-               char* libname;
-               char *mname;
-               gboolean res = FALSE;
-
-               if (col != NULL) {
-                       mname = (char *)g_memdup (desc, col - desc + 1);
-                       mname [col - desc] = 0;
-               } else {
-                       mname = g_strdup (desc);
-               }
-               if (!load_embedded_profiler (desc, mname)) {
-                       libname = g_strdup_printf ("mono-profiler-%s", mname);
-                       res = load_profiler_from_mono_installation (libname, desc);
-                       if (!res && mono_config_get_assemblies_dir ())
-                               res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, desc);
-                       if (!res)
-                               res = load_profiler_from_directory (NULL, libname, desc);
-                       if (!res)
-                               g_warning ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
-                       g_free (libname);
-               }
-               g_free (mname);
+void
+mono_profiler_install_jit_end (MonoLegacyProfileJitResult end)
+{
+       current->jit_end2 = end;
+
+       if (end) {
+               mono_profiler_set_jit_done_callback (current->handle, jit_done_cb);
+               mono_profiler_set_jit_failed_callback (current->handle, jit_failed_cb);
        }
-       g_free (cdesc);
 }
 
+void
+mono_profiler_set_events (int flags)
+{
+       /* Do nothing. */
+}