[Mono]: Add dotnet-gcdump support. (#88634)
authorJohan Lorensson <lateralusx.github@gmail.com>
Sun, 16 Jul 2023 10:50:44 +0000 (12:50 +0200)
committerGitHub <noreply@github.com>
Sun, 16 Jul 2023 10:50:44 +0000 (12:50 +0200)
Add support for dotnet-gcdump on Mono.

New GC events consumed by dotnet-gcdump has been added to the new ep-rt-mono-runtime-provider.c source file.

Disable experimental EventPipe mono profiler provider by default to preserve resources. It is possible to re-enable it by setting the following env variable, MONO_DIAGNOSTICS=--diagnostic-mono-profiler=enable.

16 files changed:
src/coreclr/scripts/genEventPipe.py
src/coreclr/scripts/genEventing.py
src/mono/mono/component/event_pipe.c
src/mono/mono/eglib/glib.h
src/mono/mono/eventpipe/ds-rt-mono.h
src/mono/mono/eventpipe/ep-rt-mono-profiler-provider.c [new file with mode: 0644]
src/mono/mono/eventpipe/ep-rt-mono-runtime-provider.c [new file with mode: 0644]
src/mono/mono/eventpipe/ep-rt-mono.c
src/mono/mono/eventpipe/ep-rt-mono.h
src/mono/mono/eventpipe/eventpipe.cmake
src/mono/mono/eventpipe/gen-eventing-event-inc.lst
src/mono/mono/sgen/sgen-gc.c
src/mono/mono/sgen/sgen-gchandles.c
src/native/eventpipe/ep-session.c
src/native/eventpipe/ep-session.h
src/native/eventpipe/ep.h

index c51f231..37acc30 100644 (file)
@@ -662,8 +662,16 @@ write_buffer_string_utf8_to_utf16_t (
     size_t *size,
     bool *fixed_buffer)
 {
-    if (!value)
+    if (!value || value_len == 0) {
+        value_len = sizeof (ep_char16_t);
+        if ((value_len + *offset) > *size)
+            ep_raise_error_if_nok (resize_buffer (buffer, size, *offset, *size + value_len, fixed_buffer));
+        (*buffer) [*offset] = 0;
+        (*offset)++;
+        (*buffer) [*offset] = 0;
+        (*offset)++;
         return true;
+    }
 
     GFixedBufferCustomAllocatorData custom_alloc_data;
     custom_alloc_data.buffer = *buffer + *offset;
@@ -695,9 +703,23 @@ write_buffer_string_utf8_t (
     bool *fixed_buffer)
 {
     if (!value)
-        return true;
+        value_len = 0;
+
+    if ((value_len + 1 + *offset) > *size)
+        ep_raise_error_if_nok (resize_buffer (buffer, size, *offset, *size + value_len + 1, fixed_buffer));
+
+    if (value_len != 0) {
+        memcpy (*buffer + *offset, value, value_len);
+        *offset += value_len;
+    }
 
-    return write_buffer ((const uint8_t *)value, (value_len + 1) * sizeof(*value), buffer, offset, size, fixed_buffer);
+    (*buffer) [*offset] = 0;
+    (*offset)++;
+
+    return true;
+
+ep_on_error:
+    return false;
 }
 
 """
index b9eaaca..cef3617 100644 (file)
@@ -731,7 +731,7 @@ typedef struct _DOTNET_TRACE_CONTEXT
 
             eventpipeProviderCtxName = providerSymbol + "_EVENTPIPE_Context"
             if is_windows:
-                Clrallevents.write(('constexpr ' if target_cpp else '') + 'EVENTPIPE_TRACE_CONTEXT ' + eventpipeProviderCtxName + ' = { W("' + providerName + '"), 0, false, 0 };\n')
+                Clrallevents.write(('constexpr ' if target_cpp else 'static const ') + 'EVENTPIPE_TRACE_CONTEXT ' + eventpipeProviderCtxName + ' = { W("' + providerName + '"), 0, false, 0 };\n')
 
             if not is_windows and not write_xplatheader:
                 Clrallevents.write('__attribute__((weak)) EVENTPIPE_TRACE_CONTEXT ' + eventpipeProviderCtxName + ' = { W("' + providerName + '"), 0, false, 0 };\n')
@@ -782,14 +782,14 @@ typedef struct _EVENT_DESCRIPTOR
                     symbolName = eventNode.getAttribute('symbol')
                     keywords = eventNode.getAttribute('keywords')
                     level = convertToLevelId(levelName)
-                    Clrproviders.write(("constexpr " if target_cpp else "const ") + "EVENT_DESCRIPTOR " + symbolName + " = { " + str(level) + ", " + hex(getKeywordsMaskCombined(keywords, keywordsToMask)) + " };\n")
+                    Clrproviders.write(("constexpr " if target_cpp else "static const ") + "EVENT_DESCRIPTOR " + symbolName + " = { " + str(level) + ", " + hex(getKeywordsMaskCombined(keywords, keywordsToMask)) + " };\n")
 
                 allProviders.append("&" + providerSymbol + "_LTTNG_Context")
 
             # define and initialize runtime providers' DOTNET_TRACE_CONTEXT depending on the platform
             if not is_windows:
                 Clrproviders.write('#define NB_PROVIDERS ' + str(nbProviders) + '\n')
-                Clrproviders.write(('constexpr ' if target_cpp else 'const ') + 'LTTNG_TRACE_CONTEXT * ALL_LTTNG_PROVIDERS_CONTEXT[NB_PROVIDERS] = { ')
+                Clrproviders.write(('constexpr ' if target_cpp else 'static const ') + 'LTTNG_TRACE_CONTEXT * ALL_LTTNG_PROVIDERS_CONTEXT[NB_PROVIDERS] = { ')
                 Clrproviders.write(', '.join(allProviders))
                 Clrproviders.write(' };\n')
 
index 398d463..1ea641b 100644 (file)
@@ -17,7 +17,6 @@
 #include <emscripten/emscripten.h>
 #endif
 
-extern void ep_rt_mono_component_init (void);
 static bool _event_pipe_component_inited = false;
 
 struct _EventPipeProviderConfigurationNative {
@@ -127,7 +126,7 @@ static MonoComponentEventPipe fn_table = {
        &ep_provider_add_event,
        &event_pipe_get_session_info,
        &event_pipe_thread_ctrl_activity_id,
-       &ep_rt_mono_write_event_ee_startup_start,
+       &ep_rt_write_event_ee_startup_start,
        &ep_rt_write_event_threadpool_worker_thread_start,
        &ep_rt_write_event_threadpool_worker_thread_stop,
        &ep_rt_write_event_threadpool_worker_thread_wait,
index 77441af..4a8a7e1 100644 (file)
@@ -1635,6 +1635,7 @@ __CAST_UTYPE_TO_STYPE(gunichar, gchar, CHAR_MIN, CHAR_MAX)
 
 #define GLONG_TO_ULONG(v)        G_CAST_TYPE_TO_TYPE(glong, gulong, v)
 #define GULONG_TO_LONG(v)        G_CAST_TYPE_TO_TYPE(gulong, glong, v)
+#define GLONG_TO_UINT32(v)       G_CAST_TYPE_TO_TYPE(glong, guint32, v)
 
 #define GDOUBLE_TO_INT64(v)      G_CAST_TYPE_TO_TYPE(gdouble, gint64, v)
 #define GDOUBLE_TO_UINT64(v)     G_CAST_TYPE_TO_TYPE(gdouble, guint64, v)
index 86898cf..541dca1 100644 (file)
@@ -214,8 +214,8 @@ static
 uint32_t
 ds_rt_set_environment_variable (const ep_char16_t *name, const ep_char16_t *value)
 {
-       gchar *nameNarrow = ep_rt_utf16le_to_utf8_string (name, ep_rt_utf16_string_len (name));
-       gchar *valueNarrow = ep_rt_utf16le_to_utf8_string (value, ep_rt_utf16_string_len (value));
+       gchar *nameNarrow = ep_rt_utf16le_to_utf8_string (name, -1);
+       gchar *valueNarrow = ep_rt_utf16le_to_utf8_string (value, -1);
 
        gboolean success = g_setenv(nameNarrow, valueNarrow, true);
 
diff --git a/src/mono/mono/eventpipe/ep-rt-mono-profiler-provider.c b/src/mono/mono/eventpipe/ep-rt-mono-profiler-provider.c
new file mode 100644 (file)
index 0000000..b18656b
--- /dev/null
@@ -0,0 +1,3194 @@
+#include <config.h>
+
+#ifdef ENABLE_PERFTRACING
+#include <eventpipe/ep-rt-config.h>
+#include <eventpipe/ep-types.h>
+#include <eventpipe/ep-rt.h>
+#include <eventpipe/ep.h>
+
+#include <mono/metadata/profiler.h>
+#include <mono/metadata/callspec.h>
+#include <mono/metadata/assembly-internals.h>
+#include <mono/sgen/sgen-conf.h>
+#include <mono/sgen/sgen-tagged-pointer.h>
+#include <clretwallmain.h>
+
+extern EVENTPIPE_TRACE_CONTEXT MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_DOTNET_Context;
+#define RUNTIME_MONO_PROFILER_PROVIDER_CONTEXT MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_DOTNET_Context
+
+// Enable/Disable mono profiler provider.
+#define DEFAULT_MONO_PROFILER_PROVIDER_ENABLED false
+static bool _mono_profiler_provider_enabled = DEFAULT_MONO_PROFILER_PROVIDER_ENABLED;
+
+// Mono profilers.
+static MonoProfilerHandle _mono_profiler_provider = NULL;
+static MonoProfilerHandle _mono_heap_dump_profiler_provider = NULL;
+
+// Profiler callspec.
+static MonoCallSpec _mono_profiler_provider_callspec = {0};
+
+// Buffered GC event types.
+typedef enum {
+       BUFFERED_GC_EVENT = 1,
+       BUFFERED_GC_EVENT_RESIZE = 2,
+       BUFFERED_GC_EVENT_ROOTS = 3,
+       BUFFERED_GC_EVENT_MOVES = 4,
+       BUFFERED_GC_EVENT_OBJECT_REF = 5,
+       BUFFERED_GC_EVENT_ROOT_REGISTER = 6,
+       BUFFERED_GC_EVENT_ROOT_UNREGISTER = 7
+} BufferedGCEventType;
+
+typedef struct _BufferedGCEvent BufferedGCEvent;
+struct _BufferedGCEvent {
+       BufferedGCEventType type;
+       uint32_t payload_size;
+};
+
+#define GC_HEAP_DUMP_DEFAULT_MEM_BLOCK_SIZE (mono_pagesize() * 16)
+#define GC_HEAP_DUMP_MEM_BLOCK_SIZE_INC (mono_pagesize())
+
+typedef struct _GCHeapDumpMemBlock GCHeapDumpMemBlock;
+struct _GCHeapDumpMemBlock {
+       GCHeapDumpMemBlock *next;
+       GCHeapDumpMemBlock *prev;
+       uint8_t *start;
+       uint32_t alloc_size;
+       uint32_t size;
+       uint32_t offset;
+       uint32_t last_used_offset;
+};
+
+static volatile GCHeapDumpMemBlock *_gc_heap_dump_mem_blocks = NULL;
+static volatile GCHeapDumpMemBlock *_gc_heap_dump_current_mem_block = NULL;
+static volatile uint32_t _gc_heap_dump_requests = 0;
+static volatile uint32_t _gc_heap_dump_in_progress = 0;
+static volatile uint64_t _gc_heap_dump_trigger_count = 0;
+
+static GSList *_mono_profiler_provider_params = NULL;
+static GQueue *_gc_heap_dump_request_params = NULL;
+
+// Lightweight atomic "exclusive/shared" lock, prevents new fire events to happend while GC is in progress and gives GC ability to wait until all pending fire events are done
+// before progressing. State uint32_t is split into two uint16_t, upper uint16_t represent gc in progress state, taken when GC starts, preventing new fire events to execute and lower
+// uint16_t keeps number of fire events in flight, (gc_in_progress << 16) | (fire_event_count & 0xFFFF). Spin lock is only taken on slow path to queue up pending shared requests
+// while GC is in progress and should very rarely be needed.
+typedef uint32_t gc_state_t;
+typedef uint16_t gc_state_count_t;
+
+#define GC_STATE_GET_FIRE_EVENT_COUNT(x) ((gc_state_count_t)((x & 0xFFFF)))
+#define GC_STATE_INC_FIRE_EVENT_COUNT(x) ((gc_state_t)((gc_state_t)(x & 0xFFFF0000) | (gc_state_t)(GC_STATE_GET_FIRE_EVENT_COUNT(x) + 1)))
+#define GC_STATE_DEC_FIRE_EVENT_COUNT(x) ((gc_state_t)((gc_state_t)(x & 0xFFFF0000) | (gc_state_t)(GC_STATE_GET_FIRE_EVENT_COUNT(x) - 1)))
+#define GC_STATE_IN_PROGRESS_START(x) ((gc_state_t)((gc_state_t)(0xFFFF << 16) | (gc_state_t)GC_STATE_GET_FIRE_EVENT_COUNT(x)))
+#define GC_STATE_IS_IN_PROGRESS(x) (((x >> 16) & 0xFFFF) == 0xFFFF)
+#define GC_STATE_IN_PROGRESS_STOP(x) ((gc_state_t)((gc_state_t)GC_STATE_GET_FIRE_EVENT_COUNT(x)))
+
+static volatile gc_state_t _gc_state = 0;
+static ep_rt_spin_lock_handle_t _gc_lock = {0};
+
+static
+void
+fire_buffered_gc_events (
+       GCHeapDumpMemBlock *block,
+       GHashTable *cache);
+
+static
+MonoProfilerCallInstrumentationFlags
+method_instrumentation_filter_callback (
+       MonoProfiler *prof,
+       MonoMethod *method);
+
+static
+void
+gc_root_register_callback (
+       MonoProfiler *prof,
+       const mono_byte *start,
+       uintptr_t size,
+       MonoGCRootSource source,
+       const void * key,
+       const char * name);
+
+static
+void
+gc_root_unregister_callback (
+       MonoProfiler *prof,
+       const mono_byte *start);
+
+static
+bool
+is_keword_enabled (uint64_t enabled_keywords, uint64_t keyword)
+{
+       return (enabled_keywords & keyword) == keyword;
+}
+
+static
+gc_state_t
+gc_state_volatile_load (const volatile gc_state_t *ptr)
+{
+       return ep_rt_volatile_load_uint32_t ((const volatile uint32_t *)ptr);
+}
+
+static
+gc_state_t
+gc_state_atomic_cas (volatile gc_state_t *target, gc_state_t expected, gc_state_t value)
+{
+       return (gc_state_t)(mono_atomic_cas_i32 ((volatile gint32 *)(target), (gint32)(value), (gint32)(expected)));
+}
+
+static
+void
+gc_in_progress_start (void)
+{
+       gc_state_t old_state = 0;
+       gc_state_t new_state = 0;
+
+       // Make sure fire event calls will block and wait for GC completion.
+       ep_rt_spin_lock_acquire (&_gc_lock);
+
+       // Set gc in progress state, preventing new fire event requests.
+       do {
+               old_state = gc_state_volatile_load (&_gc_state);
+               EP_ASSERT (!GC_STATE_IS_IN_PROGRESS (old_state));
+               new_state = GC_STATE_IN_PROGRESS_START (old_state);
+       } while (gc_state_atomic_cas (&_gc_state, old_state, new_state) != old_state);
+
+       gc_state_count_t count = GC_STATE_GET_FIRE_EVENT_COUNT (new_state);
+
+       // Wait for all fire events to complete before progressing with gc.
+       // NOTE, should never be called recursivly. Default yield count used in SpinLock.cs.
+       int yield_count = 40;
+       while (count) {
+               if (yield_count > 0) {
+                       ep_rt_mono_thread_yield ();
+                       yield_count--;
+               } else {
+                       ep_rt_thread_sleep (200);
+               }
+               count = GC_STATE_GET_FIRE_EVENT_COUNT (gc_state_volatile_load (&_gc_state));
+       }
+}
+
+static
+void
+gc_in_progress_stop (void)
+{
+       gc_state_t old_state = 0;
+       gc_state_t new_state = 0;
+
+       // Reset gc in progress state.
+       do {
+               old_state = gc_state_volatile_load (&_gc_state);
+               EP_ASSERT (GC_STATE_IS_IN_PROGRESS (old_state));
+
+               new_state = GC_STATE_IN_PROGRESS_STOP (old_state);
+               EP_ASSERT (!GC_STATE_IS_IN_PROGRESS (new_state));
+       } while (gc_state_atomic_cas (&_gc_state, old_state, new_state) != old_state);
+
+       // Make sure fire events can continune to execute.
+       ep_rt_spin_lock_release (&_gc_lock);
+}
+
+static
+bool
+gc_in_progress (void)
+{
+       return GC_STATE_IS_IN_PROGRESS (gc_state_volatile_load (&_gc_state));
+}
+
+static
+void
+fire_event_enter (void)
+{
+       gc_state_t old_state = 0;
+       gc_state_t new_state = 0;
+
+       // NOTE, should never be called recursivly.
+       do {
+               old_state = gc_state_volatile_load (&_gc_state);
+               if (GC_STATE_IS_IN_PROGRESS (old_state)) {
+                       // GC in progress and thread tries to fire event (this should be an unlikely scenario). Wait until GC is done.
+                       ep_rt_spin_lock_acquire (&_gc_lock);
+                       ep_rt_spin_lock_release (&_gc_lock);
+                       old_state = gc_state_volatile_load (&_gc_state);
+               }
+               // Increase number of fire event calls.
+               new_state = GC_STATE_INC_FIRE_EVENT_COUNT (old_state);
+       } while (gc_state_atomic_cas (&_gc_state, old_state, new_state) != old_state);
+}
+
+static
+void
+fire_event_exit (void)
+{
+       gc_state_t old_state = 0;
+       gc_state_t new_state = 0;
+
+       do {
+               old_state = gc_state_volatile_load (&_gc_state);
+               new_state = GC_STATE_DEC_FIRE_EVENT_COUNT (old_state);
+       } while (gc_state_atomic_cas (&_gc_state, old_state, new_state) != old_state);
+}
+
+static
+const EventFilterDescriptor *
+provider_params_add (const EventFilterDescriptor *key)
+{
+       ep_rt_spin_lock_requires_lock_held (&_gc_lock);
+
+       EventFilterDescriptor *param = NULL;
+       if (key && key->ptr && key->size) {
+               uint64_t param_ptr = (uint64_t)g_malloc (key->size);
+               if (param_ptr) {
+                       param = ep_event_filter_desc_alloc (param_ptr, key->size, key->type);
+                       if (param) {
+                               memcpy ((uint8_t*)(uintptr_t)param->ptr,(const uint8_t*)(uintptr_t)key->ptr, key->size);
+                               _mono_profiler_provider_params = g_slist_append (_mono_profiler_provider_params, param);
+                       } else {
+                               g_free ((void *)(uintptr_t)param_ptr);
+                       }
+               }
+       }
+       return param;
+}
+
+static
+bool
+provider_params_remove (const EventFilterDescriptor *key)
+{
+       ep_rt_spin_lock_requires_lock_held (&_gc_lock);
+
+       bool removed = false;
+       if (_mono_profiler_provider_params && key && key->ptr && key->size) {
+               GSList *list = _mono_profiler_provider_params;
+               EventFilterDescriptor *param = NULL;
+               while (list) {
+                       param = (EventFilterDescriptor *)(list->data);
+                       if (param && param->ptr && param->type == key->type && param->size == key->size &&
+                               memcmp ((const void *)(uintptr_t)param->ptr, (const void *)(uintptr_t)key->ptr, param->size) == 0) {
+                                       g_free ((void *)(uintptr_t)param->ptr);
+                                       ep_event_filter_desc_free (param);
+                                       _mono_profiler_provider_params = g_slist_delete_link (_mono_profiler_provider_params, list);
+                                       removed = true;
+                                       break;
+                       }
+                       list = list->next;
+               }
+       }
+
+       return removed;
+}
+
+static
+void
+provider_params_free (void)
+{
+       for (GSList *list = _mono_profiler_provider_params; list; list = list->next) {
+               EventFilterDescriptor *param = (EventFilterDescriptor *)(list->data);
+               if (param) {
+                       g_free ((void *)(uintptr_t)param->ptr);
+                       ep_event_filter_desc_free (param);
+               }
+       }
+       g_slist_free (_mono_profiler_provider_params);
+       _mono_profiler_provider_params = NULL;
+}
+
+static
+bool
+provider_params_get_value (
+       const EventFilterDescriptor *param,
+       const ep_char8_t *key,
+       const ep_char8_t **value)
+{
+       if (!param || !param->ptr || !param->size || !key)
+               return false;
+
+       const ep_char8_t *current = (ep_char8_t *)(uintptr_t)param->ptr;
+       const ep_char8_t *end = current + param->size;
+       bool found_key = false;
+
+       if (value)
+               *value = "";
+
+       if (!current [param->size - 1]) {
+               while (current < end) {
+                       if (found_key) {
+                               if (value)
+                                       *value = current;
+                               break;
+                       }
+
+                       if (!ep_rt_utf8_string_compare_ignore_case (current, key)) {
+                               found_key = true;
+                       }
+
+                       current = current + strlen (current) + 1;
+               }
+       }
+
+       return found_key;
+}
+
+static
+bool
+provider_params_contains_heap_collect_ondemand (const EventFilterDescriptor *param)
+{
+       const ep_char8_t *value = NULL;
+       bool found_heap_collect_ondemand_value = false;
+
+       if (provider_params_get_value (param, "heapcollect", &value)) {
+               if (strstr (value, "ondemand"))
+                       found_heap_collect_ondemand_value = true;
+       }
+
+       return found_heap_collect_ondemand_value;
+}
+
+static
+const ep_char8_t *
+provider_params_get_heap_collect_ondemand_value (void)
+{
+       ep_rt_spin_lock_requires_lock_held (&_gc_lock);
+
+       const ep_char8_t *value = NULL;
+       if (_gc_heap_dump_request_params && !g_queue_is_empty (_gc_heap_dump_request_params)) {
+               EventFilterDescriptor *param = (EventFilterDescriptor *)g_queue_pop_head (_gc_heap_dump_request_params);
+               if (param)
+                       provider_params_get_value (param, "heapcollect", &value);
+               g_queue_push_head (_gc_heap_dump_request_params , (gpointer)param);
+       }
+       return value ? value : "";
+}
+
+static
+void
+gc_heap_dump_request_params_push_value (const EventFilterDescriptor *param)
+{
+       ep_rt_spin_lock_requires_lock_held (&_gc_lock);
+
+       if (!_gc_heap_dump_request_params)
+               _gc_heap_dump_request_params = g_queue_new ();
+       if (_gc_heap_dump_request_params) {
+               EventFilterDescriptor *desc = NULL;
+               if (param) {
+                       uint8_t *value = g_malloc (param->size);
+                       memcpy (value, (uint8_t*)(uintptr_t)param->ptr, param->size);
+                       desc = ep_event_filter_desc_alloc ((uint64_t)(uintptr_t)value, param->size, param->type);
+               }
+               g_queue_push_tail (_gc_heap_dump_request_params, (gpointer)desc);
+       }
+}
+
+static
+void
+gc_heap_dump_request_params_pop_value (void)
+{
+       ep_rt_spin_lock_requires_lock_held (&_gc_lock);
+
+       if (_gc_heap_dump_request_params && !g_queue_is_empty (_gc_heap_dump_request_params)) {
+               EventFilterDescriptor *param = (EventFilterDescriptor *)g_queue_pop_head (_gc_heap_dump_request_params);
+               if (param) {
+                       g_free ((uint8_t*)(uintptr_t)param->ptr);
+                       ep_event_filter_desc_free (param);
+               }
+       }
+}
+
+static
+void
+gc_heap_dump_request_params_free (void)
+{
+       if (_gc_heap_dump_request_params) {
+               while (!g_queue_is_empty (_gc_heap_dump_request_params))
+                       gc_heap_dump_request_params_pop_value ();
+               g_queue_free (_gc_heap_dump_request_params);
+               _gc_heap_dump_request_params = NULL;
+       }
+}
+
+static
+void
+gc_heap_dump_requests_inc (void)
+{
+       EP_ASSERT (ep_rt_mono_is_runtime_initialized ());
+       ep_rt_atomic_inc_uint32_t (&_gc_heap_dump_requests);
+}
+
+static
+void
+gc_heap_dump_requests_dec (void)
+{
+       EP_ASSERT (ep_rt_mono_is_runtime_initialized ());
+       ep_rt_atomic_dec_uint32_t (&_gc_heap_dump_requests);
+}
+
+static
+bool
+gc_heap_dump_requested (void)
+{
+       if (!ep_rt_mono_is_runtime_initialized ())
+               return false;
+
+       return ep_rt_volatile_load_uint32_t(&_gc_heap_dump_requests) != 0 ? true : false;
+}
+
+static
+bool
+gc_heap_dump_in_progress (void)
+{
+       ep_rt_spin_lock_requires_lock_held (&_gc_lock);
+       return ep_rt_volatile_load_uint32_t_without_barrier (&_gc_heap_dump_in_progress) != 0 ? true : false;
+}
+
+static
+void
+gc_heap_dump_in_progress_start (void)
+{
+       EP_ASSERT (ep_rt_mono_is_runtime_initialized ());
+
+       ep_rt_spin_lock_requires_lock_held (&_gc_lock);
+       ep_rt_volatile_store_uint32_t_without_barrier (&_gc_heap_dump_in_progress, 1);
+}
+
+static
+void
+gc_heap_dump_in_progress_stop (void)
+{
+       EP_ASSERT (ep_rt_mono_is_runtime_initialized ());
+
+       ep_rt_spin_lock_requires_lock_held (&_gc_lock);
+       ep_rt_volatile_store_uint32_t_without_barrier (&_gc_heap_dump_in_progress, 0);
+}
+
+static
+void
+gc_heap_dump_trigger_callback (MonoProfiler *prof)
+{
+       if (gc_heap_dump_requested ()) {
+               ep_rt_spin_lock_acquire (&_gc_lock);
+                       gc_heap_dump_requests_dec ();
+                       gc_heap_dump_in_progress_start ();
+               ep_rt_spin_lock_release (&_gc_lock);
+
+               mono_gc_collect (mono_gc_max_generation ());
+
+               ep_rt_spin_lock_acquire (&_gc_lock);
+                       gc_heap_dump_request_params_pop_value  ();
+                       gc_heap_dump_in_progress_stop ();
+               ep_rt_spin_lock_release (&_gc_lock);
+       }
+}
+
+static
+GCHeapDumpMemBlock *
+gc_heap_dump_mem_block_alloc (uint32_t req_size)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       GCHeapDumpMemBlock *prev = NULL;
+
+       uint32_t size = GC_HEAP_DUMP_DEFAULT_MEM_BLOCK_SIZE;
+       while (size - sizeof(GCHeapDumpMemBlock) < req_size)
+               size += GC_HEAP_DUMP_MEM_BLOCK_SIZE_INC;
+
+       GCHeapDumpMemBlock *block = mono_valloc (NULL, size, MONO_MMAP_READ | MONO_MMAP_WRITE | MONO_MMAP_ANON | MONO_MMAP_PRIVATE, MONO_MEM_ACCOUNT_PROFILER);
+       if (block) {
+               block->alloc_size = size;
+               block->start = (uint8_t *)ALIGN_PTR_TO ((uint8_t *)block + sizeof (GCHeapDumpMemBlock), 16);
+               block->size = (uint32_t)(((uint8_t*)block + size) - (uint8_t*)block->start);
+               block->offset = 0;
+               block->last_used_offset = 0;
+
+               while (true) {
+                       prev = (GCHeapDumpMemBlock *)ep_rt_volatile_load_ptr_without_barrier ((volatile void **)&_gc_heap_dump_mem_blocks);
+                       if (mono_atomic_cas_ptr ((volatile gpointer*)&_gc_heap_dump_mem_blocks, block, prev) == prev)
+                               break;
+               }
+
+               if (prev)
+                       prev->next = block;
+               block->prev = prev;
+       }
+
+       return block;
+}
+
+static
+uint8_t *
+gc_heap_dump_mem_alloc (uint32_t req_size)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       GCHeapDumpMemBlock *current_block = (GCHeapDumpMemBlock *)ep_rt_volatile_load_ptr_without_barrier ((volatile void **)&_gc_heap_dump_current_mem_block);
+       uint8_t *buffer = NULL;
+
+       if (!current_block) {
+               current_block = gc_heap_dump_mem_block_alloc (req_size);
+               if (current_block) {
+                       mono_memory_barrier ();
+                       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_gc_heap_dump_current_mem_block, current_block);
+               }
+       }
+
+       if (current_block) {
+               uint32_t prev_offset = (uint32_t)mono_atomic_fetch_add_i32 ((volatile int32_t *)&current_block->offset, (int32_t)req_size);
+               if (prev_offset + req_size > current_block->size) {
+                       if (prev_offset <= current_block->size)
+                               current_block->last_used_offset = prev_offset;
+                       current_block = gc_heap_dump_mem_block_alloc (req_size);
+                       if (current_block) {
+                               buffer = current_block->start;
+                               current_block->offset += req_size;
+                               mono_memory_barrier ();
+                               ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_gc_heap_dump_current_mem_block, current_block);
+                       }
+               } else {
+                       buffer = (uint8_t*)current_block->start + prev_offset;
+               }
+       }
+
+       return buffer;
+}
+
+static
+void
+gc_heap_dump_mem_block_free_all (void)
+{
+       GCHeapDumpMemBlock *current_block = (GCHeapDumpMemBlock *)ep_rt_volatile_load_ptr ((volatile void **)&_gc_heap_dump_current_mem_block);
+
+       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_gc_heap_dump_current_mem_block, NULL);
+       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_gc_heap_dump_mem_blocks, NULL);
+
+       mono_memory_barrier ();
+
+       while (current_block) {
+               GCHeapDumpMemBlock *prev_block = current_block->prev;
+               mono_vfree ((uint8_t *)current_block, current_block->alloc_size, MONO_MEM_ACCOUNT_MEM_MANAGER);
+               current_block = prev_block;
+       }
+}
+
+static
+void
+gc_heap_dump_mem_block_free_all_but_current (void)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       GCHeapDumpMemBlock *block_to_keep = (GCHeapDumpMemBlock *)ep_rt_volatile_load_ptr ((volatile void **)&_gc_heap_dump_current_mem_block);
+       GCHeapDumpMemBlock *current_block = block_to_keep;
+
+       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_gc_heap_dump_current_mem_block, NULL);
+       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_gc_heap_dump_mem_blocks, NULL);
+
+       mono_memory_barrier ();
+
+       if (current_block) {
+               if (current_block->prev) {
+                       current_block = current_block->prev;
+                       while (current_block) {
+                               GCHeapDumpMemBlock *prev_block = current_block->prev;
+                               mono_vfree ((uint8_t *)current_block, current_block->alloc_size, MONO_MEM_ACCOUNT_MEM_MANAGER);
+                               current_block = prev_block;
+                       }
+               }
+       }
+
+       if (block_to_keep) {
+               block_to_keep->prev = NULL;
+               block_to_keep->next = NULL;
+               block_to_keep->offset = 0;
+               block_to_keep->last_used_offset = 0;
+       }
+
+       mono_memory_barrier ();
+
+       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_gc_heap_dump_current_mem_block, block_to_keep);
+       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_gc_heap_dump_mem_blocks, block_to_keep);
+}
+
+static
+uint8_t *
+buffered_gc_event_alloc (uint32_t req_size)
+{
+       EP_ASSERT (gc_in_progress ());
+       return gc_heap_dump_mem_alloc (req_size + sizeof (BufferedGCEvent));
+}
+
+static
+void
+fire_buffered_gc_events_in_alloc_order (GHashTable *cache)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       GCHeapDumpMemBlock *first_block = (GCHeapDumpMemBlock *)ep_rt_volatile_load_ptr ((volatile void **)&_gc_heap_dump_current_mem_block);
+       while (first_block && first_block->prev)
+               first_block = first_block->prev;
+
+       GCHeapDumpMemBlock *current_block = first_block;
+       while (current_block) {
+               GCHeapDumpMemBlock *next_block = current_block->next;
+               fire_buffered_gc_events (current_block, cache);
+               current_block = next_block;
+       }
+
+       gc_heap_dump_mem_block_free_all_but_current ();
+}
+
+static
+void
+get_generic_types (
+       MonoGenericInst *generic_instance,
+       uint32_t *generic_type_count,
+       uint8_t **generic_types)
+{
+       if (generic_instance) {
+               uint8_t *buffer = g_malloc (generic_instance->type_argc * (sizeof (uint8_t) + sizeof (uint64_t)));
+               if (buffer) {
+                       *generic_types = buffer;
+                       *generic_type_count = generic_instance->type_argc;
+                       for (uint32_t i = 0; i < generic_instance->type_argc; ++i) {
+                               uint8_t type = generic_instance->type_argv [i]->type;
+                               ep_write_buffer_uint8_t (&buffer, type);
+
+                               uint64_t class_id = (uint64_t)mono_class_from_mono_type_internal (generic_instance->type_argv [i]);
+                               ep_write_buffer_uint64_t (&buffer, class_id);
+                       }
+               }
+       }
+}
+
+static
+void
+get_class_data (
+       MonoClass *klass,
+       uint64_t *class_id,
+       uint64_t *module_id,
+       ep_char8_t **class_name,
+       uint32_t *class_generic_type_count,
+       uint8_t **class_generic_types)
+{
+       *class_id = (uint64_t)klass;
+       *module_id = 0;
+
+       if (klass)
+               *module_id = (uint64_t)m_class_get_image (klass);
+
+       if (klass && class_name)
+               *class_name = (ep_char8_t *)mono_type_get_name_full (m_class_get_byval_arg (klass), MONO_TYPE_NAME_FORMAT_IL);
+       else if (class_name)
+               *class_name = NULL;
+
+       if (class_generic_type_count && class_generic_types) {
+               if (mono_class_is_ginst (klass)) {
+                       MonoGenericContext *context = mono_class_get_context (klass);
+                       MonoGenericInst *class_instance = (context && context->class_inst) ? context->class_inst : NULL;
+                       get_generic_types (class_instance, class_generic_type_count, class_generic_types);
+               }
+       }
+}
+
+static
+void
+fire_gc_event_root_register (
+       uint8_t *data,
+       uint32_t payload_size)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       uintptr_t root_id;
+       uintptr_t root_size;
+       uint8_t root_source;
+       uintptr_t root_key;
+
+       memcpy (&root_id, data, sizeof (root_id));
+       data += sizeof (root_id);
+
+       memcpy (&root_size, data, sizeof (root_size));
+       data += sizeof (root_size);
+
+       memcpy (&root_source, data, sizeof (root_source));
+       data += sizeof (root_source);
+
+       memcpy (&root_key, data, sizeof (root_key));
+       data += sizeof (root_key);
+
+       FireEtwMonoProfilerGCRootRegister (
+               (const void *)root_id,
+               (uint64_t)root_size,
+               root_source,
+               (uint64_t)root_key,
+               (const ep_char8_t *)data,
+               NULL,
+               NULL);
+}
+
+static
+void
+buffer_gc_event_root_register_callback (
+       MonoProfiler *prof,
+       const mono_byte *start,
+       uintptr_t size,
+       MonoGCRootSource source,
+       const void * key,
+       const char * name)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       uintptr_t root_id = (uintptr_t)start;
+       uintptr_t root_size = size;
+       uint8_t root_source = (uint8_t)source;
+       uintptr_t root_key = (uintptr_t)key;
+       const char *root_name = (name ? name : "");
+       size_t root_name_len = strlen (root_name) + 1;
+
+       BufferedGCEvent gc_event_data;
+       gc_event_data.type = BUFFERED_GC_EVENT_ROOT_REGISTER;
+       gc_event_data.payload_size = (uint32_t)
+               (sizeof (root_id) +
+               sizeof (root_size) +
+               sizeof (root_source) +
+               sizeof (root_key) +
+               root_name_len);
+
+       uint8_t * buffer = buffered_gc_event_alloc (gc_event_data.payload_size);
+       if (buffer) {
+               // Internal header
+               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
+               buffer += sizeof (gc_event_data);
+
+               // GCEvent.RootID
+               memcpy(buffer, &root_id, sizeof (root_id));
+               buffer += sizeof (root_id);
+
+               // GCEvent.RootSize
+               memcpy(buffer, &root_size, sizeof (root_size));
+               buffer += sizeof (root_size);
+
+               // GCEvent.RootType
+               memcpy(buffer, &root_source, sizeof (root_source));
+               buffer += sizeof (root_source);
+
+               // GCEvent.RootKeyID
+               memcpy(buffer, &root_key, sizeof (root_key));
+               buffer += sizeof (root_key);
+
+               // GCEvent.RootKeyName
+               memcpy(buffer, root_name, root_name_len);
+       }
+}
+
+static
+void
+fire_gc_event_root_unregister (
+       uint8_t *data,
+       uint32_t payload_size)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       uintptr_t root_id;
+
+       memcpy (&root_id, data, sizeof (root_id));
+
+       FireEtwMonoProfilerGCRootUnregister (
+               (const void *)root_id,
+               NULL,
+               NULL);
+}
+
+static
+void
+buffer_gc_event_root_unregister_callback (
+       MonoProfiler *prof,
+       const mono_byte *start)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       uintptr_t root_id = (uintptr_t)start;
+
+       BufferedGCEvent gc_event_data;
+       gc_event_data.type = BUFFERED_GC_EVENT_ROOT_UNREGISTER;
+       gc_event_data.payload_size = sizeof (root_id);
+
+       uint8_t * buffer = buffered_gc_event_alloc (gc_event_data.payload_size);
+       if (buffer) {
+               // Internal header
+               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
+               buffer += sizeof (gc_event_data);
+
+               // GCEvent.RootID
+               memcpy(buffer, &root_id, sizeof (root_id));
+       }
+}
+
+static
+void
+fire_gc_event (
+       uint8_t *data,
+       uint32_t payload_size)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       uint8_t gc_event_type;
+       uint32_t generation;
+
+       memcpy (&gc_event_type, data, sizeof (gc_event_type));
+       data += sizeof (gc_event_type);
+
+       memcpy (&generation, data, sizeof (generation));
+
+       FireEtwMonoProfilerGCEvent (
+               gc_event_type,
+               generation,
+               NULL,
+               NULL);
+}
+
+static
+void
+buffer_gc_event (
+       uint8_t gc_event_type,
+       uint32_t generation)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       BufferedGCEvent gc_event_data;
+       gc_event_data.type = BUFFERED_GC_EVENT;
+       gc_event_data.payload_size =
+               sizeof (gc_event_type) +
+               sizeof (generation);
+
+       uint8_t * buffer = buffered_gc_event_alloc (gc_event_data.payload_size);
+       if (buffer) {
+               // Internal header
+               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
+               buffer += sizeof (gc_event_data);
+
+               // GCEvent.GCEventType
+               memcpy(buffer, &gc_event_type, sizeof (gc_event_type));
+               buffer += sizeof (gc_event_type);
+
+               // GCEvent.GCGeneration
+               memcpy(buffer, &generation, sizeof (generation));
+       }
+}
+
+static
+void
+fire_gc_event_resize (
+       uint8_t *data,
+       uint32_t payload_size)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       uintptr_t size;
+
+       memcpy (&size, data, sizeof (size));
+
+       FireEtwMonoProfilerGCResize (
+               (uint64_t)size,
+               NULL,
+               NULL);
+}
+
+static
+void
+buffer_gc_event_resize_callback (
+       MonoProfiler *prof,
+       uintptr_t size)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       BufferedGCEvent gc_event_data;
+       gc_event_data.type = BUFFERED_GC_EVENT_RESIZE;
+       gc_event_data.payload_size = sizeof (size);
+
+       uint8_t * buffer = buffered_gc_event_alloc (gc_event_data.payload_size);
+       if (buffer) {
+               // Internal header
+               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
+               buffer += sizeof (gc_event_data);
+
+               // GCResize.NewSize
+               memcpy(buffer, &size, sizeof (size));
+       }
+}
+
+static
+void
+fire_gc_event_moves (
+       uint8_t *data,
+       uint32_t payload_size)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       uint64_t count;
+
+       memcpy (&count, data, sizeof (count));
+       data += sizeof (count);
+
+       FireEtwMonoProfilerGCMoves (
+               (uint32_t)count,
+               sizeof (uintptr_t) + sizeof (uintptr_t),
+               data,
+               NULL,
+               NULL);
+}
+
+static
+void
+buffer_gc_event_moves_callback (
+       MonoProfiler *prof,
+       MonoObject *const* objects,
+       uint64_t count)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       uintptr_t object_id;
+       uintptr_t address_id;
+
+       // Serialized as object_id/address_id pairs.
+       count = count / 2;
+
+       BufferedGCEvent gc_event_data;
+       gc_event_data.type = BUFFERED_GC_EVENT_MOVES;
+       gc_event_data.payload_size =
+               (uint32_t)(sizeof (count) +
+               (count * (sizeof (uintptr_t) + sizeof (uintptr_t))));
+
+       uint8_t * buffer = buffered_gc_event_alloc (gc_event_data.payload_size);
+       if (buffer) {
+               // Internal header
+               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
+               buffer += sizeof (gc_event_data);
+
+               // GCMoves.Count
+               memcpy (buffer, &count, sizeof (count));
+               buffer += sizeof (count);
+
+               // Serialize directly as memory stream expected by FireEtwMonoProfilerGCMoves.
+               for (uint64_t i = 0; i < count; i++) {
+                       // GCMoves.Values[].ObjectID.
+                       object_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (*objects);
+                       ep_write_buffer_uintptr_t (&buffer, object_id);
+                       objects++;
+
+                       // GCMoves.Values[].AddressID.
+                       address_id = (uintptr_t)*objects;
+                       ep_write_buffer_uintptr_t (&buffer, address_id);
+                       objects++;
+               }
+       }
+}
+
+static
+void
+fire_gc_event_roots (
+       uint8_t *data,
+       uint32_t payload_size)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       uint64_t count;
+
+       memcpy (&count, data, sizeof (count));
+       data += sizeof (count);
+
+       FireEtwMonoProfilerGCRoots (
+               (uint32_t)count,
+               sizeof (uintptr_t) + sizeof (uintptr_t),
+               data,
+               NULL,
+               NULL);
+}
+
+static
+void
+buffer_gc_event_roots_callback (
+       MonoProfiler *prof,
+       uint64_t count,
+       const mono_byte *const * addresses,
+       MonoObject *const * objects)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       uintptr_t object_id;
+       uintptr_t address_id;
+
+       BufferedGCEvent gc_event_data;
+       gc_event_data.type = BUFFERED_GC_EVENT_ROOTS;
+       gc_event_data.payload_size =
+               (uint32_t)(sizeof (count) +
+               (count * (sizeof (uintptr_t) + sizeof (uintptr_t))));
+
+       uint8_t * buffer = buffered_gc_event_alloc (gc_event_data.payload_size);
+       if (buffer) {
+               // Internal header
+               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
+               buffer += sizeof (gc_event_data);
+
+               // GCRoots.Count
+               memcpy (buffer, &count, sizeof (count));
+               buffer += sizeof (count);
+
+               // Serialize directly as memory stream expected by FireEtwMonoProfilerGCRoots.
+               for (uint64_t i = 0; i < count; i++) {
+                       // GCRoots.Values[].ObjectID.
+                       object_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (*objects);
+                       ep_write_buffer_uintptr_t (&buffer, object_id);
+                       objects++;
+
+                       // GCRoots.Values[].AddressID.
+                       address_id = (uintptr_t)*addresses;
+                       ep_write_buffer_uintptr_t (&buffer, address_id);
+                       addresses++;
+               }
+       }
+}
+
+static
+void
+fire_gc_event_heap_dump_object_reference (
+       uint8_t *data,
+       uint32_t payload_size,
+       GHashTable *cache)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       uintptr_t object_id;
+       uintptr_t vtable_id;
+       uintptr_t object_size;
+       uint8_t object_gen;
+       uintptr_t object_ref_count;
+
+       memcpy (&object_id, data, sizeof (object_id));
+       data += sizeof (object_id);
+
+       memcpy (&vtable_id, data, sizeof (vtable_id));
+       data += sizeof (vtable_id);
+
+       memcpy (&object_size, data, sizeof (object_size));
+       data += sizeof (object_size);
+
+       memcpy (&object_gen, data, sizeof (object_gen));
+       data += sizeof (object_gen);
+
+       memcpy (&object_ref_count, data, sizeof (object_ref_count));
+       data += sizeof (object_ref_count);
+
+       FireEtwMonoProfilerGCHeapDumpObjectReference (
+               (const void *)object_id,
+               (uint64_t)vtable_id,
+               (uint64_t)object_size,
+               object_gen,
+               (uint32_t)object_ref_count,
+               sizeof (uint32_t) + sizeof (uintptr_t),
+               data,
+               NULL,
+               NULL);
+
+       if (cache)
+               g_hash_table_insert (cache, (MonoVTable *)SGEN_POINTER_UNTAG_ALL (vtable_id), NULL);
+}
+
+static
+int
+buffer_gc_event_heap_dump_object_reference_callback (
+       MonoObject *obj,
+       MonoClass *klass,
+       uintptr_t size,
+       uintptr_t num,
+       MonoObject **refs,
+       uintptr_t *offsets,
+       void *data)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       uintptr_t object_id;
+       uintptr_t vtable_id;
+       uint8_t object_gen;
+       uintptr_t object_size = size;
+       uintptr_t object_ref_count = num;
+       uint32_t object_ref_offset;
+
+       /* account for object alignment */
+       object_size += 7;
+       object_size &= ~7;
+
+       size_t payload_size =
+               sizeof (object_id) +
+               sizeof (vtable_id) +
+               sizeof (object_size) +
+               sizeof (object_gen) +
+               sizeof (object_ref_count) +
+               (object_ref_count * (sizeof (uint32_t) + sizeof (uintptr_t)));
+
+       BufferedGCEvent gc_event_data;
+       gc_event_data.type = BUFFERED_GC_EVENT_OBJECT_REF;
+       gc_event_data.payload_size = GSIZE_TO_UINT32 (payload_size);
+
+       uint8_t *buffer = buffered_gc_event_alloc (gc_event_data.payload_size);
+       if (buffer) {
+               // Internal header
+               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
+               buffer += sizeof (gc_event_data);
+
+               // GCEvent.ObjectID
+               object_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (obj);
+               memcpy (buffer, &object_id, sizeof (object_id));
+               buffer += sizeof (object_id);
+
+               // GCEvent.VTableID
+               vtable_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (mono_object_get_vtable_internal (obj));
+               memcpy (buffer, &vtable_id, sizeof (vtable_id));
+               buffer += sizeof (vtable_id);
+
+               // GCEvent.ObjectSize
+               memcpy (buffer, &object_size, sizeof (object_size));
+               buffer += sizeof (object_size);
+
+               // GCEvent.ObjectGeneration
+               object_gen = (uint8_t)mono_gc_get_generation (obj);
+               memcpy (buffer, &object_gen, sizeof (object_gen));
+               buffer += sizeof (object_gen);
+
+               // GCEvent.Count
+               memcpy (buffer, &object_ref_count, sizeof (object_ref_count));
+               buffer += sizeof (object_ref_count);
+
+               // Serialize directly as memory stream expected by FireEtwMonoProfilerGCHeapDumpObjectReference.
+               uintptr_t last_offset = 0;
+               for (uintptr_t i = 0; i < object_ref_count; i++) {
+                       // GCEvent.Values[].ReferencesOffset
+                       object_ref_offset = GUINTPTR_TO_UINT32 (offsets [i] - last_offset);
+                       ep_write_buffer_uint32_t (&buffer, object_ref_offset);
+
+                       // GCEvent.Values[].ObjectID
+                       object_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (refs[i]);
+                       ep_write_buffer_uintptr_t (&buffer, object_id);
+
+                       last_offset = offsets [i];
+               }
+       }
+
+       return 0;
+}
+
+static
+void
+fire_buffered_gc_events (
+       GCHeapDumpMemBlock *block,
+       GHashTable *cache)
+{
+       EP_ASSERT (gc_in_progress ());
+
+       if (block) {
+               uint32_t current_offset = 0;
+               uint32_t used_size = (block->offset < block->size) ? block->offset : block->last_used_offset;
+               BufferedGCEvent gc_event;
+               while ((current_offset + sizeof (gc_event)) <= used_size) {
+                       uint8_t *data = block->start + current_offset;
+                       memcpy (&gc_event, data, sizeof (gc_event));
+                       data += sizeof (gc_event);
+                       if ((current_offset + sizeof (gc_event) + gc_event.payload_size) <= used_size) {
+                               switch (gc_event.type) {
+                               case BUFFERED_GC_EVENT:
+                                       fire_gc_event (data, gc_event.payload_size);
+                                       break;
+                               case BUFFERED_GC_EVENT_RESIZE:
+                                       fire_gc_event_resize (data, gc_event.payload_size);
+                                       break;
+                               case BUFFERED_GC_EVENT_ROOTS:
+                                       fire_gc_event_roots (data, gc_event.payload_size);
+                                       break;
+                               case BUFFERED_GC_EVENT_MOVES:
+                                       fire_gc_event_moves (data, gc_event.payload_size);
+                                       break;
+                               case BUFFERED_GC_EVENT_OBJECT_REF:
+                                       fire_gc_event_heap_dump_object_reference (data, gc_event.payload_size, cache);
+                                       break;
+                               case BUFFERED_GC_EVENT_ROOT_REGISTER:
+                                       fire_gc_event_root_register (data, gc_event.payload_size);
+                                       break;
+                               case BUFFERED_GC_EVENT_ROOT_UNREGISTER:
+                                       fire_gc_event_root_unregister (data, gc_event.payload_size);
+                                       break;
+                               default:
+                                       EP_ASSERT (!"Unknown buffered GC event type.");
+                               }
+
+                               current_offset += sizeof (gc_event) + gc_event.payload_size;
+                       } else {
+                               break;
+                       }
+               }
+       }
+}
+
+static
+void
+fire_cached_gc_events (GHashTable *cache)
+{
+       if (cache) {
+               GHashTableIter iter;
+               MonoVTable *object_vtable;
+               g_hash_table_iter_init (&iter, cache);
+               while (g_hash_table_iter_next (&iter, (void**)&object_vtable, NULL)) {
+                       if (object_vtable) {
+                               uint64_t vtable_id = (uint64_t)object_vtable;
+                               uint64_t class_id;
+                               uint64_t module_id;
+                               ep_char8_t *class_name;
+                               get_class_data (object_vtable->klass, &class_id, &module_id, &class_name, NULL, NULL);
+                               FireEtwMonoProfilerGCHeapDumpVTableClassReference (
+                                       vtable_id,
+                                       class_id,
+                                       module_id,
+                                       class_name,
+                                       NULL,
+                                       NULL);
+                               g_free (class_name);
+                       }
+               }
+       }
+}
+
+static
+void
+app_domain_loading_callback (
+       MonoProfiler *prof,
+       MonoDomain *domain)
+{
+       if (!EventEnabledMonoProfilerAppDomainLoading ())
+               return;
+
+       uint64_t domain_id = (uint64_t)domain;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerAppDomainLoading (
+               domain_id,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+app_domain_loaded_callback (
+       MonoProfiler *prof,
+       MonoDomain *domain)
+{
+       if (!EventEnabledMonoProfilerAppDomainLoaded ())
+               return;
+
+       uint64_t domain_id = (uint64_t)domain;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerAppDomainLoaded (
+               domain_id,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+app_domain_unloading_callback (
+       MonoProfiler *prof,
+       MonoDomain *domain)
+{
+       if (!EventEnabledMonoProfilerAppDomainUnloading ())
+               return;
+
+       uint64_t domain_id = (uint64_t)domain;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerAppDomainUnloading (
+               domain_id,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+app_domain_unloaded_callback (
+       MonoProfiler *prof,
+       MonoDomain *domain)
+{
+       if (!EventEnabledMonoProfilerAppDomainUnloaded ())
+               return;
+
+       uint64_t domain_id = (uint64_t)domain;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerAppDomainUnloaded (
+               domain_id,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+app_domain_name_callback (
+       MonoProfiler *prof,
+       MonoDomain *domain,
+       const char *name)
+{
+       if (!EventEnabledMonoProfilerAppDomainName ())
+               return;
+
+       uint64_t domain_id = (uint64_t)domain;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerAppDomainName (
+               domain_id,
+               (const ep_char8_t *)(name ? name : ""),
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+get_jit_data (
+       MonoMethod *method,
+       uint64_t *method_id,
+       uint64_t *module_id,
+       uint32_t *method_token,
+       uint32_t *method_generic_type_count,
+       uint8_t **method_generic_types)
+{
+       *method_id = (uint64_t)method;
+       *module_id = 0;
+       *method_token = 0;
+
+       if (method) {
+               *method_token = method->token;
+               if (method->klass)
+                       *module_id = (uint64_t)m_class_get_image (method->klass);
+
+               if (method_generic_type_count && method_generic_types) {
+                       if (method->is_inflated) {
+                               MonoGenericContext *context = mono_method_get_context (method);
+                               MonoGenericInst *method_instance = (context && context->method_inst) ? context->method_inst : NULL;
+                               get_generic_types (method_instance, method_generic_type_count, method_generic_types);
+                       }
+               }
+       }
+}
+
+static
+void
+jit_begin_callback (
+       MonoProfiler *prof,
+       MonoMethod *method)
+{
+       if (!EventEnabledMonoProfilerJitBegin ())
+               return;
+
+       uint64_t method_id;
+       uint64_t module_id;
+       uint32_t method_token;
+
+       get_jit_data (method, &method_id, &module_id, &method_token, NULL, NULL);
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerJitBegin (
+               method_id,
+               module_id,
+               method_token,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+jit_failed_callback (
+       MonoProfiler *prof,
+       MonoMethod *method)
+{
+       if (!EventEnabledMonoProfilerJitFailed ())
+               return;
+
+       uint64_t method_id;
+       uint64_t module_id;
+       uint32_t method_token;
+
+       get_jit_data (method, &method_id, &module_id, &method_token, NULL, NULL);
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerJitFailed (
+               method_id,
+               module_id,
+               method_token,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+jit_done_callback (
+       MonoProfiler *prof,
+       MonoMethod *method,
+       MonoJitInfo *ji)
+{
+       if (!EventEnabledMonoProfilerJitDone () && !EventEnabledMonoProfilerJitDone_V1 () && !EventEnabledMonoProfilerJitDoneVerbose ())
+               return;
+
+       bool verbose = (RUNTIME_MONO_PROFILER_PROVIDER_CONTEXT.Level >= (uint8_t)EP_EVENT_LEVEL_VERBOSE);
+
+       uint64_t method_id;
+       uint64_t module_id;
+       uint32_t method_token;
+
+       uint32_t method_generic_type_count = 0;
+       uint8_t *method_generic_types = NULL;
+
+       char *method_namespace = NULL;
+       const char *method_name = NULL;
+       char *method_signature = NULL;
+
+       get_jit_data (method, &method_id, &module_id, &method_token, &method_generic_type_count, &method_generic_types);
+
+       if (verbose) {
+               //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc.
+               method_name = method->name;
+               method_signature = mono_signature_full_name (mono_method_signature_internal (method));
+               if (method->klass)
+                       method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL);
+       }
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerJitDone_V1 (
+               method_id,
+               module_id,
+               method_token,
+               method_generic_type_count,
+               sizeof (uint8_t) + sizeof (uint64_t),
+               method_generic_types,
+               NULL,
+               NULL);
+
+       if (verbose) {
+               FireEtwMonoProfilerJitDoneVerbose (
+                       method_id,
+                       (const ep_char8_t *)method_namespace,
+                       (const ep_char8_t *)method_name,
+                       (const ep_char8_t *)method_signature,
+                       NULL,
+                       NULL);
+       }
+
+       fire_event_exit ();
+
+       g_free (method_namespace);
+       g_free (method_signature);
+       g_free (method_generic_types);
+}
+
+static
+void
+jit_chunk_created_callback (
+       MonoProfiler *prof,
+       const mono_byte *chunk,
+       uintptr_t size)
+{
+       if (!EventEnabledMonoProfilerJitChunkCreated ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerJitChunkCreated (
+               chunk,
+               (uint64_t)size,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+jit_chunk_destroyed_callback (
+       MonoProfiler *prof,
+       const mono_byte *chunk)
+{
+       if (!EventEnabledMonoProfilerJitChunkDestroyed ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerJitChunkDestroyed (
+               chunk,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+jit_code_buffer_callback (
+       MonoProfiler *prof,
+       const mono_byte *buffer,
+       uint64_t size,
+       MonoProfilerCodeBufferType type,
+       const void *data)
+{
+       if (!EventEnabledMonoProfilerJitCodeBuffer ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerJitCodeBuffer (
+               buffer,
+               size,
+               (uint8_t)type,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+class_loading_callback (
+       MonoProfiler *prof,
+       MonoClass *klass)
+{
+       if (!EventEnabledMonoProfilerClassLoading ())
+               return;
+
+       uint64_t class_id;
+       uint64_t module_id;
+
+       get_class_data (klass, &class_id, &module_id, NULL, NULL, NULL);
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerClassLoading (
+               class_id,
+               module_id,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+class_failed_callback (
+       MonoProfiler *prof,
+       MonoClass *klass)
+{
+       if (!EventEnabledMonoProfilerClassFailed ())
+               return;
+
+       uint64_t class_id;
+       uint64_t module_id;
+
+       get_class_data (klass, &class_id, &module_id, NULL, NULL, NULL);
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerClassFailed (
+               class_id,
+               module_id,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+class_loaded_callback (
+       MonoProfiler *prof,
+       MonoClass *klass)
+{
+       if (!EventEnabledMonoProfilerClassLoaded () && !EventEnabledMonoProfilerClassLoaded_V1 ())
+               return;
+
+       uint64_t class_id;
+       uint64_t module_id;
+       ep_char8_t *class_name;
+
+       uint32_t class_generic_type_count = 0;
+       uint8_t *class_generic_types = NULL;
+
+       get_class_data (klass, &class_id, &module_id, &class_name, &class_generic_type_count, &class_generic_types);
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerClassLoaded_V1 (
+               class_id,
+               module_id,
+               class_name ? class_name : "",
+               class_generic_type_count,
+               sizeof (uint8_t) + sizeof (uint64_t),
+               class_generic_types,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+
+       g_free (class_name);
+       g_free (class_generic_types);
+}
+
+static
+void
+get_vtable_data (
+       MonoVTable *vtable,
+       uint64_t *vtable_id,
+       uint64_t *class_id,
+       uint64_t *domain_id)
+{
+       *vtable_id = (uint64_t)vtable;
+       *class_id = 0;
+       *domain_id = 0;
+
+       if (vtable) {
+               *class_id = (uint64_t)mono_vtable_class_internal (vtable);
+               *domain_id = (uint64_t)mono_vtable_domain_internal (vtable);
+       }
+}
+
+static
+void
+vtable_loading_callback (
+       MonoProfiler *prof,
+       MonoVTable *vtable)
+{
+       if (!EventEnabledMonoProfilerVTableLoading ())
+               return;
+
+       uint64_t vtable_id;
+       uint64_t class_id;
+       uint64_t domain_id;
+
+       get_vtable_data (vtable, &vtable_id, &class_id, &domain_id);
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerVTableLoading (
+               vtable_id,
+               class_id,
+               domain_id,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+vtable_failed_callback (
+       MonoProfiler *prof,
+       MonoVTable *vtable)
+{
+       if (!EventEnabledMonoProfilerVTableFailed ())
+               return;
+
+       uint64_t vtable_id;
+       uint64_t class_id;
+       uint64_t domain_id;
+
+       get_vtable_data (vtable, &vtable_id, &class_id, &domain_id);
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerVTableFailed (
+               vtable_id,
+               class_id,
+               domain_id,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+vtable_loaded_callback (
+       MonoProfiler *prof,
+       MonoVTable *vtable)
+{
+       if (!EventEnabledMonoProfilerVTableLoaded ())
+               return;
+
+       uint64_t vtable_id;
+       uint64_t class_id;
+       uint64_t domain_id;
+
+       get_vtable_data (vtable, &vtable_id, &class_id, &domain_id);
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerVTableLoaded (
+               vtable_id,
+               class_id,
+               domain_id,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+module_loading_callback (
+       MonoProfiler *prof,
+       MonoImage *image)
+{
+       if (!EventEnabledMonoProfilerModuleLoading ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerModuleLoading (
+               (uint64_t)image,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+module_failed_callback (
+       MonoProfiler *prof,
+       MonoImage *image)
+{
+       if (!EventEnabledMonoProfilerModuleFailed ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerModuleFailed (
+               (uint64_t)image,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+const char *
+get_module_path (MonoImage *image)
+{
+       if (image && image->filename) {
+               /* if there's a filename, use it */
+               return image->filename;
+       } else if (image && image->module_name) {
+               /* otherwise, use the module name */
+               return image->module_name;
+       }
+
+       return "";
+}
+
+static
+void
+module_loaded_callback (
+       MonoProfiler *prof,
+       MonoImage *image)
+{
+       if (!EventEnabledMonoProfilerModuleLoaded ())
+               return;
+
+       uint64_t module_id = (uint64_t)image;
+       const ep_char8_t *module_path = NULL;
+       const ep_char8_t *module_guid = NULL;
+
+       if (image) {
+               module_path = get_module_path (image);
+               module_guid = (const ep_char8_t *)mono_image_get_guid (image);
+       }
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerModuleLoaded (
+               module_id,
+               module_path ? module_path : "",
+               module_guid ? module_guid : "",
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+module_unloading_callback (
+       MonoProfiler *prof,
+       MonoImage *image)
+{
+       if (!EventEnabledMonoProfilerModuleUnloading ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerModuleUnloading (
+               (uint64_t)image,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+module_unloaded_callback (
+       MonoProfiler *prof,
+       MonoImage *image)
+{
+       if (!EventEnabledMonoProfilerModuleUnloaded ())
+               return;
+
+       uint64_t module_id = (uint64_t)image;
+       const ep_char8_t *module_path = NULL;
+       const ep_char8_t *module_guid = NULL;
+
+       if (image) {
+               module_path = get_module_path (image);
+               module_guid = (const ep_char8_t *)mono_image_get_guid (image);
+       }
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerModuleUnloaded (
+               module_id,
+               module_path ? module_path : "",
+               module_guid ? module_guid : "",
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+get_assembly_data (
+       MonoAssembly *assembly,
+       uint64_t *assembly_id,
+       uint64_t *module_id,
+       ep_char8_t **assembly_name)
+{
+       *assembly_id = (uint64_t)assembly;
+       *module_id = 0;
+
+       if (assembly)
+               *module_id = (uint64_t)mono_assembly_get_image_internal (assembly);
+
+       if (assembly && assembly_name)
+               *assembly_name = (ep_char8_t *)mono_stringify_assembly_name (&assembly->aname);
+       else if (assembly_name)
+               *assembly_name = NULL;
+}
+
+static
+void
+assembly_loading_callback (
+       MonoProfiler *prof,
+       MonoAssembly *assembly)
+{
+       if (!EventEnabledMonoProfilerAssemblyLoading ())
+               return;
+
+       uint64_t assembly_id;
+       uint64_t module_id;
+
+       get_assembly_data (assembly, &assembly_id, &module_id, NULL);
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerAssemblyLoading (
+               assembly_id,
+               module_id,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+assembly_loaded_callback (
+       MonoProfiler *prof,
+       MonoAssembly *assembly)
+{
+       if (!EventEnabledMonoProfilerAssemblyLoaded ())
+               return;
+
+       uint64_t assembly_id;
+       uint64_t module_id;
+       ep_char8_t *assembly_name;
+
+       get_assembly_data (assembly, &assembly_id, &module_id, &assembly_name);
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerAssemblyLoaded (
+               assembly_id,
+               module_id,
+               assembly_name ? assembly_name : "",
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+
+       g_free (assembly_name);
+}
+
+static
+void
+assembly_unloading_callback (
+       MonoProfiler *prof,
+       MonoAssembly *assembly)
+{
+       if (!EventEnabledMonoProfilerAssemblyUnloading ())
+               return;
+
+       uint64_t assembly_id;
+       uint64_t module_id;
+
+       get_assembly_data (assembly, &assembly_id, &module_id, NULL);
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerAssemblyUnloading (
+               assembly_id,
+               module_id,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+assembly_unloaded_callback (
+       MonoProfiler *prof,
+       MonoAssembly *assembly)
+{
+       if (!EventEnabledMonoProfilerAssemblyUnloaded ())
+               return;
+
+       uint64_t assembly_id;
+       uint64_t module_id;
+       ep_char8_t *assembly_name;
+
+       get_assembly_data (assembly, &assembly_id, &module_id, &assembly_name);
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerAssemblyUnloaded (
+               assembly_id,
+               module_id,
+               assembly_name ? assembly_name : "",
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+
+       g_free (assembly_name);
+}
+
+static
+void
+method_enter_callback (
+       MonoProfiler *prof,
+       MonoMethod *method,
+       MonoProfilerCallContext *context)
+{
+       if (!EventEnabledMonoProfilerMethodEnter ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerMethodEnter (
+               (uint64_t)method,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+method_leave_callback (
+       MonoProfiler *prof,
+       MonoMethod *method,
+       MonoProfilerCallContext *context)
+{
+       if (!EventEnabledMonoProfilerMethodLeave ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerMethodLeave (
+               (uint64_t)method,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+method_tail_call_callback (
+       MonoProfiler *prof,
+       MonoMethod *method,
+       MonoMethod *target_method)
+{
+       if (!EventEnabledMonoProfilerMethodTailCall ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerMethodTailCall (
+               (uint64_t)method,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+method_exception_leave_callback (
+       MonoProfiler *prof,
+       MonoMethod *method,
+       MonoObject *exc)
+{
+       if (!EventEnabledMonoProfilerMethodExceptionLeave ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerMethodExceptionLeave (
+               (uint64_t)method,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+method_free_callback (
+       MonoProfiler *prof,
+       MonoMethod *method)
+{
+       if (!EventEnabledMonoProfilerMethodFree ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerMethodFree (
+               (uint64_t)method,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+method_begin_invoke_callback (
+       MonoProfiler *prof,
+       MonoMethod *method)
+{
+       if (!EventEnabledMonoProfilerMethodBeginInvoke ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerMethodBeginInvoke (
+               (uint64_t)method,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+method_end_invoke_callback (
+       MonoProfiler *prof,
+       MonoMethod *method)
+{
+       if (!EventEnabledMonoProfilerMethodEndInvoke ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerMethodEndInvoke (
+               (uint64_t)method,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+MonoProfilerCallInstrumentationFlags
+method_instrumentation_filter_callback (
+       MonoProfiler *prof,
+       MonoMethod *method)
+{
+       if (_mono_profiler_provider_callspec.len > 0 && !mono_callspec_eval (method, &_mono_profiler_provider_callspec))
+               return MONO_PROFILER_CALL_INSTRUMENTATION_NONE;
+
+       return MONO_PROFILER_CALL_INSTRUMENTATION_ENTER |
+                       MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE |
+                       MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL |
+                       MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE;
+}
+
+static
+void
+exception_throw_callback (
+       MonoProfiler *prof,
+       MonoObject *exc)
+{
+       if (!EventEnabledMonoProfilerExceptionThrow ())
+               return;
+
+       uint64_t type_id = 0;
+
+       if (exc && mono_object_class(exc))
+               type_id = (uint64_t)m_class_get_byval_arg (mono_object_class(exc));
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerExceptionThrow (
+               type_id,
+               SGEN_POINTER_UNTAG_ALL (exc),
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+exception_clause_callback (
+       MonoProfiler *prof,
+       MonoMethod *method,
+       uint32_t clause_num,
+       MonoExceptionEnum clause_type,
+       MonoObject *exc)
+{
+       if (!EventEnabledMonoProfilerExceptionClause ())
+               return;
+
+       uint64_t type_id = 0;
+
+       if (exc && mono_object_class(exc))
+               type_id = (uint64_t)m_class_get_byval_arg (mono_object_class(exc));
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerExceptionClause (
+               (uint8_t)clause_type,
+               clause_num,
+               (uint64_t)method,
+               type_id,
+               SGEN_POINTER_UNTAG_ALL (exc),
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+gc_event_callback (
+       MonoProfiler *prof,
+       MonoProfilerGCEvent gc_event,
+       uint32_t generation,
+       mono_bool serial)
+{
+       switch (gc_event) {
+       case MONO_GC_EVENT_PRE_STOP_WORLD:
+       case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED:
+       {
+               FireEtwMonoProfilerGCEvent (
+                       (uint8_t)gc_event,
+                       generation,
+                       NULL,
+                       NULL);
+               break;
+       }
+       case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED:
+       {
+               FireEtwMonoProfilerGCEvent (
+                       (uint8_t)gc_event,
+                       generation,
+                       NULL,
+                       NULL);
+
+               gc_in_progress_start ();
+
+               if (gc_heap_dump_in_progress ()) {
+                       FireEtwMonoProfilerGCHeapDumpStart (
+                               provider_params_get_heap_collect_ondemand_value (),
+                               NULL,
+                               NULL);
+               }
+
+               break;
+       }
+       case MONO_GC_EVENT_POST_STOP_WORLD:
+       {
+               if (gc_in_progress ()) {
+                       uint64_t enabled_keywords = RUNTIME_MONO_PROFILER_PROVIDER_CONTEXT.EnabledKeywordsBitmask;
+
+                       if (is_keword_enabled (enabled_keywords, GC_ROOT_KEYWORD)) {
+                               mono_profiler_set_gc_root_register_callback (_mono_profiler_provider, NULL);
+                               mono_profiler_set_gc_root_unregister_callback (_mono_profiler_provider, NULL);
+                               mono_profiler_set_gc_root_register_callback (_mono_heap_dump_profiler_provider, buffer_gc_event_root_register_callback);
+                               mono_profiler_set_gc_root_unregister_callback (_mono_heap_dump_profiler_provider, buffer_gc_event_root_unregister_callback);
+                       }
+
+                       if (gc_heap_dump_in_progress ()) {
+                               if (is_keword_enabled (enabled_keywords, GC_ROOT_KEYWORD)) {
+                                       mono_profiler_set_gc_roots_callback (_mono_heap_dump_profiler_provider, buffer_gc_event_roots_callback);
+                               }
+
+                               if (is_keword_enabled (enabled_keywords, GC_MOVES_KEYWORD)) {
+                                       mono_profiler_set_gc_moves_callback (_mono_heap_dump_profiler_provider, buffer_gc_event_moves_callback);
+                               }
+
+                               if (is_keword_enabled (enabled_keywords, GC_RESIZE_KEYWORD)) {
+                                       mono_profiler_set_gc_resize_callback (_mono_heap_dump_profiler_provider, buffer_gc_event_resize_callback);
+                               }
+                       }
+
+                       buffer_gc_event (
+                               (uint8_t)gc_event,
+                               generation);
+               }
+               break;
+       }
+       case MONO_GC_EVENT_START:
+       case MONO_GC_EVENT_END:
+       {
+               if (gc_in_progress ()) {
+                       buffer_gc_event (
+                               (uint8_t)gc_event,
+                               generation);
+               }
+               break;
+       }
+       case MONO_GC_EVENT_PRE_START_WORLD:
+       {
+               if (gc_in_progress ()) {
+                       uint64_t enabled_keywords = RUNTIME_MONO_PROFILER_PROVIDER_CONTEXT.EnabledKeywordsBitmask;
+
+                       if (gc_heap_dump_in_progress () && is_keword_enabled (enabled_keywords, GC_HEAP_DUMP_KEYWORD))
+                               mono_gc_walk_heap (0, buffer_gc_event_heap_dump_object_reference_callback, NULL);
+
+                       mono_profiler_set_gc_root_register_callback (_mono_heap_dump_profiler_provider, NULL);
+                       mono_profiler_set_gc_root_unregister_callback (_mono_heap_dump_profiler_provider, NULL);
+                       mono_profiler_set_gc_roots_callback (_mono_heap_dump_profiler_provider, NULL);
+                       mono_profiler_set_gc_moves_callback (_mono_heap_dump_profiler_provider, NULL);
+                       mono_profiler_set_gc_resize_callback (_mono_heap_dump_profiler_provider, NULL);
+
+                       if (is_keword_enabled (enabled_keywords, GC_ROOT_KEYWORD)) {
+                               mono_profiler_set_gc_root_register_callback (_mono_profiler_provider, gc_root_register_callback);
+                               mono_profiler_set_gc_root_unregister_callback (_mono_profiler_provider, gc_root_unregister_callback);
+                       }
+
+                       buffer_gc_event (
+                               (uint8_t)gc_event,
+                               generation);
+               }
+
+               break;
+       }
+       case MONO_GC_EVENT_POST_START_WORLD:
+       {
+               if (gc_in_progress ()) {
+                       GHashTable *cache = NULL;
+                       uint64_t enabled_keywords = RUNTIME_MONO_PROFILER_PROVIDER_CONTEXT.EnabledKeywordsBitmask;
+
+                       if (gc_heap_dump_in_progress () && is_keword_enabled (enabled_keywords, GC_HEAP_DUMP_VTABLE_CLASS_REF_KEYWORD))
+                               cache = g_hash_table_new_full (NULL, NULL, NULL, NULL);
+
+                       fire_buffered_gc_events_in_alloc_order (cache);
+                       fire_cached_gc_events (cache);
+
+                       if (cache)
+                               g_hash_table_destroy (cache);
+
+                       if (gc_heap_dump_in_progress ()) {
+                               FireEtwMonoProfilerGCHeapDumpStop (
+                                       NULL,
+                                       NULL);
+                       }
+
+                       FireEtwMonoProfilerGCEvent (
+                               (uint8_t)gc_event,
+                               generation,
+                               NULL,
+                               NULL);
+
+                       if (!is_keword_enabled (enabled_keywords, GC_KEYWORD))
+                               mono_profiler_set_gc_event_callback (_mono_profiler_provider, NULL);
+
+                       gc_heap_dump_in_progress_stop ();
+                       gc_in_progress_stop ();
+               }
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+static
+void
+gc_allocation_callback (
+       MonoProfiler *prof,
+       MonoObject *object)
+{
+       if (!EventEnabledMonoProfilerGCAllocation ())
+               return;
+
+       uint64_t vtable_id = 0;
+       uint64_t object_size = 0;
+
+       if (object) {
+               vtable_id = (uint64_t)mono_object_get_vtable_internal (object);
+               object_size = (uint64_t)mono_object_get_size_internal (object);
+
+               /* account for object alignment */
+               object_size += 7;
+               object_size &= ~7;
+       }
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerGCAllocation (
+               vtable_id,
+               SGEN_POINTER_UNTAG_ALL (object),
+               object_size,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+gc_handle_created_callback (
+       MonoProfiler *prof,
+       uint32_t handle,
+       MonoGCHandleType type,
+       MonoObject *object)
+{
+       if (!EventEnabledMonoProfilerGCHandleCreated ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerGCHandleCreated (
+               handle,
+               (uint8_t)type,
+               SGEN_POINTER_UNTAG_ALL (object),
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+gc_handle_deleted_callback (
+       MonoProfiler *prof,
+       uint32_t handle,
+       MonoGCHandleType type)
+{
+       if (!EventEnabledMonoProfilerGCHandleDeleted ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerGCHandleDeleted (
+               handle,
+               (uint8_t)type,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+gc_finalizing_callback (MonoProfiler *prof)
+{
+       if (!EventEnabledMonoProfilerGCFinalizing ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerGCFinalizing (
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+gc_finalized_callback (MonoProfiler *prof)
+{
+       if (!EventEnabledMonoProfilerGCFinalized ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerGCFinalized (
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+gc_finalizing_object_callback (
+       MonoProfiler *prof,
+       MonoObject *object)
+{
+       if (!EventEnabledMonoProfilerGCFinalizingObject ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerGCFinalizingObject (
+               SGEN_POINTER_UNTAG_ALL (object),
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+gc_finalized_object_callback (
+       MonoProfiler *prof,
+       MonoObject * object)
+{
+       if (!EventEnabledMonoProfilerGCFinalizedObject ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerGCFinalizedObject (
+               SGEN_POINTER_UNTAG_ALL (object),
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+gc_root_register_callback (
+       MonoProfiler *prof,
+       const mono_byte *start,
+       uintptr_t size,
+       MonoGCRootSource source,
+       const void * key,
+       const char * name)
+{
+       if (!EventEnabledMonoProfilerGCRootRegister ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerGCRootRegister (
+               start,
+               (uint64_t)size,
+               (uint8_t) source,
+               (uint64_t)key,
+               (const ep_char8_t *)(name ? name : ""),
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+gc_root_unregister_callback (
+       MonoProfiler *prof,
+       const mono_byte *start)
+{
+       if (!EventEnabledMonoProfilerGCRootUnregister ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerGCRootUnregister (
+               start,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+monitor_contention_callback (
+       MonoProfiler *prof,
+       MonoObject *object)
+{
+       if (!EventEnabledMonoProfilerMonitorContention ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerMonitorContention (
+               SGEN_POINTER_UNTAG_ALL (object),
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+monitor_failed_callback (
+       MonoProfiler *prof,
+       MonoObject *object)
+{
+       if (!EventEnabledMonoProfilerMonitorFailed ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerMonitorFailed (
+               SGEN_POINTER_UNTAG_ALL (object),
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+monitor_acquired_callback (
+       MonoProfiler *prof,
+       MonoObject *object)
+{
+       if (!EventEnabledMonoProfilerMonitorAcquired ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerMonitorAcquired (
+               SGEN_POINTER_UNTAG_ALL (object),
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+thread_started_callback (
+       MonoProfiler *prof,
+       uintptr_t tid)
+{
+       if (!EventEnabledMonoProfilerThreadStarted ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerThreadStarted (
+               (uint64_t)tid,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+thread_stopping_callback (
+       MonoProfiler *prof,
+       uintptr_t tid)
+{
+       if (!EventEnabledMonoProfilerThreadStopping ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerThreadStopping (
+               (uint64_t)tid,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+thread_stopped_callback (
+       MonoProfiler *prof,
+       uintptr_t tid)
+{
+       if (!EventEnabledMonoProfilerThreadStopped ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerThreadStopped (
+               (uint64_t)tid,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+thread_exited_callback (
+       MonoProfiler *prof,
+       uintptr_t tid)
+{
+       if (!EventEnabledMonoProfilerThreadExited ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerThreadExited (
+               (uint64_t)tid,
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+thread_name_callback (
+       MonoProfiler *prof,
+       uintptr_t tid,
+       const char *name)
+{
+       if (!EventEnabledMonoProfilerThreadName ())
+               return;
+
+       fire_event_enter ();
+
+       FireEtwMonoProfilerThreadName (
+               (uint64_t)tid,
+               (ep_char8_t *)(name ? name : ""),
+               NULL,
+               NULL);
+
+       fire_event_exit ();
+}
+
+static
+void
+calculate_live_keywords (
+       uint64_t *live_keywords,
+       bool *trigger_heap_dump)
+{
+       uint64_t keywords[] = { GC_HEAP_COLLECT_KEYWORD };
+       uint64_t count[] = { 0 };
+
+       ep_requires_lock_held ();
+
+       EP_ASSERT (G_N_ELEMENTS (keywords) == G_N_ELEMENTS (count));
+       *live_keywords = ep_rt_mono_session_calculate_and_count_all_keywords (
+               "Microsoft-DotNETRuntimeMonoProfiler",
+               keywords,
+               count,
+               G_N_ELEMENTS (count));
+
+       *trigger_heap_dump = ep_rt_mono_is_runtime_initialized ();
+       *trigger_heap_dump &= is_keword_enabled (*live_keywords, GC_KEYWORD);
+       *trigger_heap_dump &= is_keword_enabled (*live_keywords, GC_HEAP_COLLECT_KEYWORD);
+       *trigger_heap_dump &= count [0] > _gc_heap_dump_trigger_count;
+
+       _gc_heap_dump_trigger_count = count [0];
+
+       ep_requires_lock_held ();
+}
+
+static
+void
+eventpipe_provider_callback (
+       const uint8_t *source_id,
+       unsigned long is_enabled,
+       uint8_t level,
+       uint64_t match_any_keywords,
+       uint64_t match_all_keywords,
+       EventFilterDescriptor *filter_data,
+       void *callback_data)
+{
+       EP_ASSERT (_mono_profiler_provider_enabled);
+
+       ep_rt_config_requires_lock_not_held ();
+       ep_rt_spin_lock_requires_lock_held (&_gc_lock);
+
+       EP_ASSERT (_mono_profiler_provider != NULL);
+       EP_ASSERT (_mono_heap_dump_profiler_provider != NULL);
+
+       EP_LOCK_ENTER (section1)
+               uint64_t live_keywords = 0;
+               bool trigger_heap_dump = false;
+               calculate_live_keywords (&live_keywords, &trigger_heap_dump);
+
+               if (is_keword_enabled(live_keywords, LOADER_KEYWORD)) {
+                       mono_profiler_set_domain_loading_callback (_mono_profiler_provider, app_domain_loading_callback);
+                       mono_profiler_set_domain_loaded_callback (_mono_profiler_provider, app_domain_loaded_callback);
+                       mono_profiler_set_domain_unloading_callback (_mono_profiler_provider, app_domain_unloading_callback);
+                       mono_profiler_set_domain_unloaded_callback (_mono_profiler_provider, app_domain_unloaded_callback);
+                       mono_profiler_set_domain_name_callback (_mono_profiler_provider, app_domain_name_callback);
+                       mono_profiler_set_image_loading_callback (_mono_profiler_provider, module_loading_callback);
+                       mono_profiler_set_image_failed_callback (_mono_profiler_provider, module_failed_callback);
+                       mono_profiler_set_image_loaded_callback (_mono_profiler_provider, module_loaded_callback);
+                       mono_profiler_set_image_unloading_callback (_mono_profiler_provider, module_unloading_callback);
+                       mono_profiler_set_image_unloaded_callback (_mono_profiler_provider, module_unloaded_callback);
+                       mono_profiler_set_assembly_loading_callback (_mono_profiler_provider, assembly_loading_callback);
+                       mono_profiler_set_assembly_loaded_callback (_mono_profiler_provider, assembly_loaded_callback);
+                       mono_profiler_set_assembly_unloading_callback (_mono_profiler_provider, assembly_unloading_callback);
+                       mono_profiler_set_assembly_unloaded_callback (_mono_profiler_provider, assembly_unloaded_callback);
+               } else {
+                       mono_profiler_set_domain_loading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_domain_loaded_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_domain_unloading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_domain_unloaded_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_domain_name_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_image_loading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_image_failed_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_image_loaded_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_image_unloading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_image_unloaded_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_assembly_loading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_assembly_loaded_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_assembly_unloading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_assembly_unloaded_callback (_mono_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled(live_keywords, JIT_KEYWORD)) {
+                       mono_profiler_set_jit_begin_callback (_mono_profiler_provider, jit_begin_callback);
+                       mono_profiler_set_jit_failed_callback (_mono_profiler_provider, jit_failed_callback);
+                       mono_profiler_set_jit_done_callback (_mono_profiler_provider, jit_done_callback);
+                       mono_profiler_set_jit_chunk_created_callback (_mono_profiler_provider, jit_chunk_created_callback);
+                       mono_profiler_set_jit_chunk_destroyed_callback (_mono_profiler_provider, jit_chunk_destroyed_callback);
+                       mono_profiler_set_jit_code_buffer_callback (_mono_profiler_provider, jit_code_buffer_callback);
+               } else {
+                       mono_profiler_set_jit_begin_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_jit_failed_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_jit_done_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_jit_chunk_created_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_jit_chunk_destroyed_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_jit_code_buffer_callback (_mono_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled(live_keywords, TYPE_LOADING_KEYWORD)) {
+                       mono_profiler_set_class_loading_callback (_mono_profiler_provider, class_loading_callback);
+                       mono_profiler_set_class_failed_callback (_mono_profiler_provider, class_failed_callback);
+                       mono_profiler_set_class_loaded_callback (_mono_profiler_provider, class_loaded_callback);
+                       mono_profiler_set_vtable_loading_callback (_mono_profiler_provider, vtable_loading_callback);
+                       mono_profiler_set_vtable_failed_callback (_mono_profiler_provider, vtable_failed_callback);
+                       mono_profiler_set_vtable_loaded_callback (_mono_profiler_provider, vtable_loaded_callback);
+               } else {
+                       mono_profiler_set_class_loading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_class_failed_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_class_loaded_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_vtable_loading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_vtable_failed_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_vtable_loaded_callback (_mono_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled(live_keywords, METHOD_TRACING_KEYWORD)) {
+                       mono_profiler_set_method_enter_callback (_mono_profiler_provider, method_enter_callback);
+                       mono_profiler_set_method_leave_callback (_mono_profiler_provider, method_leave_callback);
+                       mono_profiler_set_method_tail_call_callback (_mono_profiler_provider, method_tail_call_callback);
+                       mono_profiler_set_method_exception_leave_callback (_mono_profiler_provider, method_exception_leave_callback);
+                       mono_profiler_set_method_free_callback (_mono_profiler_provider, method_free_callback);
+                       mono_profiler_set_method_begin_invoke_callback (_mono_profiler_provider, method_begin_invoke_callback);
+                       mono_profiler_set_method_end_invoke_callback (_mono_profiler_provider, method_end_invoke_callback);
+               } else {
+                       mono_profiler_set_method_enter_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_method_leave_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_method_tail_call_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_method_exception_leave_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_method_free_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_method_begin_invoke_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_method_end_invoke_callback (_mono_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled(live_keywords, EXCEPTION_KEYWORD)) {
+                       mono_profiler_set_exception_throw_callback (_mono_profiler_provider, exception_throw_callback);
+                       mono_profiler_set_exception_clause_callback (_mono_profiler_provider, exception_clause_callback);
+               } else {
+                       mono_profiler_set_exception_throw_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_exception_clause_callback (_mono_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled(live_keywords, GC_KEYWORD)) {
+                       mono_profiler_set_gc_event_callback (_mono_profiler_provider, gc_event_callback);
+               } else {
+                       // NOTE, disabled in mono_profiler_gc_event, MONO_GC_EVENT_POST_START_WORLD to make sure all
+                       // callbacks during GC fires.
+               }
+
+               if (is_keword_enabled(live_keywords, GC_ALLOCATION_KEYWORD)) {
+                       mono_profiler_set_gc_allocation_callback (_mono_profiler_provider, gc_allocation_callback);
+               } else {
+                       mono_profiler_set_gc_allocation_callback (_mono_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled(live_keywords, GC_HANDLE_KEYWORD)) {
+                       mono_profiler_set_gc_handle_created_callback (_mono_profiler_provider, gc_handle_created_callback);
+                       mono_profiler_set_gc_handle_deleted_callback (_mono_profiler_provider, gc_handle_deleted_callback);
+               } else {
+                       mono_profiler_set_gc_handle_created_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_handle_deleted_callback (_mono_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled(live_keywords, GC_FINALIZATION_KEYWORD)) {
+                       mono_profiler_set_gc_finalizing_callback (_mono_profiler_provider, gc_finalizing_callback);
+                       mono_profiler_set_gc_finalized_callback (_mono_profiler_provider, gc_finalized_callback);
+                       mono_profiler_set_gc_finalizing_object_callback (_mono_profiler_provider, gc_finalizing_object_callback);
+                       mono_profiler_set_gc_finalized_object_callback (_mono_profiler_provider, gc_finalized_object_callback);
+               } else {
+                       mono_profiler_set_gc_finalizing_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_finalized_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_finalizing_object_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_finalized_object_callback (_mono_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled(live_keywords, GC_ROOT_KEYWORD)) {
+                       mono_profiler_set_gc_root_register_callback (_mono_profiler_provider, gc_root_register_callback);
+                       mono_profiler_set_gc_root_unregister_callback (_mono_profiler_provider, gc_root_unregister_callback);
+               } else {
+                       mono_profiler_set_gc_root_register_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_root_unregister_callback (_mono_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled (live_keywords, GC_HEAP_COLLECT_KEYWORD)) {
+                       mono_profiler_set_gc_finalized_callback (_mono_heap_dump_profiler_provider, gc_heap_dump_trigger_callback);
+               } else {
+                       mono_profiler_set_gc_finalized_callback (_mono_heap_dump_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled (live_keywords, MONITOR_KEYWORD) || is_keword_enabled (match_any_keywords, CONTENTION_KEYWORD)) {
+                       mono_profiler_set_monitor_contention_callback (_mono_profiler_provider, monitor_contention_callback);
+               } else {
+                       mono_profiler_set_monitor_contention_callback (_mono_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled (live_keywords, MONITOR_KEYWORD)) {
+                       mono_profiler_set_monitor_failed_callback (_mono_profiler_provider, monitor_failed_callback);
+                       mono_profiler_set_monitor_acquired_callback (_mono_profiler_provider, monitor_acquired_callback);
+               } else {
+                       mono_profiler_set_monitor_failed_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_monitor_acquired_callback (_mono_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled (live_keywords, THREADING_KEYWORD)) {
+                       mono_profiler_set_thread_started_callback (_mono_profiler_provider, thread_started_callback);
+                       mono_profiler_set_thread_stopping_callback (_mono_profiler_provider, thread_stopping_callback);
+                       mono_profiler_set_thread_stopped_callback (_mono_profiler_provider, thread_stopped_callback);
+                       mono_profiler_set_thread_exited_callback (_mono_profiler_provider, thread_exited_callback);
+                       mono_profiler_set_thread_name_callback (_mono_profiler_provider, thread_name_callback);
+               } else {
+                       mono_profiler_set_thread_started_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_thread_stopping_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_thread_stopped_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_thread_exited_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_thread_name_callback (_mono_profiler_provider, NULL);
+               }
+
+               if (_mono_profiler_provider_callspec.enabled) {
+                       if (is_keword_enabled(live_keywords, METHOD_INSTRUMENTATION_KEYWORD)) {
+                               mono_profiler_set_call_instrumentation_filter_callback (_mono_profiler_provider, method_instrumentation_filter_callback);
+                       } else {
+                               mono_profiler_set_call_instrumentation_filter_callback (_mono_profiler_provider, NULL);
+                       }
+               }
+
+               if (trigger_heap_dump) {
+                       if (filter_data) {
+                               if (provider_params_contains_heap_collect_ondemand (filter_data) && !provider_params_remove (filter_data)) {
+                                       provider_params_add (filter_data);
+                               }
+                       }
+
+                       gc_heap_dump_request_params_push_value (filter_data);
+                       gc_heap_dump_requests_inc ();
+                       mono_gc_finalize_notify ();
+               } else {
+                       provider_params_free ();
+               }
+
+               RUNTIME_MONO_PROFILER_PROVIDER_CONTEXT.Level = level;
+               RUNTIME_MONO_PROFILER_PROVIDER_CONTEXT.EnabledKeywordsBitmask = live_keywords;
+               RUNTIME_MONO_PROFILER_PROVIDER_CONTEXT.IsEnabled = (live_keywords == 1 ? true : false);
+       EP_LOCK_EXIT (section1)
+
+ep_on_exit:
+       ep_rt_config_requires_lock_not_held ();
+       return;
+
+ep_on_error:
+       ep_exit_error_handler ();
+}
+
+void
+EventPipeEtwCallbackDotNETRuntimeMonoProfiler (
+       const uint8_t *source_id,
+       unsigned long is_enabled,
+       uint8_t level,
+       uint64_t match_any_keywords,
+       uint64_t match_all_keywords,
+       EventFilterDescriptor *filter_data,
+       void *callback_data)
+{
+       if (!_mono_profiler_provider_enabled) {
+               mono_trace (
+                       G_LOG_LEVEL_WARNING,
+                       MONO_TRACE_DIAGNOSTICS,
+                       "Microsoft-DotNETRuntimeMonoProfiler disabled, "
+                       "set MONO_DIAGNOSTICS=--diagnostic-mono-profiler=enable "
+                       "environment variable to enable provider.");
+               return;
+       }
+
+       ep_rt_spin_lock_requires_lock_not_held (&_gc_lock);
+
+       EP_SPIN_LOCK_ENTER (&_gc_lock, section1);
+               eventpipe_provider_callback (
+                       source_id,
+                       is_enabled,
+                       level,
+                       match_any_keywords,
+                       match_all_keywords,
+                       filter_data,
+                       callback_data);
+       EP_SPIN_LOCK_EXIT (&_gc_lock, section1);
+
+ep_on_exit:
+       ep_rt_spin_lock_requires_lock_not_held (&_gc_lock);
+       return;
+
+ep_on_error:
+       ep_exit_error_handler ();
+}
+
+void
+ep_rt_mono_profiler_provider_component_init (void)
+{
+       if (_mono_profiler_provider_enabled) {
+               _mono_profiler_provider = mono_profiler_create (NULL);
+               _mono_heap_dump_profiler_provider = mono_profiler_create (NULL);
+       }
+}
+
+void
+ep_rt_mono_profiler_provider_init (void)
+{
+       if (_mono_profiler_provider_enabled) {
+               EP_ASSERT (_mono_profiler_provider != NULL);
+               EP_ASSERT (_mono_heap_dump_profiler_provider != NULL);
+
+               ep_rt_spin_lock_alloc (&_gc_lock);
+       }
+}
+
+void
+ep_rt_mono_profiler_provider_fini (void)
+{
+       if (_mono_profiler_provider_enabled) {
+               if (_mono_profiler_provider_callspec.enabled)
+                       mono_callspec_cleanup (&_mono_profiler_provider_callspec);
+
+               if (_mono_profiler_provider) {
+                       mono_profiler_set_gc_root_register_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_root_unregister_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_event_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_allocation_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_handle_created_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_handle_deleted_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_finalizing_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_finalized_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_finalizing_object_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_gc_finalized_object_callback (_mono_profiler_provider, NULL);
+
+                       mono_profiler_set_domain_loading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_domain_loaded_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_domain_unloading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_domain_unloaded_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_domain_name_callback (_mono_profiler_provider, NULL);
+
+                       mono_profiler_set_image_loading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_image_failed_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_image_loaded_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_image_unloading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_image_unloaded_callback (_mono_profiler_provider, NULL);
+
+                       mono_profiler_set_assembly_loading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_assembly_loaded_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_assembly_unloading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_assembly_unloaded_callback (_mono_profiler_provider, NULL);
+
+                       mono_profiler_set_jit_begin_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_jit_failed_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_jit_done_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_jit_chunk_created_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_jit_chunk_destroyed_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_jit_code_buffer_callback (_mono_profiler_provider, NULL);
+
+                       mono_profiler_set_class_loading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_class_failed_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_class_loaded_callback (_mono_profiler_provider, NULL);
+
+                       mono_profiler_set_vtable_loading_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_vtable_failed_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_vtable_loaded_callback (_mono_profiler_provider, NULL);
+
+                       mono_profiler_set_method_enter_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_method_leave_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_method_tail_call_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_method_exception_leave_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_method_free_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_method_begin_invoke_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_method_end_invoke_callback (_mono_profiler_provider, NULL);
+
+                       mono_profiler_set_exception_throw_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_exception_clause_callback (_mono_profiler_provider, NULL);
+
+                       mono_profiler_set_monitor_contention_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_monitor_failed_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_monitor_acquired_callback (_mono_profiler_provider, NULL);
+
+                       mono_profiler_set_thread_started_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_thread_stopping_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_thread_stopped_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_thread_exited_callback (_mono_profiler_provider, NULL);
+                       mono_profiler_set_thread_name_callback (_mono_profiler_provider, NULL);
+
+                       mono_profiler_set_call_instrumentation_filter_callback (_mono_profiler_provider, NULL);
+               }
+               _mono_profiler_provider = NULL;
+
+               if (_mono_heap_dump_profiler_provider) {
+                       mono_profiler_set_gc_root_register_callback (_mono_heap_dump_profiler_provider, NULL);
+                       mono_profiler_set_gc_root_unregister_callback (_mono_heap_dump_profiler_provider, NULL);
+                       mono_profiler_set_gc_roots_callback (_mono_heap_dump_profiler_provider, NULL);
+                       mono_profiler_set_gc_moves_callback (_mono_heap_dump_profiler_provider, NULL);
+                       mono_profiler_set_gc_resize_callback (_mono_heap_dump_profiler_provider, NULL);
+                       mono_profiler_set_gc_finalized_callback (_mono_heap_dump_profiler_provider, NULL);
+               }
+               _mono_heap_dump_profiler_provider = NULL;
+
+               _gc_heap_dump_requests = 0;
+               _gc_heap_dump_in_progress = 0;
+               _gc_heap_dump_trigger_count = 0;
+               _gc_state = 0;
+
+               _mono_profiler_provider_enabled = DEFAULT_MONO_PROFILER_PROVIDER_ENABLED;
+
+               gc_heap_dump_mem_block_free_all ();
+
+               gc_heap_dump_request_params_free ();
+               provider_params_free ();
+
+               ep_rt_spin_lock_free (&_gc_lock);
+       }
+}
+
+static
+bool
+profiler_parse_options (const ep_char8_t *option)
+{
+       do {
+               if (!*option)
+                       return false;
+
+               if (!strncmp (option, "enable", 6)) {
+                       _mono_profiler_provider_enabled = true;
+                       option += 6;
+               } else if (!strncmp (option, "disable", 7)) {
+                       _mono_profiler_provider_enabled = false;
+                       option += 7;
+               } else if (!strncmp (option, "alloc", 5)) {
+                       _mono_profiler_provider_enabled = true;
+                       mono_profiler_enable_allocations ();
+                       option += 5;
+               } else if (!strncmp (option, "exception", 9)) {
+                       _mono_profiler_provider_enabled = true;
+                       mono_profiler_enable_clauses ();
+                       option += 9;
+               /*} else if (!strncmp (option, "sample", 6)) {
+               *       _mono_profiler_provider_enabled = true;
+                       mono_profiler_enable_sampling (_mono_profiler_provider);
+                       option += 6;*/
+               } else {
+                       return false;
+               }
+
+               if (*option == ',')
+                       option++;
+       } while (*option);
+
+       return true;
+}
+
+bool
+ep_rt_mono_profiler_provider_parse_options (const char *options)
+{
+       if (!options)
+               return false;
+
+       if (strncmp (options, "--diagnostic-mono-profiler=", 27) == 0) {
+               if (!profiler_parse_options (options + 27))
+                       mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed parsing MONO_DIAGNOSTICS environment variable option: %s", options);
+               return true;
+       } else if (strncmp (options, "--diagnostic-mono-profiler-callspec=", 36) == 0) {
+               char *errstr = NULL;
+               if (!mono_callspec_parse (options + 36, &_mono_profiler_provider_callspec, &errstr)) {
+                       mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed parsing '%s': %s", options, errstr);
+                       g_free (errstr);
+                       mono_callspec_cleanup (&_mono_profiler_provider_callspec);
+               } else {
+                       mono_profiler_set_call_instrumentation_filter_callback (_mono_profiler_provider, method_instrumentation_filter_callback);
+               }
+               return true;
+       } else {
+               return false;
+       }
+}
+
+#endif /* ENABLE_PERFTRACING */
+
+MONO_EMPTY_SOURCE_FILE(eventpipe_rt_mono_profiler_provider);
diff --git a/src/mono/mono/eventpipe/ep-rt-mono-runtime-provider.c b/src/mono/mono/eventpipe/ep-rt-mono-runtime-provider.c
new file mode 100644 (file)
index 0000000..151dafc
--- /dev/null
@@ -0,0 +1,4675 @@
+#include <config.h>
+
+#ifdef ENABLE_PERFTRACING
+#include <eventpipe/ep-rt-config.h>
+#include <eventpipe/ep-types.h>
+#include <eventpipe/ep-rt.h>
+#include <eventpipe/ep.h>
+
+#include <eglib/gmodule.h>
+#include <mono/metadata/profiler.h>
+#include <mono/metadata/debug-internals.h>
+#include <mono/metadata/gc-internals.h>
+#include <mono/metadata/mono-endian.h>
+#include <mono/mini/mini-runtime.h>
+#include <mono/sgen/sgen-conf.h>
+#include <mono/sgen/sgen-tagged-pointer.h>
+#include <clretwallmain.h>
+
+extern EVENTPIPE_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context;
+extern EVENTPIPE_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context;
+
+#define RUNTIME_PROVIDER_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context
+#define RUNTIME_RUNDOWN_PROVIDER_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context
+
+#define NUM_NANOSECONDS_IN_1_MS 1000000
+
+// Sample profiler.
+static GArray * _sampled_thread_callstacks = NULL;
+static uint32_t _max_sampled_thread_count = 32;
+
+// Mono profilers.
+extern MonoProfilerHandle _ep_rt_mono_default_profiler_provider;
+
+// Phantom JIT compile method.
+static MonoMethod *_runtime_helper_compile_method = NULL;
+static MonoJitInfo *_runtime_helper_compile_method_jitinfo = NULL;
+
+// Monitor.Enter methods.
+static MonoMethod *_monitor_enter_method = NULL;
+static MonoJitInfo *_monitor_enter_method_jitinfo = NULL;
+
+static MonoMethod *_monitor_enter_v4_method = NULL;
+static MonoJitInfo *_monitor_enter_v4_method_jitinfo = NULL;
+
+// GC roots table.
+static dn_umap_t _gc_roots_table = {0};
+
+// Lock used for GC related activities.
+static ep_rt_spin_lock_handle_t _gc_lock = {0};
+
+// Rundown types.
+typedef
+bool
+(*fire_method_rundown_events_func)(
+       const uint64_t method_id,
+       const uint64_t module_id,
+       const uint64_t method_start_address,
+       const uint32_t method_size,
+       const uint32_t method_token,
+       const uint32_t method_flags,
+       const ep_char8_t *method_namespace,
+       const ep_char8_t *method_name,
+       const ep_char8_t *method_signature,
+       const uint16_t count_of_map_entries,
+       const uint32_t *il_offsets,
+       const uint32_t *native_offsets,
+       bool aot_method,
+       bool verbose,
+       void *user_data);
+
+typedef
+bool
+(*fire_assembly_rundown_events_func)(
+       const uint64_t domain_id,
+       const uint64_t assembly_id,
+       const uint32_t assembly_flags,
+       const uint32_t binding_id,
+       const ep_char8_t *assembly_name,
+       const uint64_t module_id,
+       const uint32_t module_flags,
+       const uint32_t reserved_flags,
+       const ep_char8_t *module_il_path,
+       const ep_char8_t *module_native_path,
+       const uint8_t *managed_pdb_signature,
+       const uint32_t managed_pdb_age,
+       const ep_char8_t *managed_pdb_build_path,
+       const uint8_t *native_pdb_signature,
+       const uint32_t native_pdb_age,
+       const ep_char8_t *native_pdb_build_path,
+       void *user_data);
+
+typedef
+bool
+(*fire_domain_rundown_events_func)(
+       const uint64_t domain_id,
+       const uint32_t domain_flags,
+       const ep_char8_t *domain_name,
+       const uint32_t domain_index,
+       void *user_data);
+
+typedef struct _FireMethodEventsData {
+       MonoDomain *domain;
+       uint8_t *buffer;
+       size_t buffer_size;
+       fire_method_rundown_events_func method_events_func;
+} FireMethodEventsData;
+
+typedef struct _StackWalkData {
+       EventPipeStackContents *stack_contents;
+       bool top_frame;
+       bool async_frame;
+       bool safe_point_frame;
+       bool runtime_invoke_frame;
+} StackWalkData;
+
+typedef struct _SampleProfileStackWalkData {
+       StackWalkData stack_walk_data;
+       EventPipeStackContents stack_contents;
+       uint64_t thread_id;
+       uintptr_t thread_ip;
+       uint32_t payload_data;
+} SampleProfileStackWalkData;
+
+// Rundown flags.
+#define RUNTIME_SKU_MONO 0x4
+#define METHOD_FLAGS_DYNAMIC_METHOD 0x1
+#define METHOD_FLAGS_GENERIC_METHOD 0x2
+#define METHOD_FLAGS_SHARED_GENERIC_METHOD 0x4
+#define METHOD_FLAGS_JITTED_METHOD 0x8
+#define METHOD_FLAGS_JITTED_HELPER_METHOD 0x10
+#define METHOD_FLAGS_EXTENT_HOT_SECTION 0x00000000
+#define METHOD_FLAGS_EXTENT_COLD_SECTION 0x10000000
+
+#define MODULE_FLAGS_NATIVE_MODULE 0x2
+#define MODULE_FLAGS_DYNAMIC_MODULE 0x4
+#define MODULE_FLAGS_MANIFEST_MODULE 0x8
+
+#define ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY 0x2
+#define ASSEMBLY_FLAGS_NATIVE_ASSEMBLY 0x4
+#define ASSEMBLY_FLAGS_COLLECTIBLE_ASSEMBLY 0x8
+
+#define DOMAIN_FLAGS_DEFAULT_DOMAIN 0x1
+#define DOMAIN_FLAGS_EXECUTABLE_DOMAIN 0x2
+
+// Event data types.
+struct _ModuleEventData {
+       uint8_t module_il_pdb_signature [EP_GUID_SIZE];
+       uint8_t module_native_pdb_signature [EP_GUID_SIZE];
+       uint64_t domain_id;
+       uint64_t module_id;
+       uint64_t assembly_id;
+       const char *module_il_path;
+       const char *module_il_pdb_path;
+       const char *module_native_path;
+       const char *module_native_pdb_path;
+       uint32_t module_il_pdb_age;
+       uint32_t module_native_pdb_age;
+       uint32_t reserved_flags;
+       uint32_t module_flags;
+};
+
+typedef struct _ModuleEventData ModuleEventData;
+
+struct _AssemblyEventData {
+       uint64_t domain_id;
+       uint64_t assembly_id;
+       uint64_t binding_id;
+       char *assembly_name;
+       uint32_t assembly_flags;
+};
+
+typedef struct _AssemblyEventData AssemblyEventData;
+
+// Event flags.
+#define THREAD_FLAGS_GC_SPECIAL 0x00000001
+#define THREAD_FLAGS_FINALIZER 0x00000002
+#define THREAD_FLAGS_THREADPOOL_WORKER 0x00000004
+
+#define EXCEPTION_THROWN_FLAGS_HAS_INNER 0x1
+#define EXCEPTION_THROWN_FLAGS_IS_NESTED 0x2
+#define EXCEPTION_THROWN_FLAGS_IS_RETHROWN 0x4
+#define EXCEPTION_THROWN_FLAGS_IS_CSE 0x8
+#define EXCEPTION_THROWN_FLAGS_IS_CLS_COMPLIANT 0x10
+
+// BulkType types.
+
+typedef enum {
+       TYPE_FLAGS_DELEGATE = 0x1,
+       TYPE_FLAGS_FINALIZABLE = 0x2,
+       TYPE_FLAGS_EXTERNALLY_IMPLEMENTED_COM_OBJECT = 0x4,
+       TYPE_FLAGS_ARRAY = 0x8,
+
+       TYPE_FLAGS_ARRAY_RANK_MASK = 0x3F00,
+       TYPE_FLAGS_ARRAY_RANK_SHIFT = 8,
+       TYPE_FLAGS_ARRAY_RANK_MAX = TYPE_FLAGS_ARRAY_RANK_MASK >> TYPE_FLAGS_ARRAY_RANK_SHIFT
+} TypeFlags;
+
+// This only contains the fixed-size data at the top of each struct in
+// the bulk type event.  These fields must still match exactly the initial
+// fields of the struct described in the manifest.
+typedef struct _EventStructBulkTypeFixedSizedData {
+       uint64_t type_id;
+       uint64_t module_id;
+       uint32_t type_name_id;
+       uint32_t flags;
+       uint8_t cor_element_type;
+} EventStructBulkTypeFixedSizedData;
+
+// Represents one instance of the Value struct inside a single BulkType event
+typedef struct _BulkTypeValue {
+       EventStructBulkTypeFixedSizedData fixed_sized_data;
+       uint32_t type_parameters_count;
+       MonoType **mono_type_parameters;
+       const ep_char8_t *name;
+} BulkTypeValue;
+
+// ETW has a limitation of 64K for TOTAL event Size, however there is overhead associated with
+// the event headers.   It is unclear exactly how much that is, but 1K should be sufficiently
+// far away to avoid problems without sacrificing the perf of bulk processing.
+#define MAX_EVENT_BYTE_COUNT (63 * 1024)
+
+// The maximum event size, and the size of the buffer that we allocate to hold the event contents.
+#define MAX_SIZE_OF_EVENT_BUFFER 65536
+
+// Estimate of how many bytes we can squeeze in the event data for the value struct
+// array. (Intentionally overestimate the size of the non-array parts to keep it safe.)
+// This follows CoreCLR's kMaxBytesTypeValues.
+#define MAX_TYPE_VALUES_BYTES (MAX_EVENT_BYTE_COUNT - 0x30)
+
+// Estimate of how many type value elements we can put into the struct array, while
+// staying under the ETW event size limit. Note that this is impossible to calculate
+// perfectly, since each element of the struct array has variable size.
+//
+// In addition to the byte-size limit per event, Windows always forces on us a
+// max-number-of-descriptors per event, which in the case of BulkType, will kick in
+// far sooner. There's a max number of 128 descriptors allowed per event. 2 are used
+// for Count + ClrInstanceID. Then 4 per batched value. (Might actually be 3 if there
+// are no type parameters to log, but let's overestimate at 4 per value).
+#define K_MAX_COUNT_TYPE_VALUES ((uint32_t)(128 - 2) / 4)
+
+typedef enum {
+       TYPE_LOG_BEHAVIOR_IF_FIRST_TIME,
+       TYPE_LOG_BEHAVIOR_ALWAYS_LOG,
+       TYPE_LOG_BEHAVIOR_ALWAYS_LOG_TOP_LEVEL
+} TypeLogBehavior;
+
+typedef struct _BulkTypeEventLogger {
+       BulkTypeValue bulk_type_values [K_MAX_COUNT_TYPE_VALUES];
+       uint8_t *bulk_type_event_buffer;
+       uint32_t bulk_type_value_count;
+       uint32_t bulk_type_value_byte_count;
+       MonoMemPool *mem_pool;
+       dn_umap_t *type_cache;
+} BulkTypeEventLogger;
+
+// ETW has a limit for maximum event size. Do not log overly large method type argument sets
+static const uint32_t MAX_METHOD_TYPE_ARGUMENT_COUNT = 1024;
+
+// GC roots type.
+typedef struct _GCRootData {
+       uintptr_t start;
+       uintptr_t end;
+       const void *key;
+       char *name;
+       MonoGCRootSource source;
+} GCRootData;
+
+// GC heap dump types.
+typedef enum {
+       BUFFERED_GC_EVENT_OBJECT_REF = 1,
+       BUFFERED_GC_EVENT_ROOTS = 2,
+} BufferedGCEventType;
+
+typedef struct _BufferedGCEvent BufferedGCEvent;
+struct _BufferedGCEvent {
+       BufferedGCEventType type;
+       uint32_t payload_size;
+};
+
+typedef struct _GCHeapDumpMemFileBuffer GCHeapDumpMemFileBuffer;
+struct _GCHeapDumpMemFileBuffer {
+       ep_char8_t *name;
+       int fd;
+       uint8_t *start;
+       uint8_t *current;
+       uint8_t *end;
+};
+
+typedef struct _GCHeapDumpBuffer GCHeapDumpBuffer;
+struct _GCHeapDumpBuffer{
+       void *context;
+       bool (*reset_func)(void *context);
+       uint8_t * (*alloc_func)(void *context ,size_t size);
+       const uint8_t * (*get_next_buffer_func)(void *context, size_t *size);
+};
+
+typedef struct _GCHeapDumpBulkData GCHeapDumpBulkData;
+struct _GCHeapDumpBulkData {
+       uint8_t *data_start;
+       uint8_t *data_current;
+       uint8_t *data_end;
+       uint32_t index;
+       uint32_t count;
+       uint32_t max_count;
+};
+
+typedef enum {
+       GC_HEAP_DUMP_CONTEXT_STATE_INIT = 0,
+       GC_HEAP_DUMP_CONTEXT_STATE_START = 1,
+       GC_HEAP_DUMP_CONTEXT_STATE_DUMP = 2,
+       GC_HEAP_DUMP_CONTEXT_STATE_END = 3
+} GCHeapDumpContextState;
+
+typedef struct _GCHeapDumpContext GCHeapDumpContext;
+struct _GCHeapDumpContext {
+       EVENTPIPE_TRACE_CONTEXT trace_context;
+       GCHeapDumpBulkData bulk_nodes;
+       GCHeapDumpBulkData bulk_edges;
+       GCHeapDumpBulkData bulk_root_edges;
+       GCHeapDumpBulkData bulk_root_cwt_elem_edges;
+       GCHeapDumpBulkData bulk_root_static_vars;
+       BulkTypeEventLogger *bulk_type_logger;
+       GCHeapDumpBuffer *buffer;
+       dn_vector_ptr_t *gc_roots;
+       uint32_t gc_reason;
+       uint32_t gc_type;
+       uint32_t gc_count;
+       uint32_t gc_depth;
+       uint32_t retry_count;
+       GCHeapDumpContextState state;
+};
+
+// Must match GCBulkNode layout in ClrEtwAll.man.
+static const uint32_t BULK_NODE_EVENT_TYPE_SIZE =
+       // Address
+       sizeof (uintptr_t) +
+       // Size
+       sizeof (uint64_t) +
+       // TypeID
+       sizeof (uint64_t) +
+       // EdgeCount
+       sizeof (uint64_t);
+
+// Must match GCBulkEdge layout in ClrEtwAll.man.
+static const uint32_t BULK_EDGE_EVENT_TYPE_SIZE =
+       // Value
+       sizeof (uintptr_t) +
+       // ReferencingFiledID
+       sizeof (uint32_t);
+
+// Must match GCBulkRootEdge layout in ClrEtwAll.man.
+static const uint32_t BULK_ROOT_EDGE_EVENT_TYPE_SIZE =
+       // RootedNodeAddresses
+       sizeof (uintptr_t) +
+       // GCRootKind
+       sizeof (uint8_t) +
+       // GCRootFlag
+       sizeof (uint32_t) +
+       // GCRootID
+       sizeof (uintptr_t);
+
+// Must match GCBulkRootConditionalWeakTableElementEdge layout in ClrEtwAll.man.
+static const uint32_t BULK_ROOT_CWT_ELEM_EDGE_EVENT_TYPE_SIZE =
+       // GCKeyNodeID
+       sizeof (uintptr_t) +
+       // GCValueNodeID
+       sizeof (uintptr_t) +
+       // GCRootID
+       sizeof (uintptr_t);
+
+// Must match GCBulkRootStaticVar layout in ClrEtwAll.man.
+static const uint32_t BULK_ROOT_STATIC_VAR_EVENT_TYPE_SIZE =
+       // GCRootID
+       sizeof (uint64_t) +
+       // ObjectID
+       sizeof (uint64_t) +
+       // TypeID
+       sizeof (uint64_t) +
+       // Flags
+       sizeof (uint32_t) +
+       //FieldName
+       sizeof (ep_char16_t);
+
+// GC heap dump flags.
+#define GC_REASON_INDUCED 1
+#define GC_TYPE_NGC 0
+#define GC_ROOT_FLAGS_NONE 0
+#define GC_ROOT_FLAGS_PINNING 1
+#define GC_ROOT_KIND_STACK 0
+#define GC_ROOT_KIND_FINALIZER 1
+#define GC_ROOT_KIND_HANDLE 2
+#define GC_ROOT_KIND_OTHER 3
+
+static volatile uint32_t _gc_heap_dump_requests = 0;
+static volatile uint32_t _gc_heap_dump_count = 0;
+static volatile uint64_t _gc_heap_dump_trigger_count = 0;
+
+static dn_vector_t _gc_heap_dump_requests_data = {0};
+
+static
+uint64_t
+get_typeid_for_type (MonoType *t);
+
+static
+void
+bulk_type_log_type_and_parameters_if_necessary (
+       BulkTypeEventLogger *type_logger,
+       MonoType *mono_type,
+       TypeLogBehavior log_behavior);
+
+
+static
+uint16_t
+clr_instance_get_id (void)
+{
+       // Mono runtime id.
+       return 9;
+}
+
+static
+bool
+is_keyword_and_level_enabled (
+       const EVENTPIPE_TRACE_CONTEXT *context,
+       uint8_t level,
+       uint64_t keyword)
+{
+       if (context->IsEnabled && level <= context->Level)
+               return (keyword == 0) || (keyword & context->EnabledKeywordsBitmask) != 0;
+       return false;
+}
+
+static
+bool
+is_keword_enabled (uint64_t enabled_keywords, uint64_t keyword)
+{
+       return (enabled_keywords & keyword) == keyword;
+}
+
+static
+bool
+is_gc_heap_dump_enabled (GCHeapDumpContext *context)
+{
+       if (!context)
+               return false;
+
+       bool enabled = is_keyword_and_level_enabled (&context->trace_context, EP_EVENT_LEVEL_INFORMATIONAL, GC_HEAP_DUMP_KEYWORD);
+       enabled &= context->gc_reason == GC_REASON_INDUCED;
+       enabled &= context->gc_type == GC_TYPE_NGC;
+       return enabled;
+}
+
+static
+uint32_t
+write_buffer_string_utf8_to_utf16_t (
+       uint8_t **buf,
+       const ep_char8_t *str,
+       uint32_t len)
+{
+       uint32_t num_bytes_utf16_str = 0;
+       if (str && len != 0) {
+               glong len_utf16 = 0;
+               ep_char16_t *str_utf16 = (ep_char16_t *)(g_utf8_to_utf16le ((const gchar *)str, (glong)len, NULL, &len_utf16, NULL));
+               if (str_utf16 && len_utf16 != 0) {
+                       num_bytes_utf16_str = MIN (GLONG_TO_UINT32 (len_utf16), len) * sizeof (ep_char16_t);
+                       memcpy (*buf, str_utf16, num_bytes_utf16_str);
+               }
+               g_free (str_utf16);
+       }
+
+       (*buf) [num_bytes_utf16_str] = 0;
+       num_bytes_utf16_str++;
+
+       (*buf) [num_bytes_utf16_str] = 0;
+       num_bytes_utf16_str++;
+
+       *buf += num_bytes_utf16_str;
+       return num_bytes_utf16_str;
+}
+
+static
+bool
+fire_method_rundown_events (
+       const uint64_t method_id,
+       const uint64_t module_id,
+       const uint64_t method_start_address,
+       const uint32_t method_size,
+       const uint32_t method_token,
+       const uint32_t method_flags,
+       const ep_char8_t *method_namespace,
+       const ep_char8_t *method_name,
+       const ep_char8_t *method_signature,
+       const uint16_t count_of_map_entries,
+       const uint32_t *il_offsets,
+       const uint32_t *native_offsets,
+       bool aot_method,
+       bool verbose,
+       void *user_data)
+{
+       FireEtwMethodDCEndILToNativeMap (
+               method_id,
+               0,
+               0,
+               count_of_map_entries,
+               il_offsets,
+               native_offsets,
+               clr_instance_get_id (),
+               NULL,
+               NULL);
+
+       if (verbose) {
+               FireEtwMethodDCEndVerbose_V1 (
+                       method_id,
+                       module_id,
+                       method_start_address,
+                       method_size,
+                       method_token,
+                       method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION,
+                       method_namespace,
+                       method_name,
+                       method_signature,
+                       clr_instance_get_id (),
+                       NULL,
+                       NULL);
+
+               if (aot_method)
+                       FireEtwMethodDCEndVerbose_V1 (
+                               method_id,
+                               module_id,
+                               method_start_address,
+                               method_size,
+                               method_token,
+                               method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION,
+                               method_namespace,
+                               method_name,
+                               method_signature,
+                               clr_instance_get_id (),
+                               NULL,
+                               NULL);
+       } else {
+               FireEtwMethodDCEnd_V1 (
+                       method_id,
+                       module_id,
+                       method_start_address,
+                       method_size,
+                       method_token,
+                       method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION,
+                       clr_instance_get_id (),
+                       NULL,
+                       NULL);
+
+               if (aot_method)
+                       FireEtwMethodDCEnd_V1 (
+                               method_id,
+                               module_id,
+                               method_start_address,
+                               method_size,
+                               method_token,
+                               method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION,
+                               clr_instance_get_id (),
+                               NULL,
+                               NULL);
+       }
+
+       return true;
+}
+
+static
+bool
+fire_assembly_rundown_events (
+       const uint64_t domain_id,
+       const uint64_t assembly_id,
+       const uint32_t assembly_flags,
+       const uint32_t binding_id,
+       const ep_char8_t *assembly_name,
+       const uint64_t module_id,
+       const uint32_t module_flags,
+       const uint32_t reserved_flags,
+       const ep_char8_t *module_il_path,
+       const ep_char8_t *module_native_path,
+       const uint8_t *managed_pdb_signature,
+       const uint32_t managed_pdb_age,
+       const ep_char8_t *managed_pdb_build_path,
+       const uint8_t *native_pdb_signature,
+       const uint32_t native_pdb_age,
+       const ep_char8_t *native_pdb_build_path,
+       void *user_data)
+{
+       FireEtwModuleDCEnd_V2 (
+               module_id,
+               assembly_id,
+               module_flags,
+               reserved_flags,
+               module_il_path,
+               module_native_path,
+               clr_instance_get_id (),
+               managed_pdb_signature,
+               managed_pdb_age,
+               managed_pdb_build_path,
+               native_pdb_signature,
+               native_pdb_age,
+               native_pdb_build_path,
+               NULL,
+               NULL);
+
+       FireEtwDomainModuleDCEnd_V1 (
+               module_id,
+               assembly_id,
+               domain_id,
+               module_flags,
+               reserved_flags,
+               module_il_path,
+               module_native_path,
+               clr_instance_get_id (),
+               NULL,
+               NULL);
+
+       FireEtwAssemblyDCEnd_V1 (
+               assembly_id,
+               domain_id,
+               binding_id,
+               assembly_flags,
+               assembly_name,
+               clr_instance_get_id (),
+               NULL,
+               NULL);
+
+       return true;
+}
+
+static
+bool
+fire_domain_rundown_events (
+       const uint64_t domain_id,
+       const uint32_t domain_flags,
+       const ep_char8_t *domain_name,
+       const uint32_t domain_index,
+       void *user_data)
+{
+       return FireEtwAppDomainDCEnd_V1 (
+               domain_id,
+               domain_flags,
+               domain_name,
+               domain_index,
+               clr_instance_get_id (),
+               NULL,
+               NULL);
+}
+
+static
+void
+fire_method_events (
+       MonoJitInfo *ji,
+       MonoMethod *method,
+       FireMethodEventsData *events_data)
+{
+       EP_ASSERT (ji != NULL);
+       EP_ASSERT (events_data->domain != NULL);
+       EP_ASSERT (events_data->method_events_func != NULL);
+
+       uint64_t method_id = 0;
+       uint64_t module_id = 0;
+       uint64_t method_code_start = (uint64_t)ji->code_start;
+       uint32_t method_code_size = (uint32_t)ji->code_size;
+       uint32_t method_token = 0;
+       uint32_t method_flags = 0;
+       uint8_t kind = MONO_CLASS_DEF;
+       char *method_namespace = NULL;
+       const char *method_name = NULL;
+       char *method_signature = NULL;
+       bool verbose = (RUNTIME_RUNDOWN_PROVIDER_CONTEXT.Level >= (uint8_t)EP_EVENT_LEVEL_VERBOSE);
+
+       //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc.
+
+       if (method) {
+               method_id = (uint64_t)method;
+               method_token = method->token;
+
+               if (mono_jit_info_get_generic_sharing_context (ji))
+                       method_flags |= METHOD_FLAGS_SHARED_GENERIC_METHOD;
+
+               if (method->dynamic)
+                       method_flags |= METHOD_FLAGS_DYNAMIC_METHOD;
+
+               if (!ji->from_aot && !ji->from_llvm) {
+                       method_flags |= METHOD_FLAGS_JITTED_METHOD;
+                       if (method->wrapper_type != MONO_WRAPPER_NONE)
+                               method_flags |= METHOD_FLAGS_JITTED_HELPER_METHOD;
+               }
+
+               if (method->is_generic || method->is_inflated)
+                       method_flags |= METHOD_FLAGS_GENERIC_METHOD;
+
+               if (method->klass) {
+                       module_id = (uint64_t)m_class_get_image (method->klass);
+                       kind = m_class_get_class_kind (method->klass);
+                       if (kind == MONO_CLASS_GTD || kind == MONO_CLASS_GINST)
+                               method_flags |= METHOD_FLAGS_GENERIC_METHOD;
+               }
+
+               if (verbose) {
+                       method_name = method->name;
+                       method_signature = mono_signature_full_name (mono_method_signature_internal (method));
+                       if (method->klass)
+                               method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL);
+               }
+
+       }
+
+       uint32_t offset_entries = 0;
+       uint32_t *il_offsets = NULL;
+       uint32_t *native_offsets = NULL;
+
+       MonoDebugMethodJitInfo *debug_info = method ? mono_debug_find_method (method, events_data->domain) : NULL;
+       if (debug_info) {
+               offset_entries = debug_info->num_line_numbers;
+               if (offset_entries != 0) {
+                       size_t needed_size = (offset_entries * sizeof (uint32_t) * 2);
+                       if (!events_data->buffer || needed_size > events_data->buffer_size) {
+                               g_free (events_data->buffer);
+                               events_data->buffer_size = (size_t)(needed_size * 1.5);
+                               events_data->buffer = g_new (uint8_t, events_data->buffer_size);
+                       }
+
+                       if (events_data->buffer) {
+                               il_offsets = (uint32_t*)events_data->buffer;
+                               native_offsets = il_offsets + offset_entries;
+
+                               uint8_t *il_offsets_ptr = (uint8_t *)il_offsets;
+                               uint8_t *native_offsets_ptr = (uint8_t *)native_offsets;
+                               for (uint32_t offset_count = 0; offset_count < offset_entries; ++offset_count) {
+                                       ep_write_buffer_uint32_t (&il_offsets_ptr, debug_info->line_numbers [offset_count].il_offset);
+                                       ep_write_buffer_uint32_t (&native_offsets_ptr, debug_info->line_numbers [offset_count].native_offset);
+                               }
+                       }
+               }
+
+               mono_debug_free_method_jit_info (debug_info);
+       }
+
+       if (events_data->buffer && !il_offsets && !native_offsets) {
+               // No IL offset -> Native offset mapping available. Put all code on IL offset 0.
+               EP_ASSERT (events_data->buffer_size >= sizeof (uint32_t) * 2);
+               offset_entries = 1;
+               il_offsets = (uint32_t*)events_data->buffer;
+               native_offsets = il_offsets + offset_entries;
+               il_offsets [0] = 0;
+               native_offsets [0] = ep_rt_val_uint32_t ((uint32_t)ji->code_size);
+       }
+
+       events_data->method_events_func (
+               method_id,
+               module_id,
+               method_code_start,
+               method_code_size,
+               method_token,
+               method_flags,
+               (ep_char8_t *)method_namespace,
+               (ep_char8_t *)method_name,
+               (ep_char8_t *)method_signature,
+               GUINT32_TO_UINT16 (offset_entries),
+               il_offsets,
+               native_offsets,
+               (ji->from_aot || ji->from_llvm),
+               verbose,
+               NULL);
+
+       g_free (method_namespace);
+       g_free (method_signature);
+}
+
+static
+bool
+include_method (MonoMethod *method)
+{
+       if (!method) {
+               return false;
+       } else if (!m_method_is_wrapper (method)) {
+               return true;
+       } else {
+               WrapperInfo *wrapper = mono_marshal_get_wrapper_info (method);
+               return (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_PINVOKE) ? true : false;
+       }
+}
+
+static
+bool
+get_module_event_data (
+       MonoImage *image,
+       ModuleEventData *module_data)
+{
+       if (module_data) {
+               memset (module_data->module_il_pdb_signature, 0, EP_GUID_SIZE);
+               memset (module_data->module_native_pdb_signature, 0, EP_GUID_SIZE);
+
+               // Under netcore we only have root domain.
+               MonoDomain *root_domain = mono_get_root_domain ();
+
+               module_data->domain_id = (uint64_t)root_domain;
+               module_data->module_id = (uint64_t)image;
+               module_data->assembly_id = image ? (uint64_t)image->assembly : 0;
+
+               // TODO: Extract all module native paths and pdb metadata when available.
+               module_data->module_native_path = "";
+               module_data->module_native_pdb_path = "";
+               module_data->module_native_pdb_age = 0;
+
+               module_data->reserved_flags = 0;
+
+               // Netcore has a 1:1 between assemblies and modules, so its always a manifest module.
+               module_data->module_flags = MODULE_FLAGS_MANIFEST_MODULE;
+               if (image && image->dynamic)
+                       module_data->module_flags |= MODULE_FLAGS_DYNAMIC_MODULE;
+               if (image && image->aot_module)
+                       module_data->module_flags |= MODULE_FLAGS_NATIVE_MODULE;
+
+               module_data->module_il_path = NULL;
+               if (image && image->filename) {
+                       /* if there's a filename, use it */
+                       module_data->module_il_path = image->filename;
+               } else if (image && image->module_name) {
+                       /* otherwise, use the module name */
+                       module_data->module_il_path = image->module_name;
+               }
+               if (!module_data->module_il_path)
+                       module_data->module_il_path = "";
+
+               module_data->module_il_pdb_path = "";
+               module_data->module_il_pdb_age = 0;
+
+               if (image && image->image_info) {
+                       MonoPEDirEntry *debug_dir_entry = (MonoPEDirEntry *)&image->image_info->cli_header.datadir.pe_debug;
+                       if (debug_dir_entry->size) {
+                               ImageDebugDirectory debug_dir;
+                               memset (&debug_dir, 0, sizeof (debug_dir));
+
+                               uint32_t offset = mono_cli_rva_image_map (image, debug_dir_entry->rva);
+                               for (uint32_t idx = 0; idx < debug_dir_entry->size / sizeof (ImageDebugDirectory); ++idx) {
+                                       uint8_t *data = (uint8_t *) ((ImageDebugDirectory *) (image->raw_data + offset) + idx);
+                                       debug_dir.major_version = read16 (data + 8);
+                                       debug_dir.minor_version = read16 (data + 10);
+                                       debug_dir.type = read32 (data + 12);
+                                       debug_dir.pointer = read32 (data + 24);
+
+                                       if (debug_dir.type == DEBUG_DIR_ENTRY_CODEVIEW && debug_dir.major_version == 0x100 && debug_dir.minor_version == 0x504d) {
+                                               data  = (uint8_t *)(image->raw_data + debug_dir.pointer);
+                                               int32_t signature = read32 (data);
+                                               if (signature == 0x53445352) {
+                                                       memcpy (module_data->module_il_pdb_signature, data + 4, EP_GUID_SIZE);
+                                                       module_data->module_il_pdb_age = read32 (data + 20);
+                                                       module_data->module_il_pdb_path = (const char *)(data + 24);
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return true;
+}
+
+static
+void
+fire_method_events_callback (
+       MonoJitInfo *ji,
+       void  *user_data)
+{
+       FireMethodEventsData *events_data = (FireMethodEventsData *)user_data;
+       EP_ASSERT (events_data != NULL);
+
+       if (ji && !ji->is_trampoline && !ji->async) {
+               MonoMethod *method = jinfo_get_method (ji);
+               if (include_method (method))
+                       fire_method_events (ji, method, events_data);
+       }
+}
+
+static
+void
+fire_assembly_events (
+       MonoDomain *domain,
+       MonoAssembly *assembly,
+       fire_assembly_rundown_events_func assembly_events_func)
+{
+       EP_ASSERT (domain != NULL);
+       EP_ASSERT (assembly != NULL);
+       EP_ASSERT (assembly_events_func != NULL);
+
+       // Native methods are part of JIT table and already emitted.
+       // TODO: FireEtwMethodDCEndVerbose_V1_or_V2 for all native methods in module as well?
+
+       uint32_t binding_id = 0;
+
+       ModuleEventData module_data;
+       memset (&module_data, 0, sizeof (module_data));
+
+       get_module_event_data (assembly->image, &module_data);
+
+       uint32_t assembly_flags = 0;
+       if (assembly->dynamic)
+               assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY;
+
+       if (assembly->image && assembly->image->aot_module) {
+               assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY;
+       }
+
+       char *assembly_name = mono_stringify_assembly_name (&assembly->aname);
+
+       assembly_events_func (
+               module_data.domain_id,
+               module_data.assembly_id,
+               assembly_flags,
+               binding_id,
+               (const ep_char8_t*)assembly_name,
+               module_data.module_id,
+               module_data.module_flags,
+               module_data.reserved_flags,
+               (const ep_char8_t *)module_data.module_il_path,
+               (const ep_char8_t *)module_data.module_native_path,
+               module_data.module_il_pdb_signature,
+               module_data.module_il_pdb_age,
+               (const ep_char8_t *)module_data.module_il_pdb_path,
+               module_data.module_native_pdb_signature,
+               module_data.module_native_pdb_age,
+               (const ep_char8_t *)module_data.module_native_pdb_path,
+               NULL);
+
+       g_free (assembly_name);
+}
+
+static
+gboolean
+execute_rundown (
+       fire_domain_rundown_events_func domain_events_func,
+       fire_assembly_rundown_events_func assembly_events_func,
+       fire_method_rundown_events_func method_events_func)
+{
+       EP_ASSERT (domain_events_func != NULL);
+       EP_ASSERT (assembly_events_func != NULL);
+       EP_ASSERT (method_events_func != NULL);
+
+       // Under netcore we only have root domain.
+       MonoDomain *root_domain = mono_get_root_domain ();
+       if (root_domain) {
+               uint64_t domain_id = (uint64_t)root_domain;
+
+               // Emit all functions in use (JIT, AOT and Interpreter).
+               FireMethodEventsData events_data;
+               events_data.domain = root_domain;
+               events_data.buffer_size = 1024 * sizeof(uint32_t);
+               events_data.buffer = g_new (uint8_t, events_data.buffer_size);
+               events_data.method_events_func = method_events_func;
+
+               // All called JIT/AOT methods should be included in jit info table.
+               mono_jit_info_table_foreach_internal (fire_method_events_callback, &events_data);
+
+               // All called interpreted methods should be included in interpreter jit info table.
+               if (mono_get_runtime_callbacks ()->is_interpreter_enabled())
+                       mono_get_runtime_callbacks ()->interp_jit_info_foreach (fire_method_events_callback, &events_data);
+
+               // Phantom methods injected in callstacks representing runtime functions.
+               if (_runtime_helper_compile_method_jitinfo && _runtime_helper_compile_method)
+                       fire_method_events (_runtime_helper_compile_method_jitinfo, _runtime_helper_compile_method, &events_data);
+               if (_monitor_enter_method_jitinfo && _monitor_enter_method)
+                       fire_method_events (_monitor_enter_method_jitinfo, _monitor_enter_method, &events_data);
+               if (_monitor_enter_v4_method_jitinfo && _monitor_enter_v4_method)
+                       fire_method_events (_monitor_enter_v4_method_jitinfo, _monitor_enter_v4_method, &events_data);
+
+               g_free (events_data.buffer);
+
+               // Iterate all assemblies in domain.
+               GPtrArray *assemblies = mono_alc_get_all_loaded_assemblies ();
+               if (assemblies) {
+                       for (uint32_t i = 0; i < assemblies->len; ++i) {
+                               MonoAssembly *assembly = (MonoAssembly *)g_ptr_array_index (assemblies, i);
+                               if (assembly)
+                                       fire_assembly_events (root_domain, assembly, assembly_events_func);
+                       }
+                       g_ptr_array_free (assemblies, TRUE);
+               }
+
+               uint32_t domain_flags = DOMAIN_FLAGS_DEFAULT_DOMAIN | DOMAIN_FLAGS_EXECUTABLE_DOMAIN;
+               const char *domain_name = root_domain->friendly_name ? root_domain->friendly_name : "";
+               uint32_t domain_index = 1;
+
+               domain_events_func (
+                       domain_id,
+                       domain_flags,
+                       (const ep_char8_t *)domain_name,
+                       domain_index,
+                       NULL);
+       }
+
+       return TRUE;
+}
+
+static
+bool
+in_safe_point_frame (EventPipeStackContents *stack_content, WrapperInfo *wrapper)
+{
+       EP_ASSERT (stack_content != NULL);
+
+       // If top of stack is a managed->native icall wrapper for one of the below subtypes, we are at a safe point frame.
+       if (wrapper && ep_stack_contents_get_length (stack_content) == 0 && wrapper->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER &&
+                       (wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_state_poll ||
+                       wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_enter_gc_safe_region_unbalanced ||
+                       wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_exit_gc_safe_region_unbalanced ||
+                       wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_enter_gc_unsafe_region_unbalanced ||
+                       wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_exit_gc_unsafe_region_unbalanced))
+               return true;
+
+       return false;
+}
+
+static
+bool
+in_runtime_invoke_frame (EventPipeStackContents *stack_content, WrapperInfo *wrapper)
+{
+       EP_ASSERT (stack_content != NULL);
+
+       // If top of stack is a managed->native runtime invoke wrapper, we are at a managed frame.
+       if (wrapper && ep_stack_contents_get_length (stack_content) == 0 &&
+                       (wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL ||
+                       wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT ||
+                       wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC ||
+                       wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL))
+               return true;
+
+       return false;
+}
+
+static
+bool
+in_monitor_enter_frame (WrapperInfo *wrapper)
+{
+       if (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER &&
+                       (wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_fast ||
+                       wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_internal))
+               return true;
+
+       return false;
+}
+
+static
+bool
+in_monitor_enter_v4_frame (WrapperInfo *wrapper)
+{
+       if (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER &&
+                       (wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_v4_fast ||
+                       wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_v4_internal))
+               return true;
+
+       return false;
+}
+
+static
+gboolean
+walk_managed_stack_for_thread (
+       MonoStackFrameInfo *frame,
+       MonoContext *ctx,
+       StackWalkData *stack_walk_data)
+{
+       EP_ASSERT (frame != NULL);
+       EP_ASSERT (stack_walk_data != NULL);
+
+       switch (frame->type) {
+       case FRAME_TYPE_DEBUGGER_INVOKE:
+       case FRAME_TYPE_MANAGED_TO_NATIVE:
+       case FRAME_TYPE_TRAMPOLINE:
+       case FRAME_TYPE_INTERP_TO_MANAGED:
+       case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
+       case FRAME_TYPE_INTERP_ENTRY:
+               stack_walk_data->top_frame = false;
+               return FALSE;
+       case FRAME_TYPE_JIT_ENTRY:
+               // Frame in JIT compiler at top of callstack, add phantom frame representing call into JIT compiler.
+               // Makes it possible to detect stacks waiting on JIT compiler.
+               if (_runtime_helper_compile_method && stack_walk_data->top_frame)
+                       ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)_runtime_helper_compile_method), _runtime_helper_compile_method);
+               stack_walk_data->top_frame = false;
+               return FALSE;
+       case FRAME_TYPE_MANAGED:
+       case FRAME_TYPE_INTERP:
+               if (frame->ji) {
+                       stack_walk_data->async_frame |= frame->ji->async;
+                       MonoMethod *method = frame->ji->async ? NULL : frame->actual_method;
+                       if (method && m_method_is_wrapper (method)) {
+                               WrapperInfo *wrapper = mono_marshal_get_wrapper_info (method);
+                               if (in_safe_point_frame (stack_walk_data->stack_contents, wrapper)) {
+                                       stack_walk_data->safe_point_frame = true;
+                               }else if (in_runtime_invoke_frame (stack_walk_data->stack_contents, wrapper)) {
+                                       stack_walk_data->runtime_invoke_frame = true;
+                               } else if (_monitor_enter_method && in_monitor_enter_frame (wrapper)) {
+                                       ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)_monitor_enter_method), _monitor_enter_method);
+                               } else if (_monitor_enter_v4_method && in_monitor_enter_v4_frame (wrapper)) {
+                                       ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)_monitor_enter_v4_method), _monitor_enter_v4_method);
+                               } else if (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_PINVOKE) {
+                                       ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)frame->ji->code_start + frame->native_offset), method);
+                               }
+                       } else if (method && !m_method_is_wrapper (method)) {
+                               ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)frame->ji->code_start + frame->native_offset), method);
+                       } else if (!method && frame->ji->async && !frame->ji->is_trampoline) {
+                               ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)frame->ji->code_start), method);
+                       }
+               }
+               stack_walk_data->top_frame = false;
+               return ep_stack_contents_get_length (stack_walk_data->stack_contents) >= EP_MAX_STACK_DEPTH;
+       default:
+               EP_UNREACHABLE ("walk_managed_stack_for_thread");
+               return FALSE;
+       }
+}
+
+static
+gboolean
+walk_managed_stack_for_thread_callback (
+       MonoStackFrameInfo *frame,
+       MonoContext *ctx,
+       void *data)
+{
+       return walk_managed_stack_for_thread (frame, ctx, (StackWalkData *)data);
+}
+
+static
+gboolean
+sample_profiler_walk_managed_stack_for_thread_callback (
+       MonoStackFrameInfo *frame,
+       MonoContext *ctx,
+       void *data)
+{
+       EP_ASSERT (frame != NULL);
+       EP_ASSERT (data != NULL);
+
+       SampleProfileStackWalkData *sample_data = (SampleProfileStackWalkData *)data;
+
+       if (sample_data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR) {
+               switch (frame->type) {
+               case FRAME_TYPE_MANAGED:
+                       sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED;
+                       break;
+               case FRAME_TYPE_MANAGED_TO_NATIVE:
+               case FRAME_TYPE_TRAMPOLINE:
+                       sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL;
+                       break;
+               case FRAME_TYPE_JIT_ENTRY:
+                       sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL;
+                       break;
+               case FRAME_TYPE_INTERP:
+                       sample_data->payload_data = frame->managed ? EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED : EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL;
+                       break;
+               case FRAME_TYPE_INTERP_TO_MANAGED:
+               case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
+                       break;
+               default:
+                       sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED;
+               }
+       }
+
+       return walk_managed_stack_for_thread (frame, ctx, &sample_data->stack_walk_data);
+}
+
+bool
+ep_rt_mono_walk_managed_stack_for_thread (
+       ep_rt_thread_handle_t thread,
+       EventPipeStackContents *stack_contents)
+{
+       EP_ASSERT (thread != NULL && stack_contents != NULL);
+
+       StackWalkData stack_walk_data;
+       stack_walk_data.stack_contents = stack_contents;
+       stack_walk_data.top_frame = true;
+       stack_walk_data.async_frame = false;
+       stack_walk_data.safe_point_frame = false;
+       stack_walk_data.runtime_invoke_frame = false;
+
+       bool restore_async_context = FALSE;
+       bool prevent_profiler_event_recursion = FALSE;
+       EventPipeMonoThreadData *thread_data = ep_rt_mono_thread_data_get_or_create ();
+       if (thread_data) {
+               prevent_profiler_event_recursion = thread_data->prevent_profiler_event_recursion;
+               if (prevent_profiler_event_recursion && !mono_thread_info_is_async_context ()) {
+                       // Running stackwalk in async context mode is currently the only way to prevent
+                       // unwinder to NOT load additional classes during stackwalk, making it signal unsafe and
+                       // potential triggering uncontrolled recursion in profiler class loading event.
+                       mono_thread_info_set_is_async_context (TRUE);
+                       restore_async_context = TRUE;
+               }
+               thread_data->prevent_profiler_event_recursion = TRUE;
+       }
+
+       if (thread == ep_rt_thread_get_handle () && mono_get_eh_callbacks ()->mono_walk_stack_with_ctx)
+               mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (walk_managed_stack_for_thread_callback, NULL, MONO_UNWIND_SIGNAL_SAFE, &stack_walk_data);
+       else if (mono_get_eh_callbacks ()->mono_walk_stack_with_state)
+               mono_get_eh_callbacks ()->mono_walk_stack_with_state (walk_managed_stack_for_thread_callback, mono_thread_info_get_suspend_state (thread), MONO_UNWIND_SIGNAL_SAFE, &stack_walk_data);
+
+       if (thread_data) {
+               if (restore_async_context)
+                       mono_thread_info_set_is_async_context (FALSE);
+               thread_data->prevent_profiler_event_recursion = prevent_profiler_event_recursion;
+       }
+
+       return true;
+}
+
+bool
+ep_rt_mono_sample_profiler_write_sampling_event_for_threads (
+       ep_rt_thread_handle_t sampling_thread,
+       EventPipeEvent *sampling_event)
+{
+       // Follows CoreClr implementation of sample profiler. Generic invasive/expensive way to do CPU sample profiling relying on STW and stackwalks.
+       // TODO: Investigate alternatives on platforms supporting Signals/SuspendThread (see Mono profiler) or CPU PMU's (see ETW/perf_event_open).
+
+       // Sample profiler only runs on one thread, no need to synchorinize.
+       if (!_sampled_thread_callstacks)
+               _sampled_thread_callstacks = g_array_sized_new (FALSE, FALSE, sizeof (SampleProfileStackWalkData), _max_sampled_thread_count);
+
+       // Make sure there is room based on previous max number of sampled threads.
+       // NOTE, there is a chance there are more threads than max, if that's the case we will
+       // miss those threads in this sample, but will be included in next when max has been adjusted.
+       g_array_set_size (_sampled_thread_callstacks, _max_sampled_thread_count);
+
+       uint32_t filtered_thread_count = 0;
+       uint32_t sampled_thread_count = 0;
+
+       mono_stop_world (MONO_THREAD_INFO_FLAGS_NO_GC);
+
+       bool restore_async_context = FALSE;
+       if (!mono_thread_info_is_async_context ()) {
+               mono_thread_info_set_is_async_context (TRUE);
+               restore_async_context = TRUE;
+       }
+
+       // Record all info needed in sample events while runtime is suspended, must be async safe.
+       FOREACH_THREAD_SAFE_EXCLUDE (thread_info, MONO_THREAD_INFO_FLAGS_NO_GC | MONO_THREAD_INFO_FLAGS_NO_SAMPLE) {
+               if (!mono_thread_info_is_running (thread_info) && thread_info->jit_data) {
+                       MonoThreadUnwindState *thread_state = mono_thread_info_get_suspend_state (thread_info);
+                       if (thread_state->valid) {
+                               if (sampled_thread_count < _max_sampled_thread_count) {
+                                       SampleProfileStackWalkData *data = &g_array_index (_sampled_thread_callstacks, SampleProfileStackWalkData, sampled_thread_count);
+                                       data->thread_id = ep_rt_thread_id_t_to_uint64_t (mono_thread_info_get_tid (thread_info));
+                                       data->thread_ip = (uintptr_t)MONO_CONTEXT_GET_IP (&thread_state->ctx);
+                                       data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR;
+                                       data->stack_walk_data.stack_contents = &data->stack_contents;
+                                       data->stack_walk_data.top_frame = true;
+                                       data->stack_walk_data.async_frame = false;
+                                       data->stack_walk_data.safe_point_frame = false;
+                                       data->stack_walk_data.runtime_invoke_frame = false;
+                                       ep_stack_contents_reset (&data->stack_contents);
+                                       mono_get_eh_callbacks ()->mono_walk_stack_with_state (sample_profiler_walk_managed_stack_for_thread_callback, thread_state, MONO_UNWIND_SIGNAL_SAFE, data);
+                                       if (data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL && (data->stack_walk_data.safe_point_frame || data->stack_walk_data.runtime_invoke_frame)) {
+                                               // If classified as external code (managed->native frame on top of stack), but have a safe point or runtime invoke frame
+                                               // as second, re-classify current callstack to be executing managed code.
+                                               data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED;
+                                       }
+                                       if (data->stack_walk_data.top_frame && ep_stack_contents_get_length (&data->stack_contents) == 0) {
+                                               // If no managed frames (including helper frames) are located on stack, mark sample as beginning in external code.
+                                               // This can happen on attached embedding threads returning to native code between runtime invokes.
+                                               // Make sure sample is still written into EventPipe for all attached threads even if they are currently not having
+                                               // any managed frames on stack. Prevents some tools applying thread time heuristics to prolong duration of last sample
+                                               // when embedding thread returns to native code. It also opens ability to visualize number of samples in unmanaged code
+                                               // on attached threads when executing outside of runtime. If tooling is not interested in these sample events, they are easy
+                                               // to identify and filter out.
+                                               data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL;
+                                       }
+
+                                       sampled_thread_count++;
+                               }
+                       }
+               }
+               filtered_thread_count++;
+       } FOREACH_THREAD_SAFE_END
+
+       if (restore_async_context)
+               mono_thread_info_set_is_async_context (FALSE);
+
+       mono_restart_world (MONO_THREAD_INFO_FLAGS_NO_GC);
+
+       // Fire sample event for threads. Must be done after runtime is resumed since it's not async safe.
+       // Since we can't keep thread info around after runtime as been suspended, use an empty
+       // adapter instance and only set recorded tid as parameter inside adapter.
+       THREAD_INFO_TYPE adapter = { { 0 } };
+       for (uint32_t thread_count = 0; thread_count < sampled_thread_count; ++thread_count) {
+               SampleProfileStackWalkData *data = &g_array_index (_sampled_thread_callstacks, SampleProfileStackWalkData, thread_count);
+               if ((data->stack_walk_data.top_frame && data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL) || (data->payload_data != EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR && ep_stack_contents_get_length (&data->stack_contents) > 0)) {
+                       // Check if we have an async frame, if so we will need to make sure all frames are registered in regular jit info table.
+                       // TODO: An async frame can contain wrapper methods (no way to check during stackwalk), we could skip writing profile event
+                       // for this specific stackwalk or we could cleanup stack_frames before writing profile event.
+                       if (data->stack_walk_data.async_frame) {
+                               for (uint32_t frame_count = 0; frame_count < data->stack_contents.next_available_frame; ++frame_count)
+                                       mono_jit_info_table_find_internal ((gpointer)data->stack_contents.stack_frames [frame_count], TRUE, FALSE);
+                       }
+                       mono_thread_info_set_tid (&adapter, ep_rt_uint64_t_to_thread_id_t (data->thread_id));
+                       uint32_t payload_data = ep_rt_val_uint32_t (data->payload_data);
+                       ep_write_sample_profile_event (sampling_thread, sampling_event, &adapter, &data->stack_contents, (uint8_t *)&payload_data, sizeof (payload_data));
+               }
+       }
+
+       // Current thread count will be our next maximum sampled threads.
+       _max_sampled_thread_count = filtered_thread_count;
+
+       return true;
+}
+
+void
+ep_rt_mono_execute_rundown (dn_vector_ptr_t *execution_checkpoints)
+{
+       ep_char8_t runtime_module_path [256];
+       const uint8_t object_guid [EP_GUID_SIZE] = { 0 };
+       const uint16_t runtime_product_qfe_version = 0;
+       const uint8_t startup_flags = 0;
+       const uint8_t startup_mode = 0;
+       const ep_char8_t *command_line = "";
+
+       if (!g_module_address ((void *)mono_init, runtime_module_path, sizeof (runtime_module_path), NULL, NULL, 0, NULL))
+               runtime_module_path [0] = '\0';
+
+       FireEtwRuntimeInformationDCStart (
+               clr_instance_get_id (),
+               RUNTIME_SKU_MONO,
+               RuntimeProductMajorVersion,
+               RuntimeProductMinorVersion,
+               RuntimeProductPatchVersion,
+               runtime_product_qfe_version,
+               RuntimeFileMajorVersion,
+               RuntimeFileMajorVersion,
+               RuntimeFileBuildVersion,
+               RuntimeFileRevisionVersion,
+               startup_mode,
+               startup_flags,
+               command_line,
+               object_guid,
+               runtime_module_path,
+               NULL,
+               NULL);
+
+       if (execution_checkpoints) {
+               DN_VECTOR_PTR_FOREACH_BEGIN (EventPipeExecutionCheckpoint *, checkpoint, execution_checkpoints) {
+                       FireEtwExecutionCheckpointDCEnd (
+                               clr_instance_get_id (),
+                               checkpoint->name,
+                               checkpoint->timestamp,
+                               NULL,
+                               NULL);
+               } DN_VECTOR_PTR_FOREACH_END;
+       }
+
+       FireEtwDCEndInit_V1 (
+               clr_instance_get_id (),
+               NULL,
+               NULL);
+
+       execute_rundown (
+               fire_domain_rundown_events,
+               fire_assembly_rundown_events,
+               fire_method_rundown_events);
+
+       FireEtwDCEndComplete_V1 (
+               clr_instance_get_id (),
+               NULL,
+               NULL);
+}
+
+// Clear out BulkTypeValue before filling it out (array elements can get reused if there
+// are enough types that we need to flush to multiple events).
+static
+void
+bulk_type_value_clear (BulkTypeValue *bulk_type_value)
+{
+       memset (bulk_type_value, 0, sizeof(BulkTypeValue));
+}
+
+static
+int
+bulk_type_get_byte_count_in_event (BulkTypeValue *bulk_type_value)
+{
+       int name_len = bulk_type_value->name && bulk_type_value->name [0] != '\0'
+               ? GSIZE_TO_INT (strlen (bulk_type_value->name))
+               : 0;
+
+       // NOTE, must match manifest BulkType value type.
+       return sizeof (bulk_type_value->fixed_sized_data.type_id) +
+               sizeof (bulk_type_value->fixed_sized_data.module_id) +
+               sizeof (bulk_type_value->fixed_sized_data.type_name_id) +
+               sizeof (bulk_type_value->fixed_sized_data.flags) +
+               sizeof (bulk_type_value->fixed_sized_data.cor_element_type) +
+               (name_len + 1) * sizeof (ep_char16_t) +
+               sizeof (bulk_type_value->type_parameters_count) +
+               bulk_type_value->type_parameters_count * sizeof (uint64_t);
+}
+
+static
+BulkTypeEventLogger*
+bulk_type_event_logger_alloc (void)
+{
+       BulkTypeEventLogger *type_logger = g_malloc0 (sizeof (BulkTypeEventLogger));
+       type_logger->bulk_type_event_buffer = g_malloc0 (sizeof (uint8_t) * MAX_SIZE_OF_EVENT_BUFFER);
+       type_logger->mem_pool = mono_mempool_new ();
+
+       dn_umap_custom_alloc_params_t params = {0, };
+       params.value_dispose_func = g_free;
+       type_logger->type_cache = dn_umap_custom_alloc (&params);
+
+       return type_logger;
+}
+
+static
+void
+bulk_type_event_logger_free (BulkTypeEventLogger *type_logger)
+{
+       mono_mempool_destroy (type_logger->mem_pool);
+       dn_umap_free (type_logger->type_cache);
+       g_free (type_logger->bulk_type_event_buffer);
+       g_free (type_logger);
+}
+
+//---------------------------------------------------------------------------------------
+//
+// fire_bulk_type_event fires an ETW event for all the types batched so far,
+// it then resets the state to start batching new types at the beginning of the
+// bulk_type_values array.
+//
+// This follows CoreCLR's BulkTypeEventLogger::FireBulkTypeEvent
+
+static
+void
+bulk_type_fire_bulk_type_event (BulkTypeEventLogger *type_logger)
+{
+       if (type_logger->bulk_type_value_count == 0)
+               return;
+
+       uint16_t clr_instance_id = clr_instance_get_id ();
+
+       uint32_t values_element_size = 0;
+
+       uint8_t *ptr = type_logger->bulk_type_event_buffer;
+
+       // NOTE, must match manifest BulkType value type.
+       for (uint32_t type_value_index = 0; type_value_index < type_logger->bulk_type_value_count; type_value_index++) {
+               BulkTypeValue *target = &type_logger->bulk_type_values [type_value_index];
+
+               values_element_size += ep_write_buffer_uint64_t (&ptr, target->fixed_sized_data.type_id);
+               values_element_size += ep_write_buffer_uint64_t (&ptr, target->fixed_sized_data.module_id);
+               values_element_size += ep_write_buffer_uint32_t (&ptr, target->fixed_sized_data.type_name_id);
+               values_element_size += ep_write_buffer_uint32_t (&ptr, target->fixed_sized_data.flags);
+               values_element_size += ep_write_buffer_uint8_t (&ptr, target->fixed_sized_data.cor_element_type);
+
+               uint32_t target_name_len = target->name && target->name [0] != '\0' ? GSIZE_TO_UINT32 (strlen (target->name)) : 0;
+               values_element_size += write_buffer_string_utf8_to_utf16_t (&ptr, target->name, target_name_len);
+
+               values_element_size += ep_write_buffer_uint32_t (&ptr, target->type_parameters_count);
+
+               for (uint32_t i = 0; i < target->type_parameters_count; i++) {
+                       uint64_t type_parameter = get_typeid_for_type (target->mono_type_parameters [i]);
+                       values_element_size += ep_write_buffer_uint64_t (&ptr, type_parameter);
+               }
+       }
+
+       FireEtwBulkType (
+               type_logger->bulk_type_value_count,
+               clr_instance_id,
+               values_element_size,
+               type_logger->bulk_type_event_buffer,
+               NULL,
+               NULL);
+
+       memset (type_logger->bulk_type_event_buffer, 0, sizeof (uint8_t) * MAX_SIZE_OF_EVENT_BUFFER);
+       type_logger->bulk_type_value_count = 0;
+       type_logger->bulk_type_value_byte_count = 0;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// get_typeid_for_type is responsible for obtaining the unique type identifier for a
+// particular MonoType. MonoTypes are structs that are not unique pointers. There
+// can be two different MonoTypes that both System.Thread or int32 or bool []. There
+// is exactly one MonoClass * for any type, so we leverage the MonoClass a MonoType
+// points to in order to obtain a unique type identifier in mono. With that unique
+// MonoClass, its fields this_arg and _byval_arg are unique as well.
+//
+// Arguments:
+//      * mono_type - MonoType to be logged
+//
+// Return Value:
+//      type_id - Unique type identifier of mono_type
+
+static
+uint64_t
+get_typeid_for_type (MonoType *t)
+{
+       if (m_type_is_byref (t))
+               return (uint64_t)m_class_get_this_arg (mono_class_from_mono_type_internal (t));
+       else
+               return (uint64_t)m_class_get_byval_arg (mono_class_from_mono_type_internal (t));
+}
+
+static
+uint64_t
+get_typeid_for_class (MonoClass *c)
+{
+       return get_typeid_for_type (m_class_get_byval_arg (c));
+}
+
+//---------------------------------------------------------------------------------------
+//
+// bulk_type_log_single_type batches a single type into the bulk type array and flushes
+// the array to ETW if it fills up. Most interaction with the type system (type analysis)
+// is done here. This does not recursively batch up any parameter types (arrays or generics),
+// but does add their unique identifiers to the mono_type_parameters array.
+// ep_rt_mono_log_type_and_parameters is responsible for initiating any recursive calls to
+// deal with type parameters.
+//
+// Arguments:
+//     * type_logger - BulkTypeEventLogger instance
+//      * mono_type - MonoType to be logged
+//
+// Return Value:
+//      Index into array of where this type got batched. -1 if there was a failure.
+//
+// This follows CoreCLR's BulkTypeEventLogger::LogSingleType
+
+static
+int
+bulk_type_log_single_type (
+       BulkTypeEventLogger *type_logger,
+       MonoType *mono_type)
+{
+       // If there's no room for another type, flush what we've got
+       if (type_logger->bulk_type_value_count == K_MAX_COUNT_TYPE_VALUES)
+               bulk_type_fire_bulk_type_event (type_logger);
+
+       EP_ASSERT (type_logger->bulk_type_value_count < K_MAX_COUNT_TYPE_VALUES);
+
+       BulkTypeValue *val = &type_logger->bulk_type_values [type_logger->bulk_type_value_count];
+       bulk_type_value_clear (val);
+
+       MonoClass *klass = mono_class_from_mono_type_internal (mono_type);
+       MonoType *mono_underlying_type = mono_type_get_underlying_type (mono_type);
+
+       // Initialize val fixed_sized_data
+       val->fixed_sized_data.type_id = get_typeid_for_type (mono_type);
+       val->fixed_sized_data.module_id = (uint64_t)m_class_get_image (klass);
+       val->fixed_sized_data.type_name_id = m_class_get_type_token (klass) ? mono_metadata_make_token (MONO_TABLE_TYPEDEF, mono_metadata_token_index (m_class_get_type_token (klass))) : 0;
+       if (mono_class_has_finalizer (klass))
+               val->fixed_sized_data.flags |= TYPE_FLAGS_FINALIZABLE;
+       if (m_class_is_delegate (klass))
+               val->fixed_sized_data.flags |= TYPE_FLAGS_DELEGATE;
+       if (mono_class_is_com_object (klass))
+               val->fixed_sized_data.flags |= TYPE_FLAGS_EXTERNALLY_IMPLEMENTED_COM_OBJECT;
+       val->fixed_sized_data.cor_element_type = (uint8_t)mono_underlying_type->type;
+
+       // Sets val variable sized parameter type data, type_parameters_count, and mono_type_parameters associated
+       // with arrays or generics to be recursively batched in the same ep_rt_mono_log_type_and_parameters call
+       switch (mono_underlying_type->type) {
+       case MONO_TYPE_ARRAY:
+       case MONO_TYPE_SZARRAY:
+       {
+               MonoArrayType *mono_array_type = mono_type_get_array_type (mono_type);
+               val->fixed_sized_data.flags |= TYPE_FLAGS_ARRAY;
+               if (mono_underlying_type->type == MONO_TYPE_ARRAY) {
+                       // Only ranks less than TypeFlagsArrayRankMax are supported.
+                       // Fortunately TypeFlagsArrayRankMax should be greater than the
+                       // number of ranks the type loader will support
+                       uint32_t rank = mono_array_type->rank;
+                       if (rank < TYPE_FLAGS_ARRAY_RANK_MAX) {
+                               rank <<= 8;
+                               val->fixed_sized_data.flags |= rank;
+                       }
+               }
+
+               // mono arrays are always arrays of by value types
+               val->mono_type_parameters = mono_mempool_alloc0 (type_logger->mem_pool, 1 * sizeof (MonoType*));
+               *val->mono_type_parameters = m_class_get_byval_arg (mono_array_type->eklass);
+               val->type_parameters_count++;
+               break;
+       }
+       case MONO_TYPE_GENERICINST:
+       {
+               MonoGenericInst *class_inst = mono_type->data.generic_class->context.class_inst;
+               val->type_parameters_count = class_inst->type_argc;
+               val->mono_type_parameters = mono_mempool_alloc0 (type_logger->mem_pool, val->type_parameters_count * sizeof (MonoType*));
+               memcpy (val->mono_type_parameters, class_inst->type_argv, val->type_parameters_count * sizeof (MonoType*));
+               break;
+       }
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_VALUETYPE:
+       case MONO_TYPE_PTR:
+       case MONO_TYPE_BYREF:
+       {
+               if (mono_underlying_type == mono_type)
+                       break;
+               val->mono_type_parameters = mono_mempool_alloc0 (type_logger->mem_pool, 1 * sizeof (MonoType*));
+               *val->mono_type_parameters = mono_underlying_type;
+               val->type_parameters_count++;
+               break;
+       }
+       default:
+               break;
+       }
+
+       val->name = "";
+       bool log_type_name = is_keyword_and_level_enabled (&RUNTIME_PROVIDER_CONTEXT, EP_EVENT_LEVEL_INFORMATIONAL, GC_HEAP_AND_TYPE_NAMES_KEYWORD);
+       if (type_logger->type_cache && log_type_name) {
+               dn_umap_it_t result = dn_umap_find (type_logger->type_cache, GUINT64_TO_POINTER (val->fixed_sized_data.type_id));
+               if (dn_umap_it_end (result) || !dn_umap_it_value (result)) {
+                       dn_umap_result_t insert = dn_umap_insert_or_assign (type_logger->type_cache, GUINT64_TO_POINTER (val->fixed_sized_data.type_id), mono_type_get_name_full (mono_type, MONO_TYPE_NAME_FORMAT_IL));
+                       if (insert.result)
+                               result = insert.it;
+               }
+               val->name = !dn_umap_it_end (result) ? (const ep_char8_t *)dn_umap_it_value (result) : "";
+       }
+
+       // Now that we know the full size of this type's data, see if it fits in our
+       // batch or whether we need to flush
+       int val_byte_count = bulk_type_get_byte_count_in_event (val);
+       if (val_byte_count > MAX_TYPE_VALUES_BYTES) {
+               // NOTE: If name is actively used, set it to NULL and relevant memory management to reduce byte count
+               // This type is apparently so huge, it's too big to squeeze into an event, even
+               // if it were the only type batched in the whole event.  Bail
+               mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed to log single mono type %p with typeID %llu. Type is too large for the BulkType Event.\n", (gpointer)mono_type, (unsigned long long)val->fixed_sized_data.type_id);
+               return -1;
+       }
+
+       if (type_logger->bulk_type_value_byte_count + val_byte_count > MAX_TYPE_VALUES_BYTES) {
+               // Although this type fits into the array, its size is so big that the entire
+               // array can't be logged via ETW. So flush the array, and start over by
+               // calling ourselves--this refetches the type info and puts it at the
+               // beginning of the array.  Since we know this type is small enough to be
+               // batched into an event on its own, this recursive call will not try to
+               // call itself again.
+               g_assert (type_logger->bulk_type_value_byte_count + val_byte_count > MAX_TYPE_VALUES_BYTES);
+               bulk_type_fire_bulk_type_event (type_logger);
+               return bulk_type_log_single_type (type_logger, mono_type);
+       }
+
+       // The type fits into the batch, so update our state
+       type_logger->bulk_type_value_count++;
+       type_logger->bulk_type_value_byte_count += val_byte_count;
+       return type_logger->bulk_type_value_count - 1;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// High-level method to batch a type and (recursively) its type parameters, flushing to
+// ETW as needed.  This is called by bulk_type_log_type_and_parameters_if_necessary.
+//
+// Arguments:
+//     * type_logger - BulkTypeEventLogger instance
+//      * mono_type - MonoType to be logged
+//      log_behavior - Describe how type should be logged.
+//
+// This follows CoreCLR's BulkTypeEventLogger::LogTypeAndParameter
+
+static
+void
+bulk_type_log_type_and_parameters (
+       BulkTypeEventLogger *type_logger,
+       MonoType *mono_type,
+       TypeLogBehavior log_behavior)
+{
+       // Batch up this type.  This grabs useful info about the type, including any
+       // type parameters it may have, and sticks it in bulk_type_values
+       int bulk_type_value_index = bulk_type_log_single_type (type_logger, mono_type);
+       if (bulk_type_value_index == -1) {
+               // There was a failure trying to log the type, so don't bother with its type
+               // parameters
+               return;
+       }
+
+       // Look at the type info we just batched, so we can get the type parameters
+       BulkTypeValue *val = &type_logger->bulk_type_values [bulk_type_value_index];
+
+       // We're about to recursively call ourselves for the type parameters, so make a
+       // local copy of their type handles first (else, as we log them we could flush
+       // and clear out bulk_type_values, thus trashing val)
+       uint32_t param_count = val->type_parameters_count;
+       if (param_count == 0)
+               return;
+
+       MonoType **mono_type_parameters = mono_mempool_alloc0 (type_logger->mem_pool, param_count * sizeof (MonoType*));
+       memcpy (mono_type_parameters, val->mono_type_parameters, sizeof (MonoType*) * param_count);
+
+       if (log_behavior == TYPE_LOG_BEHAVIOR_ALWAYS_LOG_TOP_LEVEL)
+               log_behavior = TYPE_LOG_BEHAVIOR_IF_FIRST_TIME;
+
+       for (uint32_t i = 0; i < param_count; i++)
+               bulk_type_log_type_and_parameters_if_necessary (type_logger, mono_type_parameters [i], log_behavior);
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Outermost level of ETW-type-logging.  This method is used to log a unique type identifier
+// (in this case a MonoType) and (recursively) its type parameters when present.
+//
+// Arguments:
+//     * type_logger - BulkTypeEventLogger instance
+//      * mono_type - MonoType to be logged
+//      log_behavior - Describe how type should be logged.
+//
+// This follows CoreCLR's BulkTypeEventLogger::LogTypeAndParameters
+
+static
+void
+bulk_type_log_type_and_parameters_if_necessary (
+       BulkTypeEventLogger *type_logger,
+       MonoType *mono_type,
+       TypeLogBehavior log_behavior)
+{
+       if (!is_keyword_and_level_enabled (&RUNTIME_PROVIDER_CONTEXT, EP_EVENT_LEVEL_INFORMATIONAL, TYPE_KEYWORD))
+               return;
+
+       bool log_type = (log_behavior == TYPE_LOG_BEHAVIOR_ALWAYS_LOG || log_behavior == TYPE_LOG_BEHAVIOR_ALWAYS_LOG_TOP_LEVEL);
+
+       if (!log_type && type_logger) {
+               uint64_t type_id = get_typeid_for_type (mono_type);
+               dn_umap_result_t result = dn_umap_insert (type_logger->type_cache, GUINT64_TO_POINTER (type_id), NULL);
+               log_type = result.result;
+       }
+
+       if (!log_type)
+               return;
+
+       if (type_logger)
+               bulk_type_log_type_and_parameters (type_logger, mono_type, log_behavior);
+}
+
+//---------------------------------------------------------------------------------------
+//
+// write_method_details_event is the method responsible for sending details of
+// methods involved in events such as JitStart, Load/Unload, Rundown, R2R, and other
+// eventpipe events. It calls ep_rt_mono_log_type_and_parameters_if_necessary to log
+// unique types from the method type and available method instantiation parameter types
+// that are ultimately emitted as a BulkType event in ep_rt_mono_fire_bulk_type_event.
+// After appropriately logging type information, it sends method details outlined by
+// the generated dotnetruntime.c and ClrEtwAll manifest.
+//
+// Arguments:
+//      * method - a MonoMethod hit during an eventpipe event
+//
+// This follows CoreCLR's ETW::MethodLog::SendMethodDetailsEvent
+
+static
+void
+write_event_method_details (MonoMethod *method)
+{
+       if (method->wrapper_type != MONO_WRAPPER_NONE || method->dynamic)
+               return;
+
+       MonoGenericContext *method_ctx = mono_method_get_context (method);
+
+       MonoGenericInst *method_inst = NULL;
+       if (method_ctx)
+               method_inst = method_ctx->method_inst;
+
+       if (method_inst && method_inst->type_argc > MAX_METHOD_TYPE_ARGUMENT_COUNT)
+               return;
+
+       BulkTypeEventLogger *type_logger = bulk_type_event_logger_alloc ();
+
+       uint64_t method_type_id = 0;
+       g_assert (mono_metadata_token_index (method->token) != 0);
+       uint32_t method_token = mono_metadata_make_token (MONO_TABLE_METHOD, mono_metadata_token_index (method->token));
+       uint64_t loader_module_id = 0;
+       MonoClass *klass = method->klass;
+       if (klass) {
+               MonoType *method_mono_type = m_class_get_byval_arg (klass);
+               method_type_id = get_typeid_for_class (klass);
+
+               bulk_type_log_type_and_parameters_if_necessary (type_logger, method_mono_type, TYPE_LOG_BEHAVIOR_ALWAYS_LOG);
+
+               loader_module_id = (uint64_t)mono_class_get_image (klass);
+       }
+
+       uint32_t method_inst_parameter_types_count = 0;
+       if (method_inst)
+               method_inst_parameter_types_count = method_inst->type_argc;
+
+       uint64_t *method_inst_parameters_type_ids = mono_mempool_alloc0 (type_logger->mem_pool, method_inst_parameter_types_count * sizeof (uint64_t));
+       uint8_t *buffer = (uint8_t *)method_inst_parameters_type_ids;
+       for (uint32_t i = 0; i < method_inst_parameter_types_count; i++) {
+               ep_write_buffer_uint64_t (&buffer, get_typeid_for_type (method_inst->type_argv [i]));
+
+               bulk_type_log_type_and_parameters_if_necessary (type_logger, method_inst->type_argv [i], TYPE_LOG_BEHAVIOR_ALWAYS_LOG);
+       }
+
+       bulk_type_fire_bulk_type_event (type_logger);
+
+       FireEtwMethodDetails (
+               (uint64_t)method,
+               method_type_id,
+               method_token,
+               method_inst_parameter_types_count,
+               loader_module_id,
+               (uint64_t*)method_inst_parameters_type_ids,
+               NULL,
+               NULL);
+
+       bulk_type_event_logger_free (type_logger);
+}
+
+static
+bool
+write_event_jit_start (MonoMethod *method)
+{
+       if (!EventEnabledMethodJittingStarted_V1 ())
+               return true;
+
+       //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc.
+       if (method) {
+               uint64_t method_id = 0;
+               uint64_t module_id = 0;
+               uint32_t code_size = 0;
+               uint32_t method_token = 0;
+               char *method_namespace = NULL;
+               const char *method_name = NULL;
+               char *method_signature = NULL;
+
+               write_event_method_details (method);
+
+               method_id = (uint64_t)method;
+
+               if (!method->dynamic)
+                       method_token = method->token;
+
+               if (!mono_method_has_no_body (method)) {
+                       ERROR_DECL (error);
+                       MonoMethodHeader *header = mono_method_get_header_internal (method, error);
+                       if (header)
+                               code_size = header->code_size;
+               }
+
+               method_name = method->name;
+               method_signature = mono_signature_full_name (mono_method_signature_internal (method));
+
+               if (method->klass) {
+                       module_id = (uint64_t)m_class_get_image (method->klass);
+                       method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL);
+               }
+
+               FireEtwMethodJittingStarted_V1 (
+                       method_id,
+                       module_id,
+                       method_token,
+                       code_size,
+                       method_namespace,
+                       method_name,
+                       method_signature,
+                       clr_instance_get_id (),
+                       NULL,
+                       NULL);
+
+               g_free (method_namespace);
+               g_free (method_signature);
+       }
+
+       return true;
+}
+
+static
+bool
+write_event_method_il_to_native_map (
+       MonoMethod *method,
+       MonoJitInfo *ji)
+{
+       if (!EventEnabledMethodILToNativeMap ())
+               return true;
+
+       if (method) {
+               // Under netcore we only have root domain.
+               MonoDomain *root_domain = mono_get_root_domain ();
+
+               uint64_t method_id = (uint64_t)method;
+               uint32_t fixed_buffer [64];
+               uint8_t *buffer = NULL;
+
+               uint32_t offset_entries = 0;
+               uint32_t *il_offsets = NULL;
+               uint32_t *native_offsets = NULL;
+
+               MonoDebugMethodJitInfo *debug_info = method ? mono_debug_find_method (method, root_domain) : NULL;
+               if (debug_info) {
+                       offset_entries = debug_info->num_line_numbers;
+                       if (offset_entries != 0) {
+                               size_t needed_size = (offset_entries * sizeof (uint32_t) * 2);
+                               if (needed_size > sizeof (fixed_buffer)) {
+                                       buffer = g_new (uint8_t, needed_size);
+                                       il_offsets = (uint32_t*)buffer;
+                               } else {
+                                       il_offsets = fixed_buffer;
+                               }
+                               if (il_offsets) {
+                                       native_offsets = il_offsets + offset_entries;
+                                       uint8_t *il_offsets_ptr = (uint8_t *)il_offsets;
+                                       uint8_t *native_offsets_ptr = (uint8_t *)native_offsets;
+                                       for (uint32_t offset_count = 0; offset_count < offset_entries; ++offset_count) {
+                                               ep_write_buffer_uint32_t (&il_offsets_ptr, debug_info->line_numbers [offset_count].il_offset);
+                                               ep_write_buffer_uint32_t (&native_offsets_ptr, debug_info->line_numbers [offset_count].native_offset);
+                                       }
+                               }
+                       }
+
+                       mono_debug_free_method_jit_info (debug_info);
+               }
+
+               if (!il_offsets && !native_offsets) {
+                       // No IL offset -> Native offset mapping available. Put all code on IL offset 0.
+                       EP_ASSERT (sizeof (fixed_buffer) >= sizeof (uint32_t) * 2);
+                       offset_entries = 1;
+                       il_offsets = fixed_buffer;
+                       native_offsets = il_offsets + offset_entries;
+                       il_offsets [0] = 0;
+                       native_offsets [0] = ji ? ep_rt_val_uint32_t ((uint32_t)ji->code_size) : 0;
+               }
+
+               FireEtwMethodILToNativeMap (
+                       method_id,
+                       0,
+                       0,
+                       GUINT32_TO_UINT16 (offset_entries),
+                       il_offsets,
+                       native_offsets,
+                       clr_instance_get_id (),
+                       NULL,
+                       NULL);
+
+               g_free (buffer);
+       }
+
+       return true;
+}
+
+static
+bool
+write_event_method_load (
+       MonoMethod *method,
+       MonoJitInfo *ji)
+{
+       if (!EventEnabledMethodLoad_V1 () && !EventEnabledMethodLoadVerbose_V1 ())
+               return true;
+
+       //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc.
+       if (method) {
+               uint64_t method_id = 0;
+               uint64_t module_id = 0;
+               uint64_t method_code_start = ji ? (uint64_t)ji->code_start : 0;
+               uint32_t method_code_size = ji ? (uint32_t)ji->code_size : 0;
+               uint32_t method_token = 0;
+               uint32_t method_flags = 0;
+               uint8_t kind = MONO_CLASS_DEF;
+               char *method_namespace = NULL;
+               const char *method_name = NULL;
+               char *method_signature = NULL;
+               bool verbose = (RUNTIME_PROVIDER_CONTEXT.Level >= (uint8_t)EP_EVENT_LEVEL_VERBOSE);
+
+               method_id = (uint64_t)method;
+
+               if (!method->dynamic)
+                       method_token = method->token;
+
+               if (ji && mono_jit_info_get_generic_sharing_context (ji)) {
+                       method_flags |= METHOD_FLAGS_SHARED_GENERIC_METHOD;
+                       verbose = true;
+               }
+
+               if (method->dynamic) {
+                       method_flags |= METHOD_FLAGS_DYNAMIC_METHOD;
+                       verbose = true;
+               }
+
+               if (ji && !ji->from_aot && !ji->from_llvm) {
+                       method_flags |= METHOD_FLAGS_JITTED_METHOD;
+                       if (method->wrapper_type != MONO_WRAPPER_NONE)
+                               method_flags |= METHOD_FLAGS_JITTED_HELPER_METHOD;
+               }
+
+               if (method->is_generic || method->is_inflated) {
+                       method_flags |= METHOD_FLAGS_GENERIC_METHOD;
+                       verbose = true;
+               }
+
+               if (method->klass) {
+                       module_id = (uint64_t)m_class_get_image (method->klass);
+                       kind = m_class_get_class_kind (method->klass);
+                       if (kind == MONO_CLASS_GTD || kind == MONO_CLASS_GINST)
+                               method_flags |= METHOD_FLAGS_GENERIC_METHOD;
+               }
+
+               write_event_method_details (method);
+
+               if (verbose) {
+                       method_name = method->name;
+                       method_signature = mono_signature_full_name (mono_method_signature_internal (method));
+
+                       if (method->klass)
+                               method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL);
+
+                       FireEtwMethodLoadVerbose_V1 (
+                               method_id,
+                               module_id,
+                               method_code_start,
+                               method_code_size,
+                               method_token,
+                               method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION,
+                               method_namespace,
+                               method_name,
+                               method_signature,
+                               clr_instance_get_id (),
+                               NULL,
+                               NULL);
+
+                       if (ji && (ji->from_aot || ji->from_llvm))
+                               FireEtwMethodLoadVerbose_V1 (
+                                       method_id,
+                                       module_id,
+                                       method_code_start,
+                                       method_code_size,
+                                       method_token,
+                                       method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION,
+                                       method_namespace,
+                                       method_name,
+                                       method_signature,
+                                       clr_instance_get_id (),
+                                       NULL,
+                                       NULL);
+               } else {
+                       FireEtwMethodLoad_V1 (
+                               method_id,
+                               module_id,
+                               method_code_start,
+                               method_code_size,
+                               method_token,
+                               method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION,
+                               clr_instance_get_id (),
+                               NULL,
+                               NULL);
+
+                       if (ji && (ji->from_aot || ji->from_llvm))
+                               FireEtwMethodLoad_V1 (
+                                       method_id,
+                                       module_id,
+                                       method_code_start,
+                                       method_code_size,
+                                       method_token,
+                                       method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION,
+                                       clr_instance_get_id (),
+                                       NULL,
+                                       NULL);
+               }
+
+               g_free (method_namespace);
+               g_free (method_signature);
+       }
+
+       return true;
+}
+
+static
+bool
+write_event_module_load (MonoImage *image)
+{
+       if (!EventEnabledModuleLoad_V2 () && !EventEnabledDomainModuleLoad_V1 ())
+               return true;
+
+       if (image) {
+               ModuleEventData module_data;
+               memset (&module_data, 0, sizeof (module_data));
+               if (get_module_event_data (image, &module_data)) {
+                       FireEtwModuleLoad_V2 (
+                               module_data.module_id,
+                               module_data.assembly_id,
+                               module_data.module_flags,
+                               module_data.reserved_flags,
+                               module_data.module_il_path,
+                               module_data.module_native_path,
+                               clr_instance_get_id (),
+                               module_data.module_il_pdb_signature,
+                               module_data.module_il_pdb_age,
+                               module_data.module_il_pdb_path,
+                               module_data.module_native_pdb_signature,
+                               module_data.module_native_pdb_age,
+                               module_data.module_native_pdb_path,
+                               NULL,
+                               NULL);
+
+                       FireEtwDomainModuleLoad_V1 (
+                               module_data.module_id,
+                               module_data.assembly_id,
+                               module_data.domain_id,
+                               module_data.module_flags,
+                               module_data.reserved_flags,
+                               module_data.module_il_path,
+                               module_data.module_native_path,
+                               clr_instance_get_id (),
+                               NULL,
+                               NULL);
+               }
+       }
+
+       return true;
+}
+
+static
+bool
+write_event_module_unload (MonoImage *image)
+{
+       if (!EventEnabledModuleUnload_V2())
+               return true;
+
+       if (image) {
+               ModuleEventData module_data;
+               memset (&module_data, 0, sizeof (module_data));
+               if (get_module_event_data (image, &module_data)) {
+                       FireEtwModuleUnload_V2 (
+                               module_data.module_id,
+                               module_data.assembly_id,
+                               module_data.module_flags,
+                               module_data.reserved_flags,
+                               module_data.module_il_path,
+                               module_data.module_native_path,
+                               clr_instance_get_id (),
+                               module_data.module_il_pdb_signature,
+                               module_data.module_il_pdb_age,
+                               module_data.module_il_pdb_path,
+                               module_data.module_native_pdb_signature,
+                               module_data.module_native_pdb_age,
+                               module_data.module_native_pdb_path,
+                               NULL,
+                               NULL);
+               }
+       }
+
+       return true;
+}
+
+static
+bool
+get_assembly_event_data (
+       MonoAssembly *assembly,
+       AssemblyEventData *assembly_data)
+{
+       if (assembly && assembly_data) {
+               // Under netcore we only have root domain.
+               MonoDomain *root_domain = mono_get_root_domain ();
+
+               assembly_data->domain_id = (uint64_t)root_domain;
+               assembly_data->assembly_id = (uint64_t)assembly;
+               assembly_data->binding_id = 0;
+
+               assembly_data->assembly_flags = 0;
+               if (assembly->dynamic)
+                       assembly_data->assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY;
+
+               if (assembly->image && assembly->image->aot_module)
+                       assembly_data->assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY;
+
+               assembly_data->assembly_name = mono_stringify_assembly_name (&assembly->aname);
+       }
+
+       return true;
+}
+
+static
+bool
+write_event_assembly_load (MonoAssembly *assembly)
+{
+       if (!EventEnabledAssemblyLoad_V1 ())
+               return true;
+
+       if (assembly) {
+               AssemblyEventData assembly_data;
+               memset (&assembly_data, 0, sizeof (assembly_data));
+               if (get_assembly_event_data (assembly, &assembly_data)) {
+                       FireEtwAssemblyLoad_V1 (
+                               assembly_data.assembly_id,
+                               assembly_data.domain_id,
+                               assembly_data.binding_id,
+                               assembly_data.assembly_flags,
+                               assembly_data.assembly_name,
+                               clr_instance_get_id (),
+                               NULL,
+                               NULL);
+
+                       g_free (assembly_data.assembly_name);
+               }
+       }
+
+       return true;
+}
+
+static
+bool
+write_event_assembly_unload (MonoAssembly *assembly)
+{
+       if (!EventEnabledAssemblyUnload_V1 ())
+               return true;
+
+       if (assembly) {
+               AssemblyEventData assembly_data;
+               memset (&assembly_data, 0, sizeof (assembly_data));
+               if (get_assembly_event_data (assembly, &assembly_data)) {
+                       FireEtwAssemblyUnload_V1 (
+                               assembly_data.assembly_id,
+                               assembly_data.domain_id,
+                               assembly_data.binding_id,
+                               assembly_data.assembly_flags,
+                               assembly_data.assembly_name,
+                               clr_instance_get_id (),
+                               NULL,
+                               NULL);
+
+                       g_free (assembly_data.assembly_name);
+               }
+       }
+
+       return true;
+}
+
+static
+bool
+write_event_thread_created (ep_rt_thread_id_t tid)
+{
+       if (!EventEnabledThreadCreated ())
+               return true;
+
+       uint64_t managed_thread = 0;
+       uint32_t native_thread_id = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
+       uint32_t managed_thread_id = 0;
+       uint32_t flags = 0;
+
+       MonoThread *thread = mono_thread_current ();
+       if (thread && mono_thread_info_get_tid (thread->thread_info) == tid) {
+               managed_thread_id = mono_thread_get_managed_id (thread);
+               managed_thread = (uint64_t)thread;
+
+               switch (mono_thread_info_get_flags (thread->thread_info)) {
+               case MONO_THREAD_INFO_FLAGS_NO_GC:
+               case MONO_THREAD_INFO_FLAGS_NO_SAMPLE:
+                       flags |= THREAD_FLAGS_GC_SPECIAL;
+               }
+
+               if (mono_gc_is_finalizer_thread (thread))
+                       flags |= THREAD_FLAGS_FINALIZER;
+
+               if (thread->threadpool_thread)
+                       flags |= THREAD_FLAGS_THREADPOOL_WORKER;
+       }
+
+       FireEtwThreadCreated (
+               managed_thread,
+               (uint64_t)mono_get_root_domain (),
+               flags,
+               managed_thread_id,
+               native_thread_id,
+               clr_instance_get_id (),
+               NULL,
+               NULL);
+
+       return true;
+}
+
+static
+bool
+write_event_thread_terminated (ep_rt_thread_id_t tid)
+{
+       if (!EventEnabledThreadTerminated ())
+               return true;
+
+       uint64_t managed_thread = 0;
+       MonoThread *thread = mono_thread_current ();
+       if (thread && mono_thread_info_get_tid (thread->thread_info) == tid)
+               managed_thread = (uint64_t)thread;
+
+       FireEtwThreadTerminated (
+               managed_thread,
+               (uint64_t)mono_get_root_domain (),
+               clr_instance_get_id (),
+               NULL,
+               NULL);
+
+       return true;
+}
+
+static
+uint32_t
+get_type_start_id (MonoType *type)
+{
+       uint32_t start_id = (uint32_t)(uintptr_t)type;
+
+       start_id = (((start_id * 215497) >> 16) ^ ((start_id * 1823231) + start_id));
+
+MONO_DISABLE_WARNING(4127) /* conditional expression is constant */
+       // Mix in highest bits on 64-bit systems only
+       if (sizeof (type) > 4)
+               start_id = start_id ^ GUINT64_TO_UINT32 ((((uint64_t)type >> 31) >> 1));
+MONO_RESTORE_WARNING
+
+       return start_id;
+}
+
+static
+bool
+write_event_type_load_start (MonoType *type)
+{
+       if (!EventEnabledTypeLoadStart ())
+               return true;
+
+       FireEtwTypeLoadStart (
+               get_type_start_id (type),
+               clr_instance_get_id (),
+               NULL,
+               NULL);
+
+       return true;
+}
+
+static
+bool
+write_event_type_load_stop (MonoType *type)
+{
+       if (!EventEnabledTypeLoadStop ())
+               return true;
+
+       char *type_name = NULL;
+       if (type)
+               type_name = mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
+
+       FireEtwTypeLoadStop (
+               get_type_start_id (type),
+               clr_instance_get_id (),
+               6 /* CLASS_LOADED */,
+               (uint64_t)type,
+               type_name,
+               NULL,
+               NULL);
+
+       g_free (type_name);
+
+       return true;
+}
+
+static
+gboolean
+get_exception_ip_func (
+       MonoStackFrameInfo *frame,
+       MonoContext *ctx,
+       void *data)
+{
+       *(uintptr_t *)data = (uintptr_t)MONO_CONTEXT_GET_IP (ctx);
+       return TRUE;
+}
+
+static
+bool
+write_event_exception_thrown (MonoObject *obj)
+{
+       if (!EventEnabledExceptionThrown_V1 ())
+               return true;
+
+       if (obj) {
+               ERROR_DECL (error);
+               char *type_name = NULL;
+               char *exception_message = NULL;
+               uint16_t flags = 0;
+               uint32_t hresult = 0;
+               uintptr_t ip = 0;
+
+               if (mono_object_isinst_checked ((MonoObject *) obj, mono_get_exception_class (), error)) {
+                       MonoException *exception = (MonoException *)obj;
+                       flags |= EXCEPTION_THROWN_FLAGS_IS_CLS_COMPLIANT;
+                       if (exception->inner_ex)
+                               flags |= EXCEPTION_THROWN_FLAGS_HAS_INNER;
+                       if (exception->message)
+                               exception_message = ep_rt_utf16_to_utf8_string (mono_string_chars_internal (exception->message), mono_string_length_internal (exception->message));
+                       hresult = exception->hresult;
+               }
+
+               if (exception_message == NULL)
+                       exception_message = g_strdup ("");
+
+               if (mono_get_eh_callbacks ()->mono_walk_stack_with_ctx)
+                       mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (get_exception_ip_func, NULL, MONO_UNWIND_SIGNAL_SAFE, (void *)&ip);
+
+               type_name = mono_type_get_name_full (m_class_get_byval_arg (mono_object_class (obj)), MONO_TYPE_NAME_FORMAT_IL);
+
+               FireEtwExceptionThrown_V1 (
+                       type_name,
+                       exception_message,
+                       (void *)&ip,
+                       hresult,
+                       flags,
+                       clr_instance_get_id (),
+                       NULL,
+                       NULL);
+
+               if (!mono_component_profiler_clauses_enabled ()) {
+                       FireEtwExceptionThrownStop (
+                               NULL,
+                               NULL);
+               }
+
+               g_free (exception_message);
+               g_free (type_name);
+
+               mono_error_cleanup (error);
+       }
+
+       return true;
+}
+
+static
+bool
+write_event_exception_clause (
+       MonoMethod *method,
+       uint32_t clause_num,
+       MonoExceptionEnum clause_type,
+       MonoObject *obj)
+{
+       if (!mono_component_profiler_clauses_enabled ())
+               return true;
+
+       if ((clause_type == MONO_EXCEPTION_CLAUSE_FAULT || clause_type == MONO_EXCEPTION_CLAUSE_NONE) && (!EventEnabledExceptionCatchStart() || !EventEnabledExceptionCatchStop()))
+               return true;
+
+       if (clause_type == MONO_EXCEPTION_CLAUSE_FILTER && (!EventEnabledExceptionFilterStart() || !EventEnabledExceptionFilterStop()))
+               return true;
+
+       if (clause_type == MONO_EXCEPTION_CLAUSE_FINALLY && (!EventEnabledExceptionFinallyStart() || !EventEnabledExceptionFinallyStop()))
+               return true;
+
+       uintptr_t ip = 0; //TODO: Have profiler pass along IP of handler block.
+       uint64_t method_id = (uint64_t)method;
+       char *method_name = NULL;
+
+       method_name = mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL);
+
+       if ((clause_type == MONO_EXCEPTION_CLAUSE_FAULT || clause_type == MONO_EXCEPTION_CLAUSE_NONE)) {
+               FireEtwExceptionCatchStart (
+                       (uint64_t)ip,
+                       method_id,
+                       (const ep_char8_t *)method_name,
+                       clr_instance_get_id (),
+                       NULL,
+                       NULL);
+
+               FireEtwExceptionCatchStop (
+                       NULL,
+                       NULL);
+
+               FireEtwExceptionThrownStop (
+                       NULL,
+                       NULL);
+       }
+
+       if (clause_type == MONO_EXCEPTION_CLAUSE_FILTER) {
+               FireEtwExceptionFilterStart (
+                       (uint64_t)ip,
+                       method_id,
+                       (const ep_char8_t *)method_name,
+                       clr_instance_get_id (),
+                       NULL,
+                       NULL);
+
+               FireEtwExceptionFilterStop (
+                       NULL,
+                       NULL);
+       }
+
+       if (clause_type == MONO_EXCEPTION_CLAUSE_FINALLY) {
+               FireEtwExceptionFinallyStart (
+                       (uint64_t)ip,
+                       method_id,
+                       (const ep_char8_t *)method_name,
+                       clr_instance_get_id (),
+                       NULL,
+                       NULL);
+
+               FireEtwExceptionFinallyStop (
+                       NULL,
+                       NULL);
+       }
+
+       g_free (method_name);
+       return true;
+}
+
+static
+bool
+write_event_monitor_contention_start (MonoObject *obj)
+{
+       if (!EventEnabledContentionStart_V1 ())
+               return true;
+
+       FireEtwContentionStart_V1 (
+               0 /* ManagedContention */,
+               clr_instance_get_id (),
+               NULL,
+               NULL);
+
+       return true;
+}
+
+static
+bool
+write_event_monitor_contention_stop (MonoObject *obj)
+{
+       if (!EventEnabledContentionStop ())
+               return true;
+
+       FireEtwContentionStop (
+               0 /* ManagedContention */,
+               clr_instance_get_id (),
+               NULL,
+               NULL);
+
+       return true;
+}
+
+static
+bool
+write_event_method_jit_memory_allocated_for_code (
+       const uint8_t *buffer,
+       uint64_t size,
+       MonoProfilerCodeBufferType type,
+       const void *data)
+{
+       if (!EventEnabledMethodJitMemoryAllocatedForCode ())
+               return true;
+
+       if (type != MONO_PROFILER_CODE_BUFFER_METHOD)
+               return true;
+
+       uint64_t method_id = 0;
+       uint64_t module_id = 0;
+
+       if (data) {
+               MonoMethod *method;
+               method = (MonoMethod *)data;
+               method_id = (uint64_t)method;
+               if (method->klass)
+                       module_id = (uint64_t)(uint64_t)m_class_get_image (method->klass);
+       }
+
+       FireEtwMethodJitMemoryAllocatedForCode (
+               method_id,
+               module_id,
+               size,
+               0,
+               size,
+               0 /* CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN */,
+               clr_instance_get_id (),
+               NULL,
+               NULL);
+
+       return true;
+}
+
+bool
+ep_rt_write_event_ee_startup_start (void)
+{
+       return FireEtwEEStartupStart_V1 (
+               clr_instance_get_id (),
+               NULL,
+               NULL);
+}
+
+bool
+ep_rt_write_event_threadpool_worker_thread_start (
+       uint32_t active_thread_count,
+       uint32_t retired_worker_thread_count,
+       uint16_t clr_instance_id)
+{
+       return FireEtwThreadPoolWorkerThreadStart (
+               active_thread_count,
+               retired_worker_thread_count,
+               clr_instance_id,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_threadpool_worker_thread_stop (
+       uint32_t active_thread_count,
+       uint32_t retired_worker_thread_count,
+       uint16_t clr_instance_id)
+{
+       return FireEtwThreadPoolWorkerThreadStop (
+               active_thread_count,
+               retired_worker_thread_count,
+               clr_instance_id,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_threadpool_worker_thread_wait (
+       uint32_t active_thread_count,
+       uint32_t retired_worker_thread_count,
+       uint16_t clr_instance_id)
+{
+       return FireEtwThreadPoolWorkerThreadWait (
+               active_thread_count,
+               retired_worker_thread_count,
+               clr_instance_id,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_threadpool_min_max_threads (
+       uint16_t min_worker_threads,
+       uint16_t max_worker_threads,
+       uint16_t min_io_completion_threads,
+       uint16_t max_io_completion_threads,
+       uint16_t clr_instance_id)
+{
+       return FireEtwThreadPoolMinMaxThreads (
+               min_worker_threads,
+               max_worker_threads,
+               min_io_completion_threads,
+               max_io_completion_threads,
+               clr_instance_id,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_threadpool_worker_thread_adjustment_sample (
+       double throughput,
+       uint16_t clr_instance_id)
+{
+       return FireEtwThreadPoolWorkerThreadAdjustmentSample (
+               throughput,
+               clr_instance_id,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_threadpool_worker_thread_adjustment_adjustment (
+       double average_throughput,
+       uint32_t networker_thread_count,
+       /*NativeRuntimeEventSource.ThreadAdjustmentReasonMap*/ int32_t reason,
+       uint16_t clr_instance_id)
+{
+       return FireEtwThreadPoolWorkerThreadAdjustmentAdjustment (
+               average_throughput,
+               networker_thread_count,
+               reason,
+               clr_instance_id,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_threadpool_worker_thread_adjustment_stats (
+       double duration,
+       double throughput,
+       double threadpool_worker_thread_wait,
+       double throughput_wave,
+       double throughput_error_estimate,
+       double average_throughput_error_estimate,
+       double throughput_ratio,
+       double confidence,
+       double new_control_setting,
+       uint16_t new_thread_wave_magnitude,
+       uint16_t clr_instance_id)
+{
+       return FireEtwThreadPoolWorkerThreadAdjustmentStats (
+               duration,
+               throughput,
+               threadpool_worker_thread_wait,
+               throughput_wave,
+               throughput_error_estimate,
+               average_throughput_error_estimate,
+               throughput_ratio,
+               confidence,
+               new_control_setting,
+               new_thread_wave_magnitude,
+               clr_instance_id,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_threadpool_io_enqueue (
+       intptr_t native_overlapped,
+       intptr_t overlapped,
+       bool multi_dequeues,
+       uint16_t clr_instance_id)
+{
+       return FireEtwThreadPoolIOEnqueue (
+               (const void *)native_overlapped,
+               (const void *)overlapped,
+               multi_dequeues,
+               clr_instance_id,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_threadpool_io_dequeue (
+       intptr_t native_overlapped,
+       intptr_t overlapped,
+       uint16_t clr_instance_id)
+{
+       return FireEtwThreadPoolIODequeue (
+               (const void *)native_overlapped,
+               (const void *)overlapped,
+               clr_instance_id,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_threadpool_working_thread_count (
+       uint16_t count,
+       uint16_t clr_instance_id)
+{
+       return FireEtwThreadPoolWorkingThreadCount (
+               count,
+               clr_instance_id,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_threadpool_io_pack (
+       intptr_t native_overlapped,
+       intptr_t overlapped,
+       uint16_t clr_instance_id)
+{
+       return FireEtwThreadPoolIOPack (
+               (const void *)native_overlapped,
+               (const void *)overlapped,
+               clr_instance_id,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_contention_lock_created (
+       intptr_t lock_id,
+       intptr_t associated_object_id,
+       uint16_t clr_instance_id)
+{
+       return FireEtwContentionLockCreated (
+               (const void *)lock_id,
+               (const void *)associated_object_id,
+               clr_instance_id,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_contention_start (
+       uint8_t contention_flags,
+       uint16_t clr_instance_id,
+       intptr_t lock_id,
+       intptr_t associated_object_id,
+       uint64_t lock_owner_thread_id)
+{
+       return FireEtwContentionStart_V2 (
+               contention_flags,
+               clr_instance_id,
+               (const void *)lock_id,
+               (const void *)associated_object_id,
+               lock_owner_thread_id,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_contention_stop (
+       uint8_t contention_flags,
+       uint16_t clr_instance_id,
+       double duration_ns)
+{
+       return FireEtwContentionStop_V1 (
+               contention_flags,
+               clr_instance_id,
+               duration_ns,
+               NULL,
+               NULL) == 0 ? true : false;
+}
+
+static
+void
+jit_begin_callback (
+       MonoProfiler *prof,
+       MonoMethod *method)
+{
+       write_event_jit_start (method);
+}
+
+static
+void
+jit_failed_callback (
+       MonoProfiler *prof,
+       MonoMethod *method)
+{
+       //TODO: CoreCLR doesn't have this case, so no failure event currently exists.
+}
+
+static
+void
+jit_done_callback (
+       MonoProfiler *prof,
+       MonoMethod *method,
+       MonoJitInfo *ji)
+{
+       write_event_method_load (method, ji);
+       write_event_method_il_to_native_map (method, ji);
+}
+
+static
+void
+image_loaded_callback (
+       MonoProfiler *prof,
+       MonoImage *image)
+{
+       if (image && image->heap_pdb.size == 0)
+               write_event_module_load (image);
+}
+
+static
+void
+image_unloaded_callback (
+       MonoProfiler *prof,
+       MonoImage *image)
+{
+       if (image && image->heap_pdb.size == 0)
+               write_event_module_unload (image);
+}
+
+static
+void
+assembly_loaded_callback (
+       MonoProfiler *prof,
+       MonoAssembly *assembly)
+{
+       write_event_assembly_load (assembly);
+}
+
+static
+void
+assembly_unloaded_callback (
+       MonoProfiler *prof,
+       MonoAssembly *assembly)
+{
+       write_event_assembly_unload (assembly);
+}
+
+static
+void
+thread_started_callback (
+       MonoProfiler *prof,
+       uintptr_t tid)
+{
+       write_event_thread_created (ep_rt_uint64_t_to_thread_id_t (tid));
+}
+
+static
+void
+thread_stopped_callback (
+       MonoProfiler *prof,
+       uintptr_t tid)
+{
+       write_event_thread_terminated (ep_rt_uint64_t_to_thread_id_t (tid));
+}
+
+static
+void
+class_loading_callback (
+       MonoProfiler *prof,
+       MonoClass *klass)
+{
+       bool prevent_profiler_event_recursion = FALSE;
+       EventPipeMonoThreadData *thread_data = ep_rt_mono_thread_data_get_or_create ();
+       if (thread_data) {
+               // Prevent additional class loading to happen recursively as part of fire TypeLoadStart event.
+               // Additional class loading can happen as part of capturing callstack for TypeLoadStart event.
+               prevent_profiler_event_recursion = thread_data->prevent_profiler_event_recursion;
+               thread_data->prevent_profiler_event_recursion = TRUE;
+       }
+
+       write_event_type_load_start (m_class_get_byval_arg (klass));
+
+       if (thread_data)
+               thread_data->prevent_profiler_event_recursion = prevent_profiler_event_recursion;
+}
+
+static
+void
+class_failed_callback (
+       MonoProfiler *prof,
+       MonoClass *klass)
+{
+       write_event_type_load_stop (m_class_get_byval_arg (klass));
+}
+
+static
+void
+class_loaded_callback (
+       MonoProfiler *prof,
+       MonoClass *klass)
+{
+       write_event_type_load_stop (m_class_get_byval_arg (klass));
+}
+
+static
+void
+exception_throw_callback (
+       MonoProfiler *prof,
+       MonoObject *exc)
+{
+       write_event_exception_thrown (exc);
+}
+
+static
+void
+exception_clause_callback (
+       MonoProfiler *prof,
+       MonoMethod *method,
+       uint32_t clause_num,
+       MonoExceptionEnum clause_type,
+       MonoObject *exc)
+{
+       write_event_exception_clause (method, clause_num, clause_type, exc);
+}
+
+static
+void
+monitor_contention_callback (
+       MonoProfiler *prof,
+       MonoObject *obj)
+{
+       write_event_monitor_contention_start (obj);
+}
+
+static
+void
+monitor_acquired_callback (
+       MonoProfiler *prof,
+       MonoObject *obj)
+{
+       write_event_monitor_contention_stop (obj);
+}
+
+static
+void
+monitor_failed_callback (
+       MonoProfiler *prof,
+       MonoObject *obj)
+{
+       write_event_monitor_contention_stop (obj);
+}
+
+static
+void
+jit_code_buffer_callback (
+       MonoProfiler *prof,
+       const mono_byte *buffer,
+       uint64_t size,
+       MonoProfilerCodeBufferType type,
+       const void *data)
+{
+       write_event_method_jit_memory_allocated_for_code ((const uint8_t *)buffer, size, type, data);
+}
+
+static
+uint32_t
+gc_heap_dump_requests_inc (void)
+{
+       EP_ASSERT (ep_rt_mono_is_runtime_initialized ());
+       return ep_rt_atomic_inc_uint32_t (&_gc_heap_dump_requests);
+}
+
+static
+uint32_t
+gc_heap_dump_requests_dec (void)
+{
+       EP_ASSERT (ep_rt_mono_is_runtime_initialized ());
+       return ep_rt_atomic_dec_uint32_t (&_gc_heap_dump_requests);
+}
+
+static
+bool
+gc_heap_dump_requested (void)
+{
+       if (!ep_rt_mono_is_runtime_initialized ())
+               return false;
+       return ep_rt_volatile_load_uint32_t(&_gc_heap_dump_requests) != 0 ? true : false;
+}
+
+static
+uint32_t
+gc_heap_dump_count_inc (void)
+{
+       EP_ASSERT (ep_rt_mono_is_runtime_initialized ());
+       return ep_rt_atomic_inc_uint32_t (&_gc_heap_dump_count);
+}
+
+static
+bool
+gc_heap_dump_mem_file_buffer_init (GCHeapDumpMemFileBuffer *file_buffer)
+{
+       // Called on GC thread so no need to call MONO_ENTER_GC_SAFE/MONO_EXIT_GC_SAFE
+       // around IO functions.
+
+       EP_ASSERT (file_buffer);
+
+       file_buffer->fd = g_file_open_tmp ("mono_gc_heap_dump_XXXXXX", &file_buffer->name, NULL);
+       file_buffer->start = g_malloc (MAX_EVENT_BYTE_COUNT);
+       file_buffer->current = file_buffer->start;
+       file_buffer->end = file_buffer->start + MAX_EVENT_BYTE_COUNT;
+
+       return file_buffer->fd != -1 && file_buffer->start;
+}
+
+#ifndef g_close
+#ifdef G_OS_WIN32
+#define g_close _close
+#else
+#define g_close close
+#endif
+#endif
+
+static
+void
+gc_heap_dump_mem_file_buffer_fini (GCHeapDumpMemFileBuffer *file_buffer)
+{
+       // Called on GC thread so no need to call MONO_ENTER_GC_SAFE/MONO_EXIT_GC_SAFE
+       // around IO functions.
+
+       if (!file_buffer)
+               return;
+
+       if (file_buffer->fd != -1) {
+               g_close (file_buffer->fd);
+               if (file_buffer->name) {
+                       g_unlink (file_buffer->name);
+                       g_free (file_buffer->name);
+               }
+               g_free (file_buffer->start);
+       }
+}
+
+static
+bool
+gc_heap_dump_mem_file_buffer_write_all (
+       int fd,
+       const uint8_t *buffer,
+       size_t len)
+{
+       // Called on GC thread (during GC) while holding GC locks,
+       // before/during/after STW so no need to MONO_ENTER_GC_SAFE/MONO_EXIT_GC_SAFE
+       // around async safe IO functions.
+
+       size_t offset = 0;
+       int nwritten;
+
+       do {
+               nwritten = g_write (fd, buffer + offset, GSIZE_TO_UINT32 (len - offset));
+               if (nwritten > 0)
+                       offset += nwritten;
+       } while ((nwritten > 0 && offset < len) || (nwritten == -1 && errno == EINTR));
+
+       return nwritten == len;
+}
+
+static
+bool
+gc_heap_dump_mem_file_buffer_flush (GCHeapDumpMemFileBuffer *file_buffer)
+{
+       EP_ASSERT (file_buffer);
+       EP_ASSERT (file_buffer->fd != -1);
+       EP_ASSERT (file_buffer->start);
+
+       bool result = true;
+       uint64_t size = (uint64_t)(file_buffer->current - file_buffer->start);
+
+       result &= gc_heap_dump_mem_file_buffer_write_all (file_buffer->fd, (const uint8_t *)&size, sizeof (size));
+       result &= gc_heap_dump_mem_file_buffer_write_all (file_buffer->fd, file_buffer->start, GUINT64_TO_SIZE (size));
+
+       file_buffer->current = file_buffer->start;
+
+       return result;
+}
+
+#ifndef g_lseek
+#ifdef G_OS_WIN32
+#define g_lseek _lseek
+#else
+#define g_lseek lseek
+#endif
+#endif
+
+static
+bool
+gc_heap_dump_mem_file_buffer_reset_func (void *context)
+{
+       // Called on GC thread (during GC) while holding GC locks,
+       // but after STW so no need to MONO_ENTER_GC_SAFE/MONO_EXIT_GC_SAFE
+       // around async safe IO functions.
+
+       EP_ASSERT (context);
+
+       bool result = true;
+       GCHeapDumpMemFileBuffer *file_buffer = (GCHeapDumpMemFileBuffer *)context;
+
+       EP_ASSERT (file_buffer->fd != -1);
+
+       result &= gc_heap_dump_mem_file_buffer_flush (file_buffer);
+       result &= g_lseek (file_buffer->fd, 0, SEEK_SET) != -1;
+
+       return result;
+}
+
+static
+uint8_t *
+gc_heap_dump_mem_file_buffer_alloc_func (
+       void *context,
+       size_t size)
+{
+       EP_ASSERT (context);
+
+       GCHeapDumpMemFileBuffer *file_buffer = (GCHeapDumpMemFileBuffer *)context;
+
+       if (size > MAX_EVENT_BYTE_COUNT)
+               return NULL;
+
+       if (file_buffer->current + size >= file_buffer->end)
+               if (!gc_heap_dump_mem_file_buffer_flush (file_buffer))
+                       return NULL;
+
+       uint8_t *result = file_buffer->current;
+       file_buffer->current = file_buffer->current + size;
+       return result;
+}
+
+static
+bool
+gc_heap_dump_mem_file_buffer_read (
+       int fd,
+       uint8_t *buffer,
+       size_t len)
+{
+       // Called on GC thread (during GC) while holding GC locks,
+       // but after STW so no need to MONO_ENTER_GC_SAFE/MONO_EXIT_GC_SAFE
+       // around async safe IO functions.
+
+       size_t offset = 0;
+       int nread;
+
+       do {
+               nread = g_read (fd, buffer + offset, GSIZE_TO_UINT32 (len - offset));
+               if (nread > 0)
+                       offset += nread;
+       } while ((nread > 0 && offset < len) || (nread == -1 && errno == EINTR));
+
+       return nread == len;
+}
+
+static
+const uint8_t *
+gc_heap_dump_mem_file_buffer_get_next_buffer_func (
+       void *context,
+       size_t *next_buffer_size)
+{
+       EP_ASSERT (context);
+
+       GCHeapDumpMemFileBuffer *file_buffer = (GCHeapDumpMemFileBuffer *)context;
+
+       bool result = false;
+
+       uint64_t max_size = (uint64_t)(file_buffer->end - file_buffer->start);
+       uint64_t size = 0;
+
+       EP_ASSERT (file_buffer->fd != -1);
+
+       if (gc_heap_dump_mem_file_buffer_read (file_buffer->fd, (uint8_t *)&size, sizeof (size)))
+               if (size <= max_size)
+                       result = gc_heap_dump_mem_file_buffer_read (file_buffer->fd, file_buffer->start, GUINT64_TO_SIZE (size));
+
+       file_buffer->current = file_buffer->start;
+       *next_buffer_size = GUINT64_TO_SIZE (size);
+
+       return result ? file_buffer->start : NULL;
+}
+
+static
+GCHeapDumpBuffer *
+gc_heap_dump_context_buffer_alloc (void)
+{
+       GCHeapDumpMemFileBuffer *file_buffer = g_new0 (GCHeapDumpMemFileBuffer, 1);
+       GCHeapDumpBuffer *buffer = g_new0 (GCHeapDumpBuffer, 1);
+
+       buffer->context = file_buffer;
+       buffer->reset_func = gc_heap_dump_mem_file_buffer_reset_func;
+       buffer->alloc_func = gc_heap_dump_mem_file_buffer_alloc_func;
+       buffer->get_next_buffer_func = gc_heap_dump_mem_file_buffer_get_next_buffer_func;
+
+       if (!gc_heap_dump_mem_file_buffer_init (file_buffer)) {
+               gc_heap_dump_mem_file_buffer_fini (file_buffer);
+               buffer = NULL;
+       }
+
+       return buffer;
+}
+
+static
+void
+gc_heap_dump_context_buffer_free (GCHeapDumpBuffer *buffer)
+{
+       if (!buffer)
+               return;
+
+       gc_heap_dump_mem_file_buffer_fini ((GCHeapDumpMemFileBuffer *)buffer->context);
+
+       g_free (buffer->context);
+       g_free (buffer);
+}
+
+static
+bool
+gc_heap_dump_context_alloc_bulk_data (
+       GCHeapDumpBulkData *data,
+       size_t len,
+       size_t count)
+{
+       data->data_start = g_malloc (len);
+       data->data_current = data->data_start;
+       data->data_end = data->data_start + len;
+       data->max_count = GSIZE_TO_UINT32 (count);
+       data->index = 0;
+       data->count = 0;
+
+       return data->data_start;
+}
+
+static
+void
+gc_heap_dump_context_free_bulk_data (GCHeapDumpBulkData *data)
+{
+       g_free (data->data_start);
+}
+
+static
+void
+gc_heap_dump_context_clear_bulk_data (GCHeapDumpBulkData *data)
+{
+       if (data->data_start)
+               memset (data->data_start, 0, data->data_end - data->data_start);
+       data->data_current = data->data_start;
+       data->count = 0;
+}
+
+static
+bool
+gc_heap_dump_context_init (
+       GCHeapDumpContext *context,
+       EVENTPIPE_TRACE_CONTEXT trace_context,
+       uint32_t gc_reason,
+       uint32_t gc_type,
+       uint32_t gc_count,
+       uint32_t gc_depth)
+{
+       EP_ASSERT (context);
+
+       bool result = true;
+
+       context->trace_context = trace_context;
+       context->gc_reason = gc_reason;
+       context->gc_type = gc_type;
+       context->gc_count = gc_count;
+       context->gc_depth = gc_depth;
+       context->retry_count = 0;
+       context->state = GC_HEAP_DUMP_CONTEXT_STATE_INIT;
+
+       if (is_gc_heap_dump_enabled (context)) {
+               context->bulk_type_logger = bulk_type_event_logger_alloc ();
+
+               context->buffer = gc_heap_dump_context_buffer_alloc ();
+
+               const size_t bulk_nodes_max_data_len = (MAX_EVENT_BYTE_COUNT - 0x100);
+               const size_t bulk_nodes_max_count = bulk_nodes_max_data_len / BULK_NODE_EVENT_TYPE_SIZE;
+
+               const size_t bulk_edges_max_data_len = (MAX_EVENT_BYTE_COUNT - 0x100);
+               const size_t bulk_edges_max_count = bulk_edges_max_data_len / BULK_EDGE_EVENT_TYPE_SIZE;
+
+               const size_t bulk_root_edges_max_data_len = (MAX_EVENT_BYTE_COUNT - 0x100);
+               const size_t bulk_root_edges_max_count = bulk_root_edges_max_data_len / BULK_ROOT_EDGE_EVENT_TYPE_SIZE;
+
+               const size_t bulk_root_cwt_elem_edges_max_data_len = (MAX_EVENT_BYTE_COUNT - 0x100);
+               const size_t bulk_root_cwt_elem_edges_max_count = bulk_root_cwt_elem_edges_max_data_len / BULK_ROOT_CWT_ELEM_EDGE_EVENT_TYPE_SIZE;
+
+               const size_t bulk_root_static_vars_max_data_len = (MAX_EVENT_BYTE_COUNT - 0x30);
+               const size_t bulk_root_static_vars_max_count = bulk_root_static_vars_max_data_len / BULK_ROOT_STATIC_VAR_EVENT_TYPE_SIZE;
+
+               gc_heap_dump_context_alloc_bulk_data (&context->bulk_nodes, bulk_nodes_max_data_len, bulk_nodes_max_count);
+               gc_heap_dump_context_alloc_bulk_data (&context->bulk_edges, bulk_edges_max_data_len, bulk_edges_max_count);
+               gc_heap_dump_context_alloc_bulk_data (&context->bulk_root_edges, bulk_root_edges_max_data_len, bulk_root_edges_max_count);
+               gc_heap_dump_context_alloc_bulk_data (&context->bulk_root_cwt_elem_edges, bulk_root_cwt_elem_edges_max_data_len, bulk_root_cwt_elem_edges_max_count);
+               gc_heap_dump_context_alloc_bulk_data (&context->bulk_root_static_vars, bulk_root_static_vars_max_data_len, bulk_root_static_vars_max_count);
+
+               result = context->bulk_type_logger &&
+                       context->buffer &&
+                       context->bulk_nodes.data_start &&
+                       context->bulk_edges.data_start &&
+                       context->bulk_root_edges.data_start &&
+                       context->bulk_root_cwt_elem_edges.data_start &&
+                       context->bulk_root_static_vars.data_start;
+       }
+
+       return result;
+}
+
+static
+void
+gc_heap_dump_context_fini (GCHeapDumpContext *context)
+{
+       if (context) {
+               if (is_gc_heap_dump_enabled (context)) {
+                       if (context->gc_roots)
+                               dn_vector_ptr_free (context->gc_roots);
+
+                       gc_heap_dump_context_free_bulk_data (&context->bulk_root_static_vars);
+                       gc_heap_dump_context_free_bulk_data (&context->bulk_root_cwt_elem_edges);
+                       gc_heap_dump_context_free_bulk_data (&context->bulk_root_edges);
+                       gc_heap_dump_context_free_bulk_data (&context->bulk_edges);
+                       gc_heap_dump_context_free_bulk_data (&context->bulk_nodes);
+
+                       gc_heap_dump_context_buffer_free (context->buffer);
+
+                       if (context->bulk_type_logger)
+                               bulk_type_event_logger_free (context->bulk_type_logger);
+               }
+
+               memset (context, 0, sizeof (GCHeapDumpContext));
+       }
+}
+
+static
+GCHeapDumpContext *
+gc_heap_dump_context_alloc (
+       EVENTPIPE_TRACE_CONTEXT trace_context,
+       uint32_t gc_reason,
+       uint32_t gc_type,
+       uint32_t gc_count,
+       uint32_t gc_depth)
+{
+       GCHeapDumpContext *context = g_new0 (GCHeapDumpContext, 1);
+       gc_heap_dump_context_init (
+               context,
+               trace_context,
+               gc_reason,
+               gc_type,
+               gc_count,
+               gc_depth);
+
+       return context;
+}
+
+static
+void
+gc_heap_dump_context_free (GCHeapDumpContext *context)
+{
+       gc_heap_dump_context_fini (context);
+       g_free (context);
+}
+
+static
+GCHeapDumpContext *
+gc_heap_dump_context_get (void)
+{
+       EventPipeMonoThreadData *thread_data = ep_rt_mono_thread_data_get_or_create ();
+       return thread_data ? thread_data->gc_heap_dump_context : NULL;
+}
+
+static
+void
+gc_heap_dump_context_set (GCHeapDumpContext *context)
+{
+       EventPipeMonoThreadData *thread_data = ep_rt_mono_thread_data_get_or_create ();
+       if (thread_data) {
+               if (thread_data->gc_heap_dump_context)
+                       gc_heap_dump_context_free (thread_data->gc_heap_dump_context);
+               thread_data->gc_heap_dump_context = context;
+       }
+}
+
+static
+void
+gc_heap_dump_context_reset (void)
+{
+       gc_heap_dump_context_set (NULL);
+}
+
+static
+int32_t
+gc_roots_sort_compare_func (
+       const void *a,
+       const void *b)
+{
+       EP_ASSERT (a && b);
+
+       GCRootData *root_a = *(GCRootData **)a;
+       GCRootData *root_b = *(GCRootData **)b;
+
+       EP_ASSERT (root_a && root_b);
+       if (root_a->start == root_b->start)
+               return 0;
+       return (root_a->start > root_b->start) ? 1 : -1;
+}
+
+static
+void
+gc_heap_dump_context_build_roots (GCHeapDumpContext *context)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       ep_rt_spin_lock_requires_lock_not_held (&_gc_lock);
+
+       EP_SPIN_LOCK_ENTER (&_gc_lock, section1)
+               if (!context->gc_roots) {
+                       dn_vector_ptr_custom_alloc_params_t params = { 0, };
+                       params.capacity = dn_umap_size (&_gc_roots_table);
+                       context->gc_roots = dn_vector_ptr_custom_alloc (&params);
+
+               } else {
+                       dn_vector_ptr_clear (context->gc_roots);
+               }
+
+               DN_UMAP_FOREACH_BEGIN (const mono_byte *, key, GCRootData *, value, &_gc_roots_table) {
+                       DN_UNREFERENCED_PARAMETER (key);
+                       dn_vector_ptr_push_back (context->gc_roots, value);
+               } DN_UMAP_FOREACH_END;
+       EP_SPIN_LOCK_EXIT (&_gc_lock, section1)
+
+       dn_vector_ptr_sort (context->gc_roots, gc_roots_sort_compare_func);
+
+ep_on_exit:
+       ep_rt_spin_lock_requires_lock_not_held (&_gc_lock);
+       return;
+
+ep_on_error:
+       ep_exit_error_handler ();
+}
+
+static
+GCRootData *
+gc_heap_dump_context_find_root (
+       GCHeapDumpContext *context,
+       uintptr_t root)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       const uint8_t *base = (const uint8_t *)dn_vector_ptr_data (context->gc_roots);
+       const uint8_t *p;
+       size_t lim;
+       int32_t cmp;
+       for (lim = dn_vector_ptr_size (context->gc_roots); lim; lim >>= 1) {
+               p = base + ((lim >> 1) * dn_vector_ptr_element_size);
+
+               GCRootData *gc_root_data = *(GCRootData **)p;
+               EP_ASSERT (gc_root_data);
+
+               if (gc_root_data->start <= root && gc_root_data->end > root)
+                       cmp = 0;
+               else
+                       cmp = (root > gc_root_data->start) ? 1 : -1;
+
+               if (!cmp)
+                       return *(GCRootData **)p;
+               else if (cmp > 0) {
+                       base = p + dn_vector_ptr_element_size;
+                       lim--;
+               }
+       }
+
+       return NULL;
+}
+
+static
+void
+gc_heap_dump_context_clear_nodes (GCHeapDumpContext *context)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+       gc_heap_dump_context_clear_bulk_data (&context->bulk_nodes);
+}
+
+static
+void
+gc_heap_dump_context_clear_edges (GCHeapDumpContext *context)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+       gc_heap_dump_context_clear_bulk_data (&context->bulk_edges);
+}
+
+static
+void
+gc_heap_dump_context_clear_root_edges (GCHeapDumpContext *context)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+       gc_heap_dump_context_clear_bulk_data (&context->bulk_root_edges);
+}
+
+static
+void
+gc_heap_dump_context_clear_root_cwt_elem_edges (GCHeapDumpContext *context)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+       gc_heap_dump_context_clear_bulk_data (&context->bulk_root_cwt_elem_edges);
+}
+
+static
+void
+gc_heap_dump_context_clear_root_static_vars (GCHeapDumpContext *context)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+       gc_heap_dump_context_clear_bulk_data (&context->bulk_root_static_vars);
+}
+
+static
+void
+flush_gc_event_bulk_nodes (GCHeapDumpContext *context)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       if (!context->bulk_nodes.count)
+               return;
+
+       FireEtwGCBulkNode (
+               context->bulk_nodes.index,
+               context->bulk_nodes.count,
+               clr_instance_get_id (),
+               BULK_NODE_EVENT_TYPE_SIZE,
+               context->bulk_nodes.data_start,
+               NULL,
+               NULL);
+
+       context->bulk_nodes.index++;
+       gc_heap_dump_context_clear_nodes (context);
+}
+
+static
+void
+fire_gc_event_bulk_node (
+       GCHeapDumpContext *context,
+       uintptr_t address,
+       uint64_t size,
+       uintptr_t type,
+       uint64_t edge_count)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       bool update_previous_bulk_node = (size == 0 && context->bulk_nodes.count != 0);
+
+       if (update_previous_bulk_node)
+               context->bulk_nodes.count--;
+
+       if (context->bulk_nodes.count == context->bulk_nodes.max_count)
+               flush_gc_event_bulk_nodes (context);
+
+       // Mono profiler object reference callback might split bulk node
+       // into several calls if it contains more edges than internal buffer size.
+       // Mono profiler pass an object size of 0 to identify this case.
+       if (update_previous_bulk_node) {
+               context->bulk_nodes.data_current -= sizeof (edge_count);
+               uint64_t previous_edge_count;
+               memcpy (&previous_edge_count, context->bulk_nodes.data_current, sizeof (edge_count));
+               edge_count = GUINT64_FROM_LE (previous_edge_count) + edge_count;
+               ep_write_buffer_uint64_t (&context->bulk_nodes.data_current, edge_count);
+       } else {
+               uint64_t type_id = type;
+               MonoVTable *vtable = (MonoVTable *)type;
+               if (vtable && vtable->klass) {
+                       MonoType *klass_type = m_class_get_byval_arg (vtable->klass);
+                       bulk_type_log_type_and_parameters_if_necessary (context->bulk_type_logger, klass_type, TYPE_LOG_BEHAVIOR_IF_FIRST_TIME);
+                       type_id = get_typeid_for_type (klass_type);
+               }
+
+               // NOTE, must match manifest GCBulkNode values type.
+               ep_write_buffer_uintptr_t (&context->bulk_nodes.data_current, address);
+               ep_write_buffer_uint64_t (&context->bulk_nodes.data_current, size);
+               ep_write_buffer_uint64_t (&context->bulk_nodes.data_current, type_id);
+               ep_write_buffer_uint64_t (&context->bulk_nodes.data_current, edge_count);
+       }
+
+       context->bulk_nodes.count++;
+}
+
+static
+void
+flush_gc_event_bulk_edges (GCHeapDumpContext *context)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       if (!context->bulk_edges.count)
+               return;
+
+       FireEtwGCBulkEdge (
+               context->bulk_edges.index,
+               context->bulk_edges.count,
+               clr_instance_get_id (),
+               BULK_EDGE_EVENT_TYPE_SIZE,
+               context->bulk_edges.data_start,
+               NULL,
+               NULL);
+
+       context->bulk_edges.index++;
+       gc_heap_dump_context_clear_edges (context);
+}
+
+static
+void
+fire_gc_event_bulk_edge (
+       GCHeapDumpContext *context,
+       uintptr_t address,
+       uint32_t ref_field_id)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       if (context->bulk_edges.count == context->bulk_edges.max_count)
+               flush_gc_event_bulk_edges (context);
+
+       // NOTE, must match manifest GCBulkEdge values type.
+       ep_write_buffer_uintptr_t (&context->bulk_edges.data_current, address);
+       ep_write_buffer_uint32_t (&context->bulk_edges.data_current, ref_field_id);
+
+       context->bulk_edges.count++;
+}
+
+static
+void
+fire_gc_event_object_reference (
+       GCHeapDumpContext *context,
+       const uint8_t *data,
+       uint32_t payload_size)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       uintptr_t object_address;
+       uintptr_t object_type;
+       uint64_t object_size;
+       uint64_t edge_count;
+
+       EP_ASSERT (data + sizeof (object_address) <= data + payload_size);
+       memcpy (&object_address, data, sizeof (object_address));
+       data += sizeof (object_address);
+
+       EP_ASSERT (data + sizeof (object_size) <= data + payload_size);
+       memcpy (&object_size, data, sizeof (object_size));
+       data += sizeof (object_size);
+
+       EP_ASSERT (data + sizeof (object_type) <= data + payload_size);
+       memcpy (&object_type, data, sizeof (object_type));
+       data += sizeof (object_type);
+
+       EP_ASSERT (data + sizeof (edge_count) <= data + payload_size);
+       memcpy (&edge_count, data, sizeof (edge_count));
+       data += sizeof (edge_count);
+
+       fire_gc_event_bulk_node (
+               context,
+               object_address,
+               object_size,
+               object_type,
+               edge_count);
+
+       EP_ASSERT (data + (edge_count * sizeof (object_address)) <= data + payload_size);
+       for (uint32_t i = 0; i < edge_count; i++) {
+               memcpy (&object_address, data, sizeof (object_address));
+               data += sizeof (object_address);
+
+               fire_gc_event_bulk_edge (
+                       context,
+                       object_address,
+                       0);
+       }
+}
+
+static
+int
+buffer_gc_event_object_reference_callback (
+       MonoObject *obj,
+       MonoClass *klass,
+       uintptr_t size,
+       uintptr_t num,
+       MonoObject **refs,
+       uintptr_t *offsets,
+       void *data)
+{
+       if (!data)
+               return 1;
+
+       GCHeapDumpContext *context = (GCHeapDumpContext *)data;
+
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       uintptr_t object_address = (uintptr_t)SGEN_POINTER_UNTAG_ALL (obj);
+       uintptr_t object_type = (uintptr_t)SGEN_POINTER_UNTAG_ALL (mono_object_get_vtable_internal (obj));
+       uint64_t object_size = (uint64_t)size;
+       uint64_t edge_count = (uint64_t)num;
+
+       /* account for object alignment */
+       object_size += 7;
+       object_size &= ~7;
+
+       BufferedGCEvent gc_event_data;
+       gc_event_data.type = BUFFERED_GC_EVENT_OBJECT_REF;
+       gc_event_data.payload_size =
+               sizeof (object_address) +
+               sizeof (object_size) +
+               sizeof (object_type) +
+               sizeof (edge_count) +
+               (edge_count * sizeof (uintptr_t));
+
+       EP_ASSERT (context->buffer);
+       EP_ASSERT (context->buffer->context);
+
+       uint8_t *buffer = context->buffer->alloc_func (context->buffer->context, sizeof (gc_event_data) + gc_event_data.payload_size);
+       if (buffer) {
+               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
+               buffer += sizeof (gc_event_data);
+
+               memcpy (buffer, &object_address, sizeof (object_address));
+               buffer += sizeof (object_address);
+
+               memcpy (buffer, &object_size, sizeof (object_size));
+               buffer += sizeof (object_size);
+
+               memcpy (buffer, &object_type, sizeof (object_type));
+               buffer += sizeof (object_type);
+
+               memcpy (buffer, &edge_count, sizeof (edge_count));
+               buffer += sizeof (edge_count);
+
+               for (uint64_t i = 0; i < edge_count; i++) {
+                       object_address = (uintptr_t)SGEN_POINTER_UNTAG_ALL (refs [i]);
+                       memcpy (buffer, &object_address, sizeof (object_address));
+                       buffer += sizeof (object_address);
+               }
+       }
+
+       return 0;
+}
+
+static
+void
+flush_gc_event_bulk_root_static_vars (GCHeapDumpContext *context)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       if (!context->bulk_root_static_vars.count)
+               return;
+
+       FireEtwGCBulkRootStaticVar (
+               context->bulk_root_static_vars.count,
+               (uint64_t)mono_get_root_domain (),
+               clr_instance_get_id (),
+               context->bulk_root_static_vars.data_current - context->bulk_root_static_vars.data_start,
+               context->bulk_root_static_vars.data_start,
+               NULL,
+               NULL);
+
+       context->bulk_root_static_vars.index++;
+       gc_heap_dump_context_clear_root_static_vars (context);
+}
+
+static
+void
+fire_gc_event_bulk_root_static_var (
+       GCHeapDumpContext *context,
+       GCRootData *root_data,
+       uintptr_t address,
+       uintptr_t object)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+       EP_ASSERT (root_data);
+       EP_ASSERT (root_data->source == MONO_ROOT_SOURCE_STATIC);
+
+       MonoVTable *vtable = (MonoVTable *)(root_data->key);
+       uint32_t static_var_flags = 0;
+       uint64_t type_id = (uint64_t)vtable;
+       const ep_char8_t *static_var_name = "?";
+
+       if (vtable && vtable->klass) {
+               ERROR_DECL (error);
+               gpointer iter = NULL;
+               MonoClassField *field;
+               uint32_t offset = GPTRDIFF_TO_UINT32 (address - root_data->start);
+               while ((field = mono_class_get_fields_internal (vtable->klass, &iter))) {
+                       if (mono_field_get_flags (field) & FIELD_ATTRIBUTE_LITERAL)
+                               continue;
+                       if (!(mono_field_get_flags (field) & FIELD_ATTRIBUTE_STATIC))
+                               continue;
+                       if (mono_field_is_deleted (field) || m_field_is_from_update (field))
+                               continue;
+
+                       if (mono_field_get_offset (field) == offset) {
+                               static_var_name = mono_field_get_name (field);
+                               break;
+                       }
+               }
+               if (!is_ok (error))
+                       mono_error_cleanup (error);
+               error_init_reuse (error);
+       }
+
+       size_t name_len = static_var_name && static_var_name [0] != '\0'
+               ? strlen (static_var_name)
+               : 0;
+
+       size_t event_size = BULK_ROOT_STATIC_VAR_EVENT_TYPE_SIZE + ((name_len +1) * sizeof (ep_char16_t));
+
+       if (context->bulk_root_static_vars.data_end <=  context->bulk_root_static_vars.data_current + event_size)
+               flush_gc_event_bulk_root_static_vars (context);
+
+       if (context->bulk_root_static_vars.data_end <=  context->bulk_root_static_vars.data_current + event_size)
+               return;
+
+       if (vtable && vtable->klass) {
+               MonoType *klass_type = m_class_get_byval_arg (vtable->klass);
+               bulk_type_log_type_and_parameters_if_necessary (context->bulk_type_logger, klass_type, TYPE_LOG_BEHAVIOR_IF_FIRST_TIME);
+               type_id = get_typeid_for_type (klass_type);
+       }
+
+       // NOTE, needs to match manifest GCBulkRootStaticVar values type.
+       ep_write_buffer_uint64_t (&context->bulk_root_static_vars.data_current, (uint64_t)address);
+       ep_write_buffer_uint64_t (&context->bulk_root_static_vars.data_current, (uint64_t)object);
+       ep_write_buffer_uint64_t (&context->bulk_root_static_vars.data_current, type_id);
+       ep_write_buffer_uint32_t (&context->bulk_root_static_vars.data_current, static_var_flags);
+       write_buffer_string_utf8_to_utf16_t (&context->bulk_root_static_vars.data_current, static_var_name, GSIZE_TO_UINT32 (name_len));
+
+       context->bulk_root_static_vars.count++;
+}
+
+static
+void
+flush_gc_event_bulk_root_edges (GCHeapDumpContext *context)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       if (!context->bulk_root_edges.count)
+               return;
+
+       FireEtwGCBulkRootEdge (
+               context->bulk_root_edges.index,
+               context->bulk_root_edges.count,
+               clr_instance_get_id (),
+               BULK_ROOT_EDGE_EVENT_TYPE_SIZE,
+               context->bulk_root_edges.data_start,
+               NULL,
+               NULL);
+
+       context->bulk_root_edges.index++;
+       gc_heap_dump_context_clear_root_edges (context);
+}
+
+static
+void
+flush_gc_event_bulk_root_cwt_elem_edges (GCHeapDumpContext *context)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       if (!context->bulk_root_cwt_elem_edges.count)
+               return;
+
+       FireEtwGCBulkRootConditionalWeakTableElementEdge (
+               context->bulk_root_cwt_elem_edges.index,
+               context->bulk_root_cwt_elem_edges.count,
+               clr_instance_get_id (),
+               BULK_ROOT_CWT_ELEM_EDGE_EVENT_TYPE_SIZE,
+               context->bulk_root_cwt_elem_edges.data_start,
+               NULL,
+               NULL);
+
+       context->bulk_root_cwt_elem_edges.index++;
+       gc_heap_dump_context_clear_root_cwt_elem_edges (context);
+}
+
+static
+void
+fire_gc_event_bulk_root_cwt_elem_edge (
+       GCHeapDumpContext *context,
+       uintptr_t address,
+       uintptr_t key,
+       uintptr_t value)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       if (context->bulk_root_cwt_elem_edges.count == context->bulk_root_cwt_elem_edges.max_count)
+               flush_gc_event_bulk_root_cwt_elem_edges (context);
+
+       // NOTE, must match manifest GCBulkRootConditionalWeakTableElementEdge values type.
+       ep_write_buffer_uintptr_t (&context->bulk_root_cwt_elem_edges.data_current, key);
+       ep_write_buffer_uintptr_t (&context->bulk_root_cwt_elem_edges.data_current, value);
+       ep_write_buffer_uintptr_t (&context->bulk_root_cwt_elem_edges.data_current, address);
+
+       context->bulk_root_cwt_elem_edges.count++;
+}
+
+static
+void
+fire_gc_event_bulk_root_edge (
+       GCHeapDumpContext *context,
+       uintptr_t address,
+       uintptr_t object)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       if (context->bulk_root_edges.count == context->bulk_root_edges.max_count)
+               flush_gc_event_bulk_root_edges (context);
+
+       uint8_t root_kind = GC_ROOT_KIND_OTHER;
+       uint32_t root_flags = GC_ROOT_FLAGS_NONE;
+       uintptr_t root_id = 0;
+
+       GCRootData *gc_root = gc_heap_dump_context_find_root (context, address);
+       if (gc_root) {
+               if (gc_root->source == MONO_ROOT_SOURCE_STATIC) {
+                       fire_gc_event_bulk_root_static_var (
+                               context,
+                               gc_root,
+                               address,
+                               object);
+                       return;
+               }
+
+               if (gc_root->source == MONO_ROOT_SOURCE_EPHEMERON) {
+                       // Should be ephemeron key, but current profiler
+                       // API won't report it and key is only validated
+                       // to be none 0 and a aligned pointer by gcdump.
+                       // Use object as key until we get key reported
+                       // in gc_roots profiler callback.
+                       uintptr_t key = object;
+                       uintptr_t value = object;
+                       fire_gc_event_bulk_root_cwt_elem_edge (
+                               context,
+                               root_id,
+                               key,
+                               value);
+                       return;
+               }
+
+               switch (gc_root->source) {
+               case MONO_ROOT_SOURCE_STACK :
+                       root_kind = GC_ROOT_KIND_STACK;
+                       root_id = address;
+                       break;
+               case MONO_ROOT_SOURCE_FINALIZER_QUEUE :
+                       root_kind = GC_ROOT_KIND_FINALIZER;
+                       break;
+               case MONO_ROOT_SOURCE_THREAD_STATIC :
+                       root_kind = GC_ROOT_KIND_HANDLE;
+                       root_id = address;
+                       break;
+               case MONO_ROOT_SOURCE_GC_HANDLE :
+                       root_kind = GC_ROOT_KIND_HANDLE;
+                       root_flags = GPOINTER_TO_INT (gc_root->key) != 0 ? GC_ROOT_FLAGS_PINNING : GC_ROOT_FLAGS_NONE;
+                       root_id = address;
+                       break;
+               case MONO_ROOT_SOURCE_HANDLE :
+                       root_kind = GC_ROOT_KIND_HANDLE;
+                       root_id = address;
+                       break;
+               default :
+                       break;
+               }
+       }
+
+       // NOTE, needs to match manifest GCBulkRootEdge values type.
+       ep_write_buffer_uintptr_t (&context->bulk_root_edges.data_current, object);
+       ep_write_buffer_uint8_t (&context->bulk_root_edges.data_current, root_kind);
+       ep_write_buffer_uint32_t (&context->bulk_root_edges.data_current, root_flags);
+       ep_write_buffer_uintptr_t (&context->bulk_root_edges.data_current, root_id);
+
+       context->bulk_root_edges.count++;
+}
+
+static
+void
+fire_gc_event_roots (
+       GCHeapDumpContext *context,
+       const uint8_t *data,
+       uint32_t payload_size)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       uint64_t count;
+       uintptr_t address;
+       uintptr_t object;
+
+       EP_ASSERT (data + sizeof (count) <= data + payload_size);
+       memcpy (&count, data, sizeof (count));
+       data += sizeof (count);
+
+       EP_ASSERT (data + (count * (sizeof (address) + sizeof (object))) <= data + payload_size);
+       for (uint32_t i = 0; i < count; i++) {
+               memcpy (&address, data, sizeof (address));
+               data += sizeof (address);
+
+               memcpy (&object, data, sizeof (object));
+               data += sizeof (object);
+
+               fire_gc_event_bulk_root_edge (
+                       context,
+                       address,
+                       object);
+       }
+}
+
+static
+void
+buffer_gc_event_roots_callback (
+       MonoProfiler *prof,
+       uint64_t count,
+       const mono_byte *const * addresses,
+       MonoObject *const * objects)
+{
+       GCHeapDumpContext *context = gc_heap_dump_context_get ();
+       if (!context)
+               return;
+
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       BufferedGCEvent gc_event_data;
+       gc_event_data.type = BUFFERED_GC_EVENT_ROOTS;
+       gc_event_data.payload_size =
+               (uint32_t)(sizeof (count) +
+               (count * (sizeof (uintptr_t) + sizeof (uintptr_t) + sizeof (uintptr_t))));
+
+       EP_ASSERT (context->buffer);
+       EP_ASSERT (context->buffer->context);
+
+       uint8_t *buffer = context->buffer->alloc_func (context->buffer->context, sizeof (gc_event_data) + gc_event_data.payload_size);
+       if (buffer) {
+               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
+               buffer += sizeof (gc_event_data);
+
+               memcpy (buffer, &count, sizeof (count));
+               buffer += sizeof (count);
+
+               for (uint64_t i = 0; i < count; i++) {
+                       uintptr_t address = (uintptr_t)addresses [i];
+                       uintptr_t object = (uintptr_t)SGEN_POINTER_UNTAG_ALL (objects [i]);
+
+                       memcpy (buffer, &address, sizeof (address));
+                       buffer += sizeof (address);
+
+                       memcpy (buffer, &object, sizeof (object));
+                       buffer += sizeof (object);
+               }
+       }
+}
+
+static
+void
+flush_gc_events (GCHeapDumpContext *context)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       flush_gc_event_bulk_nodes (context);
+       flush_gc_event_bulk_edges (context);
+       flush_gc_event_bulk_root_edges (context);
+       flush_gc_event_bulk_root_cwt_elem_edges (context);
+       flush_gc_event_bulk_root_static_vars (context);
+
+       if (context->bulk_type_logger && is_keyword_and_level_enabled (&context->trace_context, EP_EVENT_LEVEL_INFORMATIONAL, TYPE_KEYWORD))
+               bulk_type_fire_bulk_type_event (context->bulk_type_logger);
+}
+
+static
+void
+fire_buffered_gc_events (GCHeapDumpContext *context)
+{
+       EP_ASSERT (is_gc_heap_dump_enabled (context));
+       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+
+       if (context->buffer) {
+               const uint8_t *buffer = NULL;
+               const uint8_t *buffer_end = NULL;
+               size_t size = 0;
+
+               context->buffer->reset_func (context->buffer->context);
+
+               while ((buffer = context->buffer->get_next_buffer_func (context->buffer->context, &size))) {
+                       buffer_end = buffer + size;
+                       while (buffer < buffer_end) {
+                               if (buffer + sizeof (BufferedGCEvent) > buffer_end)
+                                       break;
+
+                               BufferedGCEvent *gc_event = (BufferedGCEvent *)buffer;
+                               buffer += sizeof (BufferedGCEvent);
+
+                               if (buffer + gc_event->payload_size > buffer_end)
+                                       break;
+
+                               switch (gc_event->type) {
+                               case BUFFERED_GC_EVENT_OBJECT_REF :
+                                       fire_gc_event_object_reference (context, buffer, gc_event->payload_size);
+                                       break;
+                               case BUFFERED_GC_EVENT_ROOTS :
+                                       fire_gc_event_roots (context, buffer, gc_event->payload_size);
+                                       break;
+                               default:
+                                       EP_ASSERT (!"Unknown buffered GC event type.");
+                               }
+
+                               buffer += gc_event->payload_size;
+                       }
+               }
+
+               flush_gc_events (context);
+       }
+}
+
+static
+void
+calculate_live_keywords (
+       uint64_t *live_keywords,
+       bool *trigger_heap_dump)
+{
+       uint64_t keywords[] = { GC_HEAP_COLLECT_KEYWORD };
+       uint64_t count[] = { 0 };
+
+       ep_requires_lock_held ();
+
+       EP_ASSERT (G_N_ELEMENTS (keywords) == G_N_ELEMENTS (count));
+       *live_keywords = ep_rt_mono_session_calculate_and_count_all_keywords (
+               ep_config_get_public_provider_name_utf8 (),
+               keywords,
+               count,
+               G_N_ELEMENTS (count));
+
+       *trigger_heap_dump = ep_rt_mono_is_runtime_initialized ();
+       *trigger_heap_dump &= is_keword_enabled (*live_keywords, GC_KEYWORD);
+       *trigger_heap_dump &= is_keword_enabled (*live_keywords, GC_HEAP_COLLECT_KEYWORD);
+       *trigger_heap_dump &= count [0] > _gc_heap_dump_trigger_count;
+
+       _gc_heap_dump_trigger_count = count [0];
+
+       ep_requires_lock_held ();
+}
+
+static
+void
+gc_event_callback (
+       MonoProfiler *prof,
+       MonoProfilerGCEvent gc_event,
+       uint32_t generation,
+       mono_bool serial)
+{
+       switch (gc_event) {
+       case MONO_GC_EVENT_POST_STOP_WORLD:
+       {
+               GCHeapDumpContext *context = gc_heap_dump_context_get ();
+               if (is_gc_heap_dump_enabled (context)) {
+                       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+                       mono_profiler_set_gc_roots_callback (_ep_rt_mono_default_profiler_provider, buffer_gc_event_roots_callback);
+               }
+               break;
+       }
+       case MONO_GC_EVENT_PRE_START_WORLD:
+       {
+               GCHeapDumpContext *context = gc_heap_dump_context_get ();
+               if (is_gc_heap_dump_enabled (context)) {
+                       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+                       mono_gc_walk_heap (0, buffer_gc_event_object_reference_callback, context);
+                       mono_profiler_set_gc_roots_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               }
+               break;
+       }
+       case MONO_GC_EVENT_POST_START_WORLD:
+       {
+               GCHeapDumpContext *context = gc_heap_dump_context_get ();
+               if (is_gc_heap_dump_enabled (context)) {
+                       EP_ASSERT (context->state == GC_HEAP_DUMP_CONTEXT_STATE_DUMP);
+                       gc_heap_dump_context_build_roots (context);
+                       fire_buffered_gc_events (context);
+               }
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+static
+void
+gc_heap_dump_trigger_callback (MonoProfiler *prof)
+{
+       bool notify_finalizer = false;
+       GCHeapDumpContext *heap_dump_context = gc_heap_dump_context_get ();
+
+       if (!heap_dump_context && gc_heap_dump_requested ()) {
+               EP_LOCK_ENTER (section1)
+                       if (gc_heap_dump_requested ()) {
+                               EVENTPIPE_TRACE_CONTEXT context = RUNTIME_PROVIDER_CONTEXT;
+                               if (!dn_vector_empty (&_gc_heap_dump_requests_data)) {
+                                       context = *dn_vector_back_t (&_gc_heap_dump_requests_data, EVENTPIPE_TRACE_CONTEXT);
+                                       dn_vector_pop_back (&_gc_heap_dump_requests_data);
+                               }
+                               gc_heap_dump_requests_dec ();
+
+                               uint32_t gc_count = gc_heap_dump_count_inc ();
+                               uint32_t gc_depth = mono_gc_max_generation () + 1;
+                               uint32_t gc_reason = GC_REASON_INDUCED;
+                               uint32_t gc_type = GC_TYPE_NGC;
+
+                               heap_dump_context =
+                                       gc_heap_dump_context_alloc (
+                                               context,
+                                               gc_reason,
+                                               gc_type,
+                                               gc_count,
+                                               gc_depth);
+
+                               gc_heap_dump_context_set (heap_dump_context);
+                       }
+               EP_LOCK_EXIT (section1)
+       }
+
+       if (heap_dump_context) {
+               switch (heap_dump_context->state) {
+               case GC_HEAP_DUMP_CONTEXT_STATE_INIT :
+               {
+                       bool all_started = false;
+                       EP_LOCK_ENTER (section2)
+                               all_started = ep_rt_mono_sesion_has_all_started ();
+                       EP_LOCK_EXIT (section2)
+
+                       if (!all_started && heap_dump_context->retry_count < 5) {
+                               heap_dump_context->retry_count++;
+                               notify_finalizer = true;
+                               break;
+                       }
+
+                       heap_dump_context->state = GC_HEAP_DUMP_CONTEXT_STATE_START;
+                       // Fallthrough
+               }
+               case GC_HEAP_DUMP_CONTEXT_STATE_START :
+               {
+                       FireEtwGCStart_V2 (
+                               heap_dump_context->gc_count,
+                               heap_dump_context->gc_depth,
+                               heap_dump_context->gc_reason,
+                               heap_dump_context->gc_type,
+                               clr_instance_get_id (),
+                               0,
+                               NULL,
+                               NULL);
+
+                       heap_dump_context->state = GC_HEAP_DUMP_CONTEXT_STATE_DUMP;
+                       notify_finalizer = true;
+                       break;
+               }
+               case GC_HEAP_DUMP_CONTEXT_STATE_DUMP :
+               {
+                       bool gc_dump = true;
+                       gc_dump &= EventPipeEventEnabledGCBulkNode ();
+                       gc_dump &= EventPipeEventEnabledGCBulkEdge ();
+                       gc_dump &= EventPipeEventEnabledGCBulkRootEdge ();
+                       gc_dump &= EventPipeEventEnabledGCBulkRootStaticVar ();
+
+                       if (gc_dump) {
+                               mono_profiler_set_gc_event_callback (_ep_rt_mono_default_profiler_provider, gc_event_callback);
+                               mono_gc_collect (mono_gc_max_generation ());
+                               mono_profiler_set_gc_event_callback (_ep_rt_mono_default_profiler_provider, NULL);
+                       }
+
+                       heap_dump_context->state = GC_HEAP_DUMP_CONTEXT_STATE_END;
+                       notify_finalizer = true;
+                       break;
+               }
+               case GC_HEAP_DUMP_CONTEXT_STATE_END :
+               {
+                       FireEtwGCEnd_V1 (
+                               heap_dump_context->gc_count,
+                               heap_dump_context->gc_depth,
+                               clr_instance_get_id (),
+                               NULL,
+                               NULL);
+
+                       gc_heap_dump_context_reset ();
+                       heap_dump_context = NULL;
+                       break;
+               }
+               default :
+                       g_assert_not_reached ();
+               }
+       }
+
+       if (!heap_dump_context) {
+               EP_LOCK_ENTER (section3)
+                       bool gc_enabled = is_keword_enabled(RUNTIME_PROVIDER_CONTEXT.EnabledKeywordsBitmask, GC_KEYWORD);
+                       bool gc_dump_enabled = is_keword_enabled(RUNTIME_PROVIDER_CONTEXT.EnabledKeywordsBitmask, GC_HEAP_COLLECT_KEYWORD);
+                       if (!(gc_enabled && gc_dump_enabled))
+                               mono_profiler_set_gc_finalized_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               EP_LOCK_EXIT (section3)
+       }
+
+       if (notify_finalizer) {
+               ep_rt_thread_sleep (200 * NUM_NANOSECONDS_IN_1_MS);
+               mono_gc_finalize_notify ();
+       }
+
+ep_on_exit:
+       ep_rt_config_requires_lock_not_held ();
+       return;
+
+ep_on_error:
+       ep_exit_error_handler ();
+}
+
+void
+EventPipeEtwCallbackDotNETRuntime (
+       const uint8_t *source_id,
+       unsigned long is_enabled,
+       uint8_t level,
+       uint64_t match_any_keywords,
+       uint64_t match_all_keywords,
+       EventFilterDescriptor *filter_data,
+       void *callback_data)
+{
+       ep_rt_config_requires_lock_not_held ();
+
+       EP_ASSERT (_ep_rt_mono_default_profiler_provider != NULL);
+
+       EP_LOCK_ENTER (section1)
+               uint64_t live_keywords = 0;
+               bool trigger_heap_dump = false;
+               calculate_live_keywords (&live_keywords, &trigger_heap_dump);
+
+               if (is_keword_enabled(live_keywords, JIT_KEYWORD)) {
+                       mono_profiler_set_jit_begin_callback (_ep_rt_mono_default_profiler_provider, jit_begin_callback);
+                       mono_profiler_set_jit_failed_callback (_ep_rt_mono_default_profiler_provider, jit_failed_callback);
+                       mono_profiler_set_jit_done_callback (_ep_rt_mono_default_profiler_provider, jit_done_callback);
+               } else {
+                       mono_profiler_set_jit_begin_callback (_ep_rt_mono_default_profiler_provider, NULL);
+                       mono_profiler_set_jit_failed_callback (_ep_rt_mono_default_profiler_provider, NULL);
+                       mono_profiler_set_jit_done_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled(live_keywords, LOADER_KEYWORD)) {
+                       mono_profiler_set_image_loaded_callback (_ep_rt_mono_default_profiler_provider, image_loaded_callback);
+                       mono_profiler_set_image_unloaded_callback (_ep_rt_mono_default_profiler_provider, image_unloaded_callback);
+                       mono_profiler_set_assembly_loaded_callback (_ep_rt_mono_default_profiler_provider, assembly_loaded_callback);
+                       mono_profiler_set_assembly_unloaded_callback (_ep_rt_mono_default_profiler_provider, assembly_unloaded_callback);
+               } else {
+                       mono_profiler_set_image_loaded_callback (_ep_rt_mono_default_profiler_provider, NULL);
+                       mono_profiler_set_image_unloaded_callback (_ep_rt_mono_default_profiler_provider, NULL);
+                       mono_profiler_set_assembly_loaded_callback (_ep_rt_mono_default_profiler_provider, NULL);
+                       mono_profiler_set_assembly_unloaded_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled(live_keywords, TYPE_DIAGNOSTIC_KEYWORD)) {
+                       mono_profiler_set_class_loading_callback (_ep_rt_mono_default_profiler_provider, class_loading_callback);
+                       mono_profiler_set_class_failed_callback (_ep_rt_mono_default_profiler_provider, class_failed_callback);
+                       mono_profiler_set_class_loaded_callback (_ep_rt_mono_default_profiler_provider, class_loaded_callback);
+               } else {
+                       mono_profiler_set_class_loading_callback (_ep_rt_mono_default_profiler_provider, NULL);
+                       mono_profiler_set_class_failed_callback (_ep_rt_mono_default_profiler_provider, NULL);
+                       mono_profiler_set_class_loaded_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled(live_keywords, EXCEPTION_KEYWORD)) {
+                       mono_profiler_set_exception_throw_callback (_ep_rt_mono_default_profiler_provider, exception_throw_callback);
+                       mono_profiler_set_exception_clause_callback (_ep_rt_mono_default_profiler_provider, exception_clause_callback);
+               } else {
+                       mono_profiler_set_exception_throw_callback (_ep_rt_mono_default_profiler_provider, NULL);
+                       mono_profiler_set_exception_clause_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               }
+
+               if (is_keword_enabled(live_keywords, CONTENTION_KEYWORD)) {
+                       mono_profiler_set_monitor_contention_callback (_ep_rt_mono_default_profiler_provider, monitor_contention_callback);
+                       mono_profiler_set_monitor_acquired_callback (_ep_rt_mono_default_profiler_provider, monitor_acquired_callback);
+                       mono_profiler_set_monitor_failed_callback (_ep_rt_mono_default_profiler_provider, monitor_failed_callback);
+               } else {
+                       mono_profiler_set_monitor_contention_callback (_ep_rt_mono_default_profiler_provider, NULL);
+                       mono_profiler_set_monitor_acquired_callback (_ep_rt_mono_default_profiler_provider, NULL);
+                       mono_profiler_set_monitor_failed_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               }
+
+               // Disabled in gc_heap_dump_trigger_callback when no longer needed.
+               if (is_keword_enabled(live_keywords, GC_KEYWORD) && is_keword_enabled(live_keywords, GC_HEAP_COLLECT_KEYWORD))
+                       mono_profiler_set_gc_finalized_callback (_ep_rt_mono_default_profiler_provider, gc_heap_dump_trigger_callback);
+
+               RUNTIME_PROVIDER_CONTEXT.Level = level;
+               RUNTIME_PROVIDER_CONTEXT.EnabledKeywordsBitmask = live_keywords;
+               RUNTIME_PROVIDER_CONTEXT.IsEnabled = (live_keywords != 0 ? true : false);
+
+               if (trigger_heap_dump) {
+                       EP_ASSERT (ep_rt_mono_is_runtime_initialized ());
+                       dn_vector_push_back (&_gc_heap_dump_requests_data, RUNTIME_PROVIDER_CONTEXT);
+                       gc_heap_dump_requests_inc ();
+                       mono_gc_finalize_notify ();
+               }
+       EP_LOCK_EXIT (section1)
+
+ep_on_exit:
+       ep_rt_config_requires_lock_not_held ();
+       return;
+
+ep_on_error:
+       ep_exit_error_handler ();
+}
+
+static
+GCRootData *
+gc_root_data_alloc (
+       uintptr_t start,
+       uintptr_t size,
+       MonoGCRootSource source,
+       const void *key,
+       const char *name)
+{
+       GCRootData *root_data = g_new0 (GCRootData, 1);
+       root_data->start = start;
+       root_data->end = start + size;
+       root_data->key = key;
+       //root_data->name = g_strdup (name);
+       root_data->source = source;
+       return root_data;
+}
+
+static
+void
+gc_root_data_free (void *data)
+{
+       GCRootData *root_data = (GCRootData *)data;
+       if (root_data) {
+               g_free (root_data->name);
+               g_free (root_data);
+       }
+}
+
+static
+void
+gc_root_register_callback (
+       MonoProfiler *prof,
+       const mono_byte *start,
+       uintptr_t size,
+       MonoGCRootSource source,
+       const void *key,
+       const char *name)
+{
+       ep_rt_spin_lock_requires_lock_not_held (&_gc_lock);
+
+       GCRootData *root_data = gc_root_data_alloc ((uintptr_t)start, size, source, key, name);
+       EP_SPIN_LOCK_ENTER (&_gc_lock, section1)
+               dn_umap_insert_or_assign (&_gc_roots_table, (void *)start, root_data);
+       EP_SPIN_LOCK_EXIT (&_gc_lock, section1)
+
+ep_on_exit:
+       ep_rt_spin_lock_requires_lock_not_held (&_gc_lock);
+       return;
+
+ep_on_error:
+       ep_exit_error_handler ();
+}
+
+static
+void
+gc_root_unregister_callback (
+       MonoProfiler *prof,
+       const mono_byte *start)
+{
+       ep_rt_spin_lock_requires_lock_not_held (&_gc_lock);
+
+       GCRootData *root_data = NULL;
+       EP_SPIN_LOCK_ENTER (&_gc_lock, section1)
+               dn_umap_extract_key (&_gc_roots_table, start, NULL, (void **)&root_data);
+       EP_SPIN_LOCK_EXIT (&_gc_lock, section1)
+
+       g_free (root_data);
+
+ep_on_exit:
+       ep_rt_spin_lock_requires_lock_not_held (&_gc_lock);
+       return;
+
+ep_on_error:
+       ep_exit_error_handler ();
+}
+
+void
+ep_rt_mono_runtime_provider_component_init (void)
+{
+       ep_rt_spin_lock_alloc (&_gc_lock);
+
+       dn_umap_custom_init_params_t params = {0,};
+       params.value_dispose_func = gc_root_data_free;
+
+       dn_umap_custom_init (&_gc_roots_table, &params);
+
+       dn_vector_init_t (&_gc_heap_dump_requests_data, EVENTPIPE_TRACE_CONTEXT);
+
+       EP_ASSERT (_ep_rt_mono_default_profiler_provider != NULL);
+       mono_profiler_set_gc_root_register_callback (_ep_rt_mono_default_profiler_provider, gc_root_register_callback);
+       mono_profiler_set_gc_root_unregister_callback (_ep_rt_mono_default_profiler_provider, gc_root_unregister_callback);
+}
+
+void
+ep_rt_mono_runtime_provider_init (void)
+{
+       MonoMethodSignature *method_signature = mono_metadata_signature_alloc (mono_get_corlib (), 1);
+       if (method_signature) {
+               method_signature->params[0] = m_class_get_byval_arg (mono_get_object_class());
+               method_signature->ret = m_class_get_byval_arg (mono_get_void_class());
+
+               ERROR_DECL (error);
+               MonoClass *runtime_helpers = mono_class_from_name_checked (mono_get_corlib (), "System.Runtime.CompilerServices", "RuntimeHelpers", error);
+               if (is_ok (error) && runtime_helpers) {
+                       MonoMethodBuilder *method_builder = mono_mb_new (runtime_helpers, "CompileMethod", MONO_WRAPPER_RUNTIME_INVOKE);
+                       if (method_builder) {
+                               _runtime_helper_compile_method = mono_mb_create_method (method_builder, method_signature, 1);
+                               mono_mb_free (method_builder);
+                       }
+               }
+               mono_error_cleanup (error);
+               mono_metadata_free_method_signature (method_signature);
+
+               if (_runtime_helper_compile_method) {
+                       _runtime_helper_compile_method_jitinfo = (MonoJitInfo *)g_new0 (MonoJitInfo, 1);
+                       if (_runtime_helper_compile_method) {
+                               _runtime_helper_compile_method_jitinfo->code_start = MINI_FTNPTR_TO_ADDR (_runtime_helper_compile_method);
+                               _runtime_helper_compile_method_jitinfo->code_size = 20;
+                               _runtime_helper_compile_method_jitinfo->d.method = _runtime_helper_compile_method;
+                       }
+               }
+       }
+
+       {
+               ERROR_DECL (error);
+               MonoMethodDesc *desc = NULL;
+               MonoClass *monitor = mono_class_from_name_checked (mono_get_corlib (), "System.Threading", "Monitor", error);
+               if (is_ok (error) && monitor) {
+                       desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE);
+                       if (desc) {
+                               _monitor_enter_v4_method = mono_method_desc_search_in_class (desc, monitor);
+                               mono_method_desc_free (desc);
+
+                               if (_monitor_enter_v4_method) {
+                                       _monitor_enter_v4_method_jitinfo = (MonoJitInfo *)g_new0 (MonoJitInfo, 1);
+                                       if (_monitor_enter_v4_method_jitinfo) {
+                                               _monitor_enter_v4_method_jitinfo->code_start = MINI_FTNPTR_TO_ADDR (_monitor_enter_v4_method);
+                                               _monitor_enter_v4_method_jitinfo->code_size = 20;
+                                               _monitor_enter_v4_method_jitinfo->d.method = _monitor_enter_v4_method;
+                                       }
+                               }
+                       }
+
+                       desc = mono_method_desc_new ("Monitor:Enter(object)", FALSE);
+                       if (desc) {
+                               _monitor_enter_method = mono_method_desc_search_in_class (desc, monitor);
+                               mono_method_desc_free (desc);
+
+                               if (_monitor_enter_method ) {
+                                       _monitor_enter_method_jitinfo = (MonoJitInfo *)g_new0 (MonoJitInfo, 1);
+                                       if (_monitor_enter_method_jitinfo) {
+                                               _monitor_enter_method_jitinfo->code_start = MINI_FTNPTR_TO_ADDR (_monitor_enter_method);
+                                               _monitor_enter_method_jitinfo->code_size = 20;
+                                               _monitor_enter_method_jitinfo->d.method = _monitor_enter_method;
+                                       }
+                               }
+                       }
+               }
+               mono_error_cleanup (error);
+       }
+}
+
+void
+ep_rt_mono_runtime_provider_fini (void)
+{
+       if (_sampled_thread_callstacks)
+               g_array_free (_sampled_thread_callstacks, TRUE);
+       _sampled_thread_callstacks = NULL;
+
+       _max_sampled_thread_count = 32;
+
+       g_free (_runtime_helper_compile_method_jitinfo);
+       _runtime_helper_compile_method_jitinfo = NULL;
+
+       if (_runtime_helper_compile_method)
+               mono_free_method (_runtime_helper_compile_method);
+       _runtime_helper_compile_method = NULL;
+
+       g_free (_monitor_enter_method_jitinfo);
+       _monitor_enter_method_jitinfo = NULL;
+       _monitor_enter_method = NULL;
+
+       g_free (_monitor_enter_v4_method_jitinfo);
+       _monitor_enter_v4_method_jitinfo = NULL;
+       _monitor_enter_v4_method = NULL;
+
+       if (_ep_rt_mono_default_profiler_provider) {
+               mono_profiler_set_jit_begin_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_jit_failed_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_jit_done_callback (_ep_rt_mono_default_profiler_provider, NULL);
+
+               mono_profiler_set_image_loaded_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_image_unloaded_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_assembly_loaded_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_assembly_unloaded_callback (_ep_rt_mono_default_profiler_provider, NULL);
+
+               mono_profiler_set_class_loading_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_class_failed_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_class_loaded_callback (_ep_rt_mono_default_profiler_provider, NULL);
+
+               mono_profiler_set_exception_throw_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_exception_clause_callback (_ep_rt_mono_default_profiler_provider, NULL);
+
+               mono_profiler_set_monitor_contention_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_monitor_acquired_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_monitor_failed_callback (_ep_rt_mono_default_profiler_provider, NULL);
+
+               mono_profiler_set_gc_root_register_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_gc_root_unregister_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_gc_finalized_callback (_ep_rt_mono_default_profiler_provider, NULL);
+       }
+
+       _gc_heap_dump_requests = 0;
+       _gc_heap_dump_count = 0;
+       _gc_heap_dump_trigger_count = 0;
+
+       dn_vector_dispose (&_gc_heap_dump_requests_data);
+       memset (&_gc_heap_dump_requests_data, 0, sizeof (_gc_heap_dump_requests_data));
+
+       dn_umap_dispose (&_gc_roots_table);
+       memset (&_gc_roots_table, 0, sizeof (_gc_roots_table));
+
+       ep_rt_spin_lock_free (&_gc_lock);
+}
+
+void
+ep_rt_mono_runtime_provider_thread_started_callback (
+       MonoProfiler *prof,
+       uintptr_t tid)
+{
+       thread_started_callback (prof, tid);
+}
+
+void
+ep_rt_mono_runtime_provider_thread_stopped_callback (
+       MonoProfiler *prof,
+       uintptr_t tid)
+{
+       thread_stopped_callback (prof, tid);
+}
+
+#endif /* ENABLE_PERFTRACING */
+
+MONO_EMPTY_SOURCE_FILE(eventpipe_rt_mono_runtime_provider);
index 0fcfa9d..5a54cd9 100644 (file)
@@ -5,43 +5,32 @@
 #include <eventpipe/ep-types.h>
 #include <eventpipe/ep-rt.h>
 #include <eventpipe/ep.h>
-#include <eventpipe/ep-event.h>
+#include <eventpipe/ep-session.h>
 
-#include <eglib/gmodule.h>
 #include <mono/utils/mono-lazy-init.h>
 #include <mono/utils/mono-time.h>
-#include <mono/utils/mono-proclib.h>
 #include <mono/utils/mono-threads.h>
 #include <mono/utils/mono-rand.h>
 #include <mono/metadata/profiler.h>
-#include <mono/metadata/appdomain.h>
-#include <mono/metadata/assembly.h>
-#include <mono/metadata/assembly-internals.h>
-#include <mono/metadata/class-internals.h>
-#include <mono/metadata/debug-internals.h>
-#include <mono/metadata/gc-internals.h>
-#include <mono/metadata/profiler-private.h>
-#include <mono/metadata/cil-coff.h>
-#include <mono/metadata/mono-endian.h>
 #include <mono/mini/mini-runtime.h>
-#include <mono/sgen/sgen-conf.h>
-#include <mono/sgen/sgen-tagged-pointer.h>
-#include <mono/utils/mono-logger-internals.h>
 #include <minipal/getexepath.h>
 #include <runtime_version.h>
 #include <clretwallmain.h>
 
 extern void InitProvidersAndEvents (void);
 
-// EventPipe rt init state.
-gboolean _ep_rt_mono_initialized;
+// EventPipe init state.
+static gboolean _eventpipe_initialized;
+
+// Runtime init state.
+gboolean _ep_rt_mono_runtime_initialized;
 
 // EventPipe TLS key.
 MonoNativeTlsKey _ep_rt_mono_thread_holder_tls_id;
-MonoNativeTlsKey _ep_rt_mono_thread_data_tls_id;
+static MonoNativeTlsKey _thread_data_tls_id;
 
 // Random byte provider.
-gpointer _ep_rt_mono_rand_provider;
+static gpointer _rand_provider;
 
 // EventPipe global config lock.
 ep_rt_spin_lock_handle_t _ep_rt_mono_config_lock = {0};
@@ -54,7439 +43,860 @@ char *_ep_rt_mono_os_cmd_line = NULL;
 mono_lazy_init_t _ep_rt_mono_managed_cmd_line_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
 char *_ep_rt_mono_managed_cmd_line = NULL;
 
-// Custom Mono EventPipe thread data.
-typedef struct _EventPipeThreadData EventPipeThreadData;
-struct _EventPipeThreadData {
-       bool prevent_profiler_event_recursion;
-};
-
-// Sample profiler.
-static GArray * _ep_rt_mono_sampled_thread_callstacks = NULL;
-static uint32_t _ep_rt_mono_max_sampled_thread_count = 32;
-
-// Mono profilers.
-static MonoProfilerHandle _ep_rt_default_profiler = NULL;
-static MonoProfilerHandle _ep_rt_dotnet_runtime_profiler_provider = NULL;
-static MonoProfilerHandle _ep_rt_dotnet_mono_profiler_provider = NULL;
-static MonoProfilerHandle _ep_rt_dotnet_mono_profiler_heap_collect_provider = NULL;
-static MonoCallSpec _ep_rt_dotnet_mono_profiler_provider_callspec = {0};
-
-// Phantom JIT compile method.
-MonoMethod *_ep_rt_mono_runtime_helper_compile_method = NULL;
-MonoJitInfo *_ep_rt_mono_runtime_helper_compile_method_jitinfo = NULL;
+// Mono profilers (shared with runtime provider).
+MonoProfilerHandle _ep_rt_mono_default_profiler_provider = NULL;
 
-// Monitor.Enter methods.
-MonoMethod *_ep_rt_mono_monitor_enter_method = NULL;
-MonoJitInfo *_ep_rt_mono_monitor_enter_method_jitinfo = NULL;
+// Providers
+EVENTPIPE_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context = {0};
+EVENTPIPE_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context = {0};
+EVENTPIPE_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context = {0};
+EVENTPIPE_TRACE_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_DOTNET_Context = {0};
+EVENTPIPE_TRACE_CONTEXT MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_DOTNET_Context = {0};
 
-MonoMethod *_ep_rt_mono_monitor_enter_v4_method = NULL;
-MonoJitInfo *_ep_rt_mono_monitor_enter_v4_method_jitinfo = NULL;
+#define RUNTIME_PROVIDER_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context
+#define RUNTIME_PRIVATE_PROVIDER_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context
+#define RUNTIME_RUNDOWN_PROVIDER_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context
+#define RUNTIME_STRESS_PROVIDER_CONTEXT MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_DOTNET_Context
+#define RUNTIME_MONO_PROFILER_PROVIDER_CONTEXT MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_DOTNET_Context
 
-// Rundown types.
-typedef
 bool
-(*ep_rt_mono_fire_method_rundown_events_func)(
-       const uint64_t method_id,
-       const uint64_t module_id,
-       const uint64_t method_start_address,
-       const uint32_t method_size,
-       const uint32_t method_token,
-       const uint32_t method_flags,
-       const ep_char8_t *method_namespace,
-       const ep_char8_t *method_name,
-       const ep_char8_t *method_signature,
-       const uint16_t count_of_map_entries,
-       const uint32_t *il_offsets,
-       const uint32_t *native_offsets,
-       bool aot_method,
-       bool verbose,
-       void *user_data);
-
-typedef
-bool
-(*ep_rt_mono_fire_assembly_rundown_events_func)(
-       const uint64_t domain_id,
-       const uint64_t assembly_id,
-       const uint32_t assembly_flags,
-       const uint32_t binding_id,
-       const ep_char8_t *assembly_name,
-       const uint64_t module_id,
-       const uint32_t module_flags,
-       const uint32_t reserved_flags,
-       const ep_char8_t *module_il_path,
-       const ep_char8_t *module_native_path,
-       const uint8_t *managed_pdb_signature,
-       const uint32_t managed_pdb_age,
-       const ep_char8_t *managed_pdb_build_path,
-       const uint8_t *native_pdb_signature,
-       const uint32_t native_pdb_age,
-       const ep_char8_t *native_pdb_build_path,
-       void *user_data);
-
-typedef
-bool
-(*ep_rt_mono_fire_domain_rundown_events_func)(
-       const uint64_t domain_id,
-       const uint32_t domain_flags,
-       const ep_char8_t *domain_name,
-       const uint32_t domain_index,
-       void *user_data);
-
-typedef struct _EventPipeFireMethodEventsData {
-       MonoDomain *domain;
-       uint8_t *buffer;
-       size_t buffer_size;
-       ep_rt_mono_fire_method_rundown_events_func method_events_func;
-} EventPipeFireMethodEventsData;
-
-typedef struct _EventPipeStackWalkData {
-       EventPipeStackContents *stack_contents;
-       bool top_frame;
-       bool async_frame;
-       bool safe_point_frame;
-       bool runtime_invoke_frame;
-} EventPipeStackWalkData;
-
-typedef struct _EventPipeSampleProfileStackWalkData {
-       EventPipeStackWalkData stack_walk_data;
-       EventPipeStackContents stack_contents;
-       uint64_t thread_id;
-       uintptr_t thread_ip;
-       uint32_t payload_data;
-} EventPipeSampleProfileStackWalkData;
-
-// Rundown flags.
-#define RUNTIME_SKU_MONO 0x4
-#define METHOD_FLAGS_DYNAMIC_METHOD 0x1
-#define METHOD_FLAGS_GENERIC_METHOD 0x2
-#define METHOD_FLAGS_SHARED_GENERIC_METHOD 0x4
-#define METHOD_FLAGS_JITTED_METHOD 0x8
-#define METHOD_FLAGS_JITTED_HELPER_METHOD 0x10
-#define METHOD_FLAGS_EXTENT_HOT_SECTION 0x00000000
-#define METHOD_FLAGS_EXTENT_COLD_SECTION 0x10000000
-
-#define MODULE_FLAGS_NATIVE_MODULE 0x2
-#define MODULE_FLAGS_DYNAMIC_MODULE 0x4
-#define MODULE_FLAGS_MANIFEST_MODULE 0x8
-
-#define ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY 0x2
-#define ASSEMBLY_FLAGS_NATIVE_ASSEMBLY 0x4
-#define ASSEMBLY_FLAGS_COLLECTIBLE_ASSEMBLY 0x8
-
-#define DOMAIN_FLAGS_DEFAULT_DOMAIN 0x1
-#define DOMAIN_FLAGS_EXECUTABLE_DOMAIN 0x2
-
-// Event data types.
-struct _ModuleEventData {
-       uint8_t module_il_pdb_signature [EP_GUID_SIZE];
-       uint8_t module_native_pdb_signature [EP_GUID_SIZE];
-       uint64_t domain_id;
-       uint64_t module_id;
-       uint64_t assembly_id;
-       const char *module_il_path;
-       const char *module_il_pdb_path;
-       const char *module_native_path;
-       const char *module_native_pdb_path;
-       uint32_t module_il_pdb_age;
-       uint32_t module_native_pdb_age;
-       uint32_t reserved_flags;
-       uint32_t module_flags;
-};
-
-typedef struct _ModuleEventData ModuleEventData;
-
-struct _AssemblyEventData {
-       uint64_t domain_id;
-       uint64_t assembly_id;
-       uint64_t binding_id;
-       char *assembly_name;
-       uint32_t assembly_flags;
-};
-
-typedef struct _AssemblyEventData AssemblyEventData;
-
-// Event flags.
-#define THREAD_FLAGS_GC_SPECIAL 0x00000001
-#define THREAD_FLAGS_FINALIZER 0x00000002
-#define THREAD_FLAGS_THREADPOOL_WORKER 0x00000004
-
-#define EXCEPTION_THROWN_FLAGS_HAS_INNER 0x1
-#define EXCEPTION_THROWN_FLAGS_IS_NESTED 0x2
-#define EXCEPTION_THROWN_FLAGS_IS_RETHROWN 0x4
-#define EXCEPTION_THROWN_FLAGS_IS_CSE 0x8
-#define EXCEPTION_THROWN_FLAGS_IS_CLS_COMPLIANT 0x10
-
-// Provider keyword flags.
-#define GC_KEYWORD 0x1
-#define GC_HANDLE_KEYWORD 0x2
-#define LOADER_KEYWORD 0x8
-#define JIT_KEYWORD 0x10
-#define APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD 0x800
-#define CONTENTION_KEYWORD 0x4000
-#define EXCEPTION_KEYWORD 0x8000
-#define THREADING_KEYWORD 0x10000
-#define GC_HEAP_DUMP_KEYWORD 0x100000
-#define GC_ALLOCATION_KEYWORD 0x200000
-#define GC_MOVES_KEYWORD 0x400000
-#define GC_HEAP_COLLECT_KEYWORD 0x800000
-#define GC_FINALIZATION_KEYWORD 0x1000000
-#define GC_RESIZE_KEYWORD 0x2000000
-#define GC_ROOT_KEYWORD 0x4000000
-#define GC_HEAP_DUMP_VTABLE_CLASS_REF_KEYWORD 0x8000000
-#define METHOD_TRACING_KEYWORD 0x20000000
-#define TYPE_DIAGNOSTIC_KEYWORD 0x8000000000
-#define TYPE_LOADING_KEYWORD 0x8000000000
-#define MONITOR_KEYWORD 0x10000000000
-#define METHOD_INSTRUMENTATION_KEYWORD 0x40000000000
-
-// MonoProfiler types.
-typedef enum {
-       MONO_PROFILER_BUFFERED_GC_EVENT = 1,
-       MONO_PROFILER_BUFFERED_GC_EVENT_RESIZE = 2,
-       MONO_PROFILER_BUFFERED_GC_EVENT_ROOTS = 3,
-       MONO_PROFILER_BUFFERED_GC_EVENT_MOVES = 4,
-       MONO_PROFILER_BUFFERED_GC_EVENT_OBJECT_REF = 5,
-       MONO_PROFILER_BUFFERED_GC_EVENT_ROOT_REGISTER = 6,
-       MONO_PROFILER_BUFFERED_GC_EVENT_ROOT_UNREGISTER = 7
-} MonoProfilerBufferedGCEventType;
-
-typedef struct _MonoProfilerBufferedGCEvent MonoProfilerBufferedGCEvent;
-struct _MonoProfilerBufferedGCEvent {
-       MonoProfilerBufferedGCEventType type;
-       uint32_t payload_size;
-};
-
-#define MONO_PROFILER_MEM_DEFAULT_BLOCK_SIZE (mono_pagesize() * 16)
-#define MONO_PROFILER_MEM_BLOCK_SIZE_INC (mono_pagesize())
-
-typedef struct _MonoProfilerMemBlock MonoProfilerMemBlock;
-struct _MonoProfilerMemBlock {
-       MonoProfilerMemBlock *next;
-       MonoProfilerMemBlock *prev;
-       uint8_t *start;
-       uint32_t alloc_size;
-       uint32_t size;
-       uint32_t offset;
-       uint32_t last_used_offset;
-};
-
-// MonoProfiler GC dump.
-static volatile MonoProfilerMemBlock *_ep_rt_mono_profiler_mem_blocks = NULL;
-static volatile MonoProfilerMemBlock *_ep_rt_mono_profiler_current_mem_block = NULL;
-static volatile uint32_t _ep_rt_mono_profiler_gc_heap_collect_requests = 0;
-static volatile uint32_t _ep_rt_mono_profiler_gc_heap_collect_in_progress = 0;
-static bool _ep_rt_mono_profiler_gc_can_collect_heap = false;
-
-static GSList *_ep_rt_mono_profiler_provider_params = NULL;
-static GQueue *_ep_rt_mono_profiler_gc_heap_collect_request_params = NULL;
-
-// Lightweight atomic "exclusive/shared" lock, prevents new fire events to happend while GC is in progress and gives GC ability to wait until all pending fire events are done
-// before progressing. State uint32_t is split into two uint16_t, upper uint16_t represent gc in progress state, taken when GC starts, preventing new fire events to execute and lower
-// uint16_t keeps number of fire events in flight, (gc_in_progress << 16) | (fire_event_count & 0xFFFF). Spin lock is only taken on slow path to queue up pending shared requests
-// while GC is in progress and should very rarely be needed.
-typedef uint32_t mono_profiler_gc_state_t;
-typedef uint16_t mono_profiler_gc_state_count_t;
-
-#define MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT(x) ((mono_profiler_gc_state_count_t)((x & 0xFFFF)))
-#define MONO_PROFILER_GC_STATE_INC_FIRE_EVENT_COUNT(x) ((mono_profiler_gc_state_t)((mono_profiler_gc_state_t)(x & 0xFFFF0000) | (mono_profiler_gc_state_t)(MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT(x) + 1)))
-#define MONO_PROFILER_GC_STATE_DEC_FIRE_EVENT_COUNT(x) ((mono_profiler_gc_state_t)((mono_profiler_gc_state_t)(x & 0xFFFF0000) | (mono_profiler_gc_state_t)(MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT(x) - 1)))
-#define MONO_PROFILER_GC_STATE_GC_IN_PROGRESS_START(x) ((mono_profiler_gc_state_t)((mono_profiler_gc_state_t)(0xFFFF << 16) | (mono_profiler_gc_state_t)MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT(x)))
-#define MONO_PROFILER_GC_STATE_IS_GC_IN_PROGRESS(x) (((x >> 16) & 0xFFFF) == 0xFFFF)
-#define MONO_PROFILER_GC_STATE_GC_IN_PROGRESS_STOP(x) ((mono_profiler_gc_state_t)((mono_profiler_gc_state_t)MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT(x)))
-
-static volatile mono_profiler_gc_state_t _ep_rt_mono_profiler_gc_state = 0;
-static ep_rt_spin_lock_handle_t _ep_rt_mono_profiler_gc_state_lock = {0};
-
-/*
- * Forward declares of all static functions.
- */
-
-static
-EventPipeThreadData *
-eventpipe_thread_data_get_or_create (void);
+ep_rt_mono_rand_try_get_bytes (
+       uint8_t *buffer,
+       size_t buffer_size)
+{
+       EP_ASSERT (_rand_provider != NULL);
 
-static
-void
-eventpipe_thread_data_free (EventPipeThreadData *thread_data);
+       ERROR_DECL (error);
+       return mono_rand_try_get_bytes (&_rand_provider, (guchar *)buffer, (gssize)buffer_size, error);
+}
 
-static
-bool
-fire_method_rundown_events_func (
-       const uint64_t method_id,
-       const uint64_t module_id,
-       const uint64_t method_start_address,
-       const uint32_t method_size,
-       const uint32_t method_token,
-       const uint32_t method_flags,
-       const ep_char8_t *method_namespace,
-       const ep_char8_t *method_name,
-       const ep_char8_t *method_signature,
-       const uint16_t count_of_map_entries,
-       const uint32_t *il_offsets,
-       const uint32_t *native_offsets,
-       bool aot_method,
-       bool verbose,
-       void *user_data);
+char *
+ep_rt_mono_get_managed_cmd_line (void)
+{
+       return mono_runtime_get_managed_cmd_line ();
+}
 
-static
-bool
-fire_assembly_rundown_events_func (
-       const uint64_t domain_id,
-       const uint64_t assembly_id,
-       const uint32_t assembly_flags,
-       const uint32_t binding_id,
-       const ep_char8_t *assembly_name,
-       const uint64_t module_id,
-       const uint32_t module_flags,
-       const uint32_t reserved_flags,
-       const ep_char8_t *module_il_path,
-       const ep_char8_t *module_native_path,
-       const uint8_t *managed_pdb_signature,
-       const uint32_t managed_pdb_age,
-       const ep_char8_t *managed_pdb_build_path,
-       const uint8_t *native_pdb_signature,
-       const uint32_t native_pdb_age,
-       const ep_char8_t *native_pdb_build_path,
-       void *user_data);
+char *
+ep_rt_mono_get_os_cmd_line (void)
+{
+       MONO_REQ_GC_NEUTRAL_MODE;
 
-static
-bool
-fire_domain_rundown_events_func (
-       const uint64_t domain_id,
-       const uint32_t domain_flags,
-       const ep_char8_t *domain_name,
-       const uint32_t domain_index,
-       void *user_data);
+       // we only return the native host here since getting the full commandline is complicated and
+       // it's not super important to have the correct value since it'll only be used during startup
+       // until we have the managed commandline
+       char *host_path = minipal_getexepath ();
 
-static
-void
-eventpipe_fire_method_events (
-       MonoJitInfo *ji,
-       MonoMethod *method,
-       EventPipeFireMethodEventsData *events_data);
+       // minipal_getexepath doesn't use Mono APIs to allocate strings so
+       // we can't use g_free (which the callers of this method expect to do)
+       // so create another copy and return that one
+       char *res = g_strdup (host_path);
+       free (host_path);
+       return res;
+}
 
-static
-void
-eventpipe_fire_method_events_func (
-       MonoJitInfo *ji,
-       void *user_data);
+#ifdef HOST_WIN32
 
-static
-void
-eventpipe_fire_assembly_events (
-       MonoDomain *domain,
-       MonoAssembly *assembly,
-       ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func);
+ep_rt_file_handle_t
+ep_rt_mono_file_open_write (const ep_char8_t *path)
+{
+       if (!path)
+               return INVALID_HANDLE_VALUE;
 
-static
-gboolean
-eventpipe_execute_rundown (
-       ep_rt_mono_fire_domain_rundown_events_func domain_events_func,
-       ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func,
-       ep_rt_mono_fire_method_rundown_events_func methods_events_func);
+       ep_char16_t *path_utf16 = ep_rt_utf8_to_utf16le_string (path, -1);
 
-static
-gboolean
-eventpipe_walk_managed_stack_for_thread (
-       MonoStackFrameInfo *frame,
-       MonoContext *ctx,
-       EventPipeStackWalkData *stack_walk_data);
+       if (!path_utf16)
+               return INVALID_HANDLE_VALUE;
 
-static
-gboolean
-eventpipe_walk_managed_stack_for_thread_func (
-       MonoStackFrameInfo *frame,
-       MonoContext *ctx,
-       void *data);
+       ep_rt_file_handle_t res;
+       MONO_ENTER_GC_SAFE;
+       res = (ep_rt_file_handle_t)CreateFileW (path_utf16, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+       MONO_EXIT_GC_SAFE;
+       ep_rt_utf16_string_free (path_utf16);
 
-static
-gboolean
-eventpipe_sample_profiler_walk_managed_stack_for_thread_func (
-       MonoStackFrameInfo *frame,
-       MonoContext *ctx,
-       void *data);
+       return res;
+}
 
-static
-void
-profiler_eventpipe_runtime_initialized (MonoProfiler *prof);
+bool
+ep_rt_mono_file_close (ep_rt_file_handle_t handle)
+{
+       bool res;
+       MONO_ENTER_GC_SAFE;
+       res = CloseHandle (handle);
+       MONO_EXIT_GC_SAFE;
+       return res;
+}
 
 static
 void
-profiler_eventpipe_thread_exited (
-       MonoProfiler *prof,
-       uintptr_t tid);
-
-static
-bool
-parse_mono_profiler_options (const ep_char8_t *option);
+win32_io_interrupt_handler (void *ignored)
+{
+}
 
-static
 bool
-get_module_event_data (
-       MonoImage *image,
-       ModuleEventData *module_data);
+ep_rt_mono_file_write (
+       ep_rt_file_handle_t handle,
+       const uint8_t *buffer,
+       uint32_t numbytes,
+       uint32_t *byteswritten)
+{
+       MONO_REQ_GC_UNSAFE_MODE;
 
-static
-bool
-get_assembly_event_data (
-       MonoAssembly *assembly,
-       AssemblyEventData *assembly_data);
+       bool res;
+       MonoThreadInfo *info = mono_thread_info_current ();
+       gboolean alerted = FALSE;
 
-static
-uint32_t
-get_type_start_id (MonoType *type);
+       if (info) {
+               mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted);
+               if (alerted) {
+                       return false;
+               }
+               mono_win32_enter_blocking_io_call (info, handle);
+       }
 
-static
-gboolean
-get_exception_ip_func (
-       MonoStackFrameInfo *frame,
-       MonoContext *ctx,
-       void *data);
+       MONO_ENTER_GC_SAFE;
+       if (info && mono_thread_info_is_interrupt_state (info)) {
+               res = false;
+       } else {
+               res = WriteFile (handle, buffer, numbytes, (PDWORD)byteswritten, NULL) ? true : false;
+       }
+       MONO_EXIT_GC_SAFE;
 
-static
-void
-runtime_profiler_jit_begin (
-       MonoProfiler *prof,
-       MonoMethod *method);
+       if (info) {
+               mono_win32_leave_blocking_io_call (info, handle);
+               mono_thread_info_uninstall_interrupt (&alerted);
+       }
 
-static
-void
-runtime_profiler_jit_failed (
-       MonoProfiler *prof,
-       MonoMethod *method);
+       return res;
+}
 
-static
-void
-runtime_profiler_jit_done (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       MonoJitInfo *ji);
+#else
 
-static
-void
-runtime_profiler_image_loaded (
-       MonoProfiler *prof,
-       MonoImage *image);
+#include <fcntl.h>
+#include <unistd.h>
 
-static
-void
-runtime_profiler_image_unloaded (
-       MonoProfiler *prof,
-       MonoImage *image);
+ep_rt_file_handle_t
+ep_rt_mono_file_open_write (const ep_char8_t *path)
+{
+       int fd;
+       mode_t perms = 0666;
 
-static
-void
-runtime_profiler_assembly_loaded (
-       MonoProfiler *prof,
-       MonoAssembly *assembly);
+       if (!path)
+               return INVALID_HANDLE_VALUE;
 
-static
-void
-runtime_profiler_assembly_unloaded (
-       MonoProfiler *prof,
-       MonoAssembly *assembly);
+       MONO_ENTER_GC_SAFE;
+       fd = creat (path, perms);
+       MONO_EXIT_GC_SAFE;
 
-static
-void
-runtime_profiler_thread_started (
-       MonoProfiler *prof,
-       uintptr_t tid);
+       if (fd == -1)
+               return INVALID_HANDLE_VALUE;
 
-static
-void
-runtime_profiler_thread_stopped (
-       MonoProfiler *prof,
-       uintptr_t tid);
+       return (ep_rt_file_handle_t)(ptrdiff_t)fd;
+}
 
-static
-void
-runtime_profiler_class_loading (
-       MonoProfiler *prof,
-       MonoClass *klass);
+bool
+ep_rt_mono_file_close (ep_rt_file_handle_t handle)
+{
+       int fd = (int)(ptrdiff_t)handle;
 
-static
-void
-runtime_profiler_class_failed (
-       MonoProfiler *prof,
-       MonoClass *klass);
+       MONO_ENTER_GC_SAFE;
+       close (fd);
+       MONO_EXIT_GC_SAFE;
 
-static
-void
-runtime_profiler_class_loaded (
-       MonoProfiler *prof,
-       MonoClass *klass);
+       return true;
+}
 
-static
-void
-runtime_profiler_exception_throw (
-       MonoProfiler *prof,
-       MonoObject *exception);
+bool
+ep_rt_mono_file_write (
+       ep_rt_file_handle_t handle,
+       const uint8_t *buffer,
+       uint32_t numbytes,
+       uint32_t *byteswritten)
+{
+       MONO_REQ_GC_UNSAFE_MODE;
 
-static
-void
-runtime_profiler_exception_clause (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       uint32_t clause_num,
-       MonoExceptionEnum clause_type,
-       MonoObject *exc);
+       int fd = (int)(ptrdiff_t)handle;
+       uint32_t ret;
+       MonoThreadInfo *info = mono_thread_info_current ();
 
-static
-void
-runtime_profiler_monitor_contention (
-       MonoProfiler *prof,
-       MonoObject *obj);
+       if (byteswritten != NULL)
+               *byteswritten = 0;
 
-static
-void
-runtime_profiler_monitor_acquired (
-       MonoProfiler *prof,
-       MonoObject *obj);
+       do {
+               MONO_ENTER_GC_SAFE;
+               ret = write (fd, buffer, numbytes);
+               MONO_EXIT_GC_SAFE;
+       } while (ret == -1 && errno == EINTR &&
+                !mono_thread_info_is_interrupt_state (info));
 
-static
-void
-runtime_profiler_monitor_failed (
-       MonoProfiler *prof,
-       MonoObject *obj);
+       if (ret == -1) {
+               if (errno == EINTR)
+                       ret = 0;
+               else
+                       return false;
+       }
 
-static
-void
-runtime_profiler_jit_code_buffer (
-       MonoProfiler *prof,
-       const mono_byte *buffer,
-       uint64_t size,
-       MonoProfilerCodeBufferType type,
-       const void *data);
+       if (byteswritten != NULL)
+               *byteswritten = ret;
 
-static
-void
-mono_profiler_get_class_data (
-       MonoClass *klass,
-       uint64_t *class_id,
-       uint64_t *module_id,
-       ep_char8_t **class_name,
-       uint32_t *class_generic_type_count,
-       uint8_t **class_generic_types);
+       return true;
+}
 
-static
-void
-mono_profiler_fire_event_enter (void);
+#endif // HOST_WIN32
 
-static
-void
-mono_profiler_fire_event_exit (void);
+EventPipeThread *
+ep_rt_mono_thread_get_or_create (void)
+{
+       EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (_ep_rt_mono_thread_holder_tls_id);
+       if (!thread_holder) {
+               thread_holder = thread_holder_alloc_func ();
+               mono_native_tls_set_value (_ep_rt_mono_thread_holder_tls_id, thread_holder);
+       }
+       return ep_thread_holder_get_thread (thread_holder);
+}
 
-static
-void
-mono_profiler_gc_in_progress_start (void);
+EventPipeMonoThreadData *
+ep_rt_mono_thread_data_get_or_create (void)
+{
+       EventPipeMonoThreadData *thread_data = (EventPipeMonoThreadData *)mono_native_tls_get_value (_thread_data_tls_id);
+       if (!thread_data) {
+               thread_data = ep_rt_object_alloc (EventPipeMonoThreadData);
+               mono_native_tls_set_value (_thread_data_tls_id, thread_data);
+       }
+       return thread_data;
+}
 
-static
-void
-mono_profiler_gc_in_progress_stop (void);
-
-static
-MonoProfilerMemBlock *
-mono_profiler_mem_block_alloc (uint32_t req_size);
-
-static
-uint8_t *
-mono_profiler_mem_alloc (uint32_t req_size);
-
-static
-void
-mono_profiler_mem_block_free_all (void);
-
-static
-void
-mono_profiler_mem_block_free_all_but_current (void);
-
-static
-void
-mono_profiler_trigger_heap_collect (MonoProfiler *prof);
-
-static
-void
-mono_profiler_fire_gc_event_root_register (
-       uint8_t *data,
-       uint32_t payload_size);
-
-static
-void
-mono_profiler_fire_buffered_gc_event_root_register (
-       MonoProfiler *prof,
-       const mono_byte *start,
-       uintptr_t size,
-       MonoGCRootSource source,
-       const void * key,
-       const char * name);
-
-static
-void
-mono_profiler_fire_gc_event_root_unregister (
-       uint8_t *data,
-       uint32_t payload_size);
-
-static
-void
-mono_profiler_fire_buffered_gc_event_root_unregister (
-       MonoProfiler *prof,
-       const mono_byte *start);
-
-static
-void
-mono_profiler_fire_gc_event (
-       uint8_t *data,
-       uint32_t payload_size);
-
-static
-void
-mono_profiler_fire_buffered_gc_event (
-       uint8_t gc_event_type,
-       uint32_t generation);
-
-static
-void
-mono_profiler_fire_gc_event_resize (
-       uint8_t *data,
-       uint32_t payload_size);
-
-static
-void
-mono_profiler_fire_buffered_gc_event_resize (
-       MonoProfiler *prof,
-       uintptr_t size);
-
-static
-void
-mono_profiler_fire_gc_event_moves (
-       uint8_t *data,
-       uint32_t payload_size);
-
-static
-void
-mono_profiler_fire_buffered_gc_event_moves (
-       MonoProfiler *prof,
-       MonoObject *const* objects,
-       uint64_t count);
-
-static
-void
-mono_profiler_fire_gc_event_roots (
-       uint8_t *data,
-       uint32_t payload_size);
-
-static
-void
-mono_profiler_fire_buffered_gc_event_roots (
-       MonoProfiler *prof,
-       uint64_t count,
-       const mono_byte *const * addresses,
-       MonoObject *const * objects);
-
-static
-void
-mono_profiler_fire_gc_event_heap_dump_object_reference (
-       uint8_t *data,
-       uint32_t payload_size,
-       GHashTable *cache);
-
-static
-int
-mono_profiler_fire_buffered_gc_event_heap_dump_object_reference (
-       MonoObject *obj,
-       MonoClass *klass,
-       uintptr_t size,
-       uintptr_t num,
-       MonoObject **refs,
-       uintptr_t *offsets,
-       void *data);
-
-static
-void
-mono_profiler_fire_buffered_gc_events (
-       MonoProfilerMemBlock *block,
-       GHashTable *cache);
-
-static
-void
-mono_profiler_fire_buffered_gc_events_in_alloc_order (GHashTable *cache);
-
-static
-void
-mono_profiler_fire_cached_gc_events (GHashTable *cache);
-
-static
-void
-mono_profiler_app_domain_loading (
-       MonoProfiler *prof,
-       MonoDomain *domain);
-
-static
-void
-mono_profiler_app_domain_loaded (
-       MonoProfiler *prof,
-       MonoDomain *domain);
-
-static
-void
-mono_profiler_app_domain_unloading (
-       MonoProfiler *prof,
-       MonoDomain *domain);
-
-static
-void
-mono_profiler_app_domain_unloaded (
-       MonoProfiler *prof,
-       MonoDomain *domain);
-
-static
-void
-mono_profiler_app_domain_name (
-       MonoProfiler *prof,
-       MonoDomain *domain,
-       const char *name);
-
-static
-void
-mono_profiler_get_generic_types (
-       MonoGenericInst *generic_instance,
-       uint32_t *generic_type_count,
-       uint8_t **generic_types);
-
-static
-void
-mono_profiler_get_jit_data (
-       MonoMethod *method,
-       uint64_t *method_id,
-       uint64_t *module_id,
-       uint32_t *method_token,
-       uint32_t *method_generic_type_count,
-       uint8_t **method_generic_types);
-
-static
-void
-mono_profiler_jit_begin (
-       MonoProfiler *prof,
-       MonoMethod *method);
-
-static
-void
-mono_profiler_jit_failed (
-       MonoProfiler *prof,
-       MonoMethod *method);
-
-static
-void
-mono_profiler_jit_done (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       MonoJitInfo *ji);
-
-static
-void
-mono_profiler_jit_chunk_created (
-       MonoProfiler *prof,
-       const mono_byte *chunk,
-       uintptr_t size);
-
-static
-void
-mono_profiler_jit_chunk_destroyed (
-       MonoProfiler *prof,
-       const mono_byte *chunk);
-
-static
-void
-mono_profiler_jit_code_buffer (
-       MonoProfiler *prof,
-       const mono_byte *buffer,
-       uint64_t size,
-       MonoProfilerCodeBufferType type,
-       const void *data);
-
-static
-void
-mono_profiler_class_loading (
-       MonoProfiler *prof,
-       MonoClass *klass);
-
-static
-void
-mono_profiler_class_failed (
-       MonoProfiler *prof,
-       MonoClass *klass);
-
-static
-void
-mono_profiler_class_loaded (
-       MonoProfiler *prof,
-       MonoClass *klass);
-
-static
-void
-mono_profiler_vtable_loading (
-       MonoProfiler *prof,
-       MonoVTable *vtable);
-
-static
-void
-mono_profiler_vtable_failed (
-       MonoProfiler *prof,
-       MonoVTable *vtable);
-
-static
-void
-mono_profiler_vtable_loaded (
-       MonoProfiler *prof,
-       MonoVTable *vtable);
-
-static
-void
-mono_profiler_module_loading (
-       MonoProfiler *prof,
-       MonoImage *image);
-
-static
-void
-mono_profiler_module_failed (
-       MonoProfiler *prof,
-       MonoImage *image);
-
-static
-void
-mono_profiler_module_loaded (
-       MonoProfiler *prof,
-       MonoImage *image);
-
-static
-void
-mono_profiler_module_unloading (
-       MonoProfiler *prof,
-       MonoImage *image);
-
-static
-void
-mono_profiler_module_unloaded (
-       MonoProfiler *prof,
-       MonoImage *image);
-
-static
-void
-mono_profiler_assembly_loading (
-       MonoProfiler *prof,
-       MonoAssembly *assembly);
-
-static
-void
-mono_profiler_assembly_loaded (
-       MonoProfiler *prof,
-       MonoAssembly *assembly);
-
-static
-void
-mono_profiler_assembly_unloading (
-       MonoProfiler *prof,
-       MonoAssembly *assembly);
-
-static
-void
-mono_profiler_assembly_unloaded (
-       MonoProfiler *prof,
-       MonoAssembly *assembly);
-
-static
-void
-mono_profiler_method_enter (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       MonoProfilerCallContext *context);
-
-static
-void
-mono_profiler_method_leave (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       MonoProfilerCallContext *context);
-
-static
-void
-mono_profiler_method_tail_call (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       MonoMethod *target_method);
-
-static
-void
-mono_profiler_method_exception_leave (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       MonoObject *exc);
-
-static
-void
-mono_profiler_method_free (
-       MonoProfiler *prof,
-       MonoMethod *method);
-
-static
-void
-mono_profiler_method_begin_invoke (
-       MonoProfiler *prof,
-       MonoMethod *method);
-
-static
-void
-mono_profiler_method_end_invoke (
-       MonoProfiler *prof,
-       MonoMethod *method);
-
-static
-MonoProfilerCallInstrumentationFlags
-mono_profiler_method_instrumentation (
-       MonoProfiler *prof,
-       MonoMethod *method);
-
-static
-void
-mono_profiler_exception_throw (
-       MonoProfiler *prof,
-       MonoObject *exc);
-
-static
-void
-mono_profiler_exception_clause (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       uint32_t clause_num,
-       MonoExceptionEnum clause_type,
-       MonoObject *exc);
-
-static
-void
-mono_profiler_gc_event (
-       MonoProfiler *prof,
-       MonoProfilerGCEvent gc_event,
-       uint32_t generation,
-       mono_bool serial);
-
-static
-void
-mono_profiler_gc_allocation (
-       MonoProfiler *prof,
-       MonoObject *object);
-
-static
-void
-mono_profiler_gc_handle_created (
-       MonoProfiler *prof,
-       uint32_t handle,
-       MonoGCHandleType type,
-       MonoObject * object);
-
-static
-void
-mono_profiler_gc_handle_deleted (
-       MonoProfiler *prof,
-       uint32_t handle,
-       MonoGCHandleType type);
-
-static
-void
-mono_profiler_gc_finalizing (MonoProfiler *prof);
-
-static
-void
-mono_profiler_gc_finalized (MonoProfiler *prof);
-
-static
-void
-mono_profiler_gc_root_register (
-       MonoProfiler *prof,
-       const mono_byte *start,
-       uintptr_t size,
-       MonoGCRootSource source,
-       const void * key,
-       const char * name);
-
-static
-void
-mono_profiler_gc_root_unregister (
-       MonoProfiler *prof,
-       const mono_byte *start);
-
-static
-void
-mono_profiler_monitor_contention (
-       MonoProfiler *prof,
-       MonoObject *object);
-
-static
-void
-mono_profiler_monitor_failed (
-       MonoProfiler *prof,
-       MonoObject *object);
-
-static
-void
-mono_profiler_monitor_acquired (
-       MonoProfiler *prof,
-       MonoObject *object);
-
-static
-void
-mono_profiler_thread_started (
-       MonoProfiler *prof,
-       uintptr_t tid);
-
-static
-void
-mono_profiler_thread_stopping (
-       MonoProfiler *prof,
-       uintptr_t tid);
-
-static
-void
-mono_profiler_thread_stopped (
-       MonoProfiler *prof,
-       uintptr_t tid);
-
-static
-void
-mono_profiler_thread_exited (
-       MonoProfiler *prof,
-       uintptr_t tid);
-
-static
-void
-mono_profiler_thread_name (
-       MonoProfiler *prof,
-       uintptr_t tid,
-       const char *name);
-
-static
-const EventFilterDescriptor *
-mono_profiler_add_provider_param (const EventFilterDescriptor *key);
-
-static
-bool
-mono_profiler_remove_provider_param (const EventFilterDescriptor *key);
-
-static
-void
-mono_profiler_free_provider_params (void);
-
-static
-bool
-mono_profiler_provider_params_get_value (
-       const EventFilterDescriptor *param,
-       const ep_char8_t *key,
-       const ep_char8_t **value);
-
-static
-bool
-mono_profiler_provider_param_contains_heap_collect_ondemand (const EventFilterDescriptor *param);
-
-static
-void
-mono_profiler_push_gc_heap_collect_param_request_value (const EventFilterDescriptor *param);
-
-static
-void
-mono_profiler_pop_gc_heap_collect_param_request_value (void);
-
-static
-void
-mono_profiler_pop_gc_heap_collect_param_request_value (void);
-
-static
-const ep_char8_t *
-mono_profiler_get_gc_heap_collect_param_request_value (void);
-
-static
-void
-mono_profiler_free_gc_heap_collect_param_requests (void);
-
-static
-void
-mono_profiler_ep_provider_callback (
-       const uint8_t *source_id,
-       unsigned long is_enabled,
-       uint8_t level,
-       uint64_t match_any_keywords,
-       uint64_t match_all_keywords,
-       EventFilterDescriptor *filter_data,
-       void *callback_data);
-
-/*
- * Forward declares of all private functions (accessed using extern in ep-rt-mono.h).
- */
-
-void
-ep_rt_mono_component_init (void);
-
-void
-ep_rt_mono_init (void);
-
-void
-ep_rt_mono_init_finish (void);
-
-void
-ep_rt_mono_fini (void);
-
-bool
-ep_rt_mono_rand_try_get_bytes (
-       uint8_t *buffer,
-       size_t buffer_size);
-
-ep_rt_file_handle_t
-ep_rt_mono_file_open_write(const ep_char8_t *path);
-
-bool
-ep_rt_mono_file_close (ep_rt_file_handle_t handle);
-
-bool
-ep_rt_mono_file_write (
-       ep_rt_file_handle_t handle,
-       const uint8_t *buffer,
-       uint32_t numbytes,
-       uint32_t *byteswritten);
-
-EventPipeThread *
-ep_rt_mono_thread_get_or_create (void);
-
-void *
-ep_rt_mono_thread_attach (bool background_thread);
-
-void *
-ep_rt_mono_thread_attach_2 (bool background_thread, EventPipeThreadType thread_type);
-
-void
-ep_rt_mono_thread_detach (void);
-
-void
-ep_rt_mono_thread_exited (void);
-
-int64_t
-ep_rt_mono_perf_counter_query (void);
-
-int64_t
-ep_rt_mono_perf_frequency_query (void);
-
-void
-ep_rt_mono_system_time_get (EventPipeSystemTime *system_time);
-
-int64_t
-ep_rt_mono_system_timestamp_get (void);
-
-void
-ep_rt_mono_os_environment_get_utf16 (dn_vector_ptr_t *os_env);
-
-void
-ep_rt_mono_init_providers_and_events (void);
-
-void
-ep_rt_mono_provider_config_init (EventPipeProviderConfiguration *provider_config);
-
-bool
-ep_rt_mono_providers_validate_all_disabled (void);
-
-void
-ep_rt_mono_fini_providers_and_events (void);
-
-bool
-ep_rt_mono_sample_profiler_write_sampling_event_for_threads (
-       ep_rt_thread_handle_t sampling_thread,
-       EventPipeEvent *sampling_event);
-
-bool
-ep_rt_mono_walk_managed_stack_for_thread (
-       ep_rt_thread_handle_t thread,
-       EventPipeStackContents *stack_contents);
-
-bool
-ep_rt_mono_method_get_simple_assembly_name (
-       ep_rt_method_desc_t *method,
-       ep_char8_t *name,
-       size_t name_len);
-
-bool
-ep_rt_mono_method_get_full_name (
-       ep_rt_method_desc_t *method,
-       ep_char8_t *name,
-       size_t name_len);
-
-void
-ep_rt_mono_execute_rundown (dn_vector_ptr_t *execution_checkpoints);
-
-static
-inline
-bool
-profiler_callback_is_enabled (uint64_t enabled_keywords, uint64_t keyword)
-{
-       return (enabled_keywords & keyword) == keyword;
-}
-
-static
-inline
-uint16_t
-clr_instance_get_id (void)
-{
-       // Mono runtime id.
-       return 9;
-}
-
-static
-EventPipeThreadData *
-eventpipe_thread_data_get_or_create (void)
-{
-       EventPipeThreadData *thread_data = (EventPipeThreadData *)mono_native_tls_get_value (_ep_rt_mono_thread_data_tls_id);
-       if (!thread_data) {
-               thread_data = ep_rt_object_alloc (EventPipeThreadData);
-               mono_native_tls_set_value (_ep_rt_mono_thread_data_tls_id, thread_data);
-       }
-       return thread_data;
-}
-
-static
-void
-eventpipe_thread_data_free (EventPipeThreadData *thread_data)
-{
-       ep_return_void_if_nok (thread_data != NULL);
-       ep_rt_object_free (thread_data);
-}
-
-static
-bool
-fire_method_rundown_events_func (
-       const uint64_t method_id,
-       const uint64_t module_id,
-       const uint64_t method_start_address,
-       const uint32_t method_size,
-       const uint32_t method_token,
-       const uint32_t method_flags,
-       const ep_char8_t *method_namespace,
-       const ep_char8_t *method_name,
-       const ep_char8_t *method_signature,
-       const uint16_t count_of_map_entries,
-       const uint32_t *il_offsets,
-       const uint32_t *native_offsets,
-       bool aot_method,
-       bool verbose,
-       void *user_data)
-{
-       FireEtwMethodDCEndILToNativeMap (
-               method_id,
-               0,
-               0,
-               count_of_map_entries,
-               il_offsets,
-               native_offsets,
-               clr_instance_get_id (),
-               NULL,
-               NULL);
-
-       if (verbose) {
-               FireEtwMethodDCEndVerbose_V1 (
-                       method_id,
-                       module_id,
-                       method_start_address,
-                       method_size,
-                       method_token,
-                       method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION,
-                       method_namespace,
-                       method_name,
-                       method_signature,
-                       clr_instance_get_id (),
-                       NULL,
-                       NULL);
-
-               if (aot_method)
-                       FireEtwMethodDCEndVerbose_V1 (
-                               method_id,
-                               module_id,
-                               method_start_address,
-                               method_size,
-                               method_token,
-                               method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION,
-                               method_namespace,
-                               method_name,
-                               method_signature,
-                               clr_instance_get_id (),
-                               NULL,
-                               NULL);
-       } else {
-               FireEtwMethodDCEnd_V1 (
-                       method_id,
-                       module_id,
-                       method_start_address,
-                       method_size,
-                       method_token,
-                       method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION,
-                       clr_instance_get_id (),
-                       NULL,
-                       NULL);
-
-               if (aot_method)
-                       FireEtwMethodDCEnd_V1 (
-                               method_id,
-                               module_id,
-                               method_start_address,
-                               method_size,
-                               method_token,
-                               method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION,
-                               clr_instance_get_id (),
-                               NULL,
-                               NULL);
-       }
-
-       return true;
-}
-
-static
-bool
-fire_assembly_rundown_events_func (
-       const uint64_t domain_id,
-       const uint64_t assembly_id,
-       const uint32_t assembly_flags,
-       const uint32_t binding_id,
-       const ep_char8_t *assembly_name,
-       const uint64_t module_id,
-       const uint32_t module_flags,
-       const uint32_t reserved_flags,
-       const ep_char8_t *module_il_path,
-       const ep_char8_t *module_native_path,
-       const uint8_t *managed_pdb_signature,
-       const uint32_t managed_pdb_age,
-       const ep_char8_t *managed_pdb_build_path,
-       const uint8_t *native_pdb_signature,
-       const uint32_t native_pdb_age,
-       const ep_char8_t *native_pdb_build_path,
-       void *user_data)
-{
-       FireEtwModuleDCEnd_V2 (
-               module_id,
-               assembly_id,
-               module_flags,
-               reserved_flags,
-               module_il_path,
-               module_native_path,
-               clr_instance_get_id (),
-               managed_pdb_signature,
-               managed_pdb_age,
-               managed_pdb_build_path,
-               native_pdb_signature,
-               native_pdb_age,
-               native_pdb_build_path,
-               NULL,
-               NULL);
-
-       FireEtwDomainModuleDCEnd_V1 (
-               module_id,
-               assembly_id,
-               domain_id,
-               module_flags,
-               reserved_flags,
-               module_il_path,
-               module_native_path,
-               clr_instance_get_id (),
-               NULL,
-               NULL);
-
-       FireEtwAssemblyDCEnd_V1 (
-               assembly_id,
-               domain_id,
-               binding_id,
-               assembly_flags,
-               assembly_name,
-               clr_instance_get_id (),
-               NULL,
-               NULL);
-
-       return true;
-}
-
-static
-bool
-fire_domain_rundown_events_func (
-       const uint64_t domain_id,
-       const uint32_t domain_flags,
-       const ep_char8_t *domain_name,
-       const uint32_t domain_index,
-       void *user_data)
-{
-       return FireEtwAppDomainDCEnd_V1 (
-               domain_id,
-               domain_flags,
-               domain_name,
-               domain_index,
-               clr_instance_get_id (),
-               NULL,
-               NULL);
-}
-
-static
-void
-eventpipe_fire_method_events (
-       MonoJitInfo *ji,
-       MonoMethod *method,
-       EventPipeFireMethodEventsData *events_data)
-{
-       EP_ASSERT (ji != NULL);
-       EP_ASSERT (events_data->domain != NULL);
-       EP_ASSERT (events_data->method_events_func != NULL);
-
-       uint64_t method_id = 0;
-       uint64_t module_id = 0;
-       uint64_t method_code_start = (uint64_t)ji->code_start;
-       uint32_t method_code_size = (uint32_t)ji->code_size;
-       uint32_t method_token = 0;
-       uint32_t method_flags = 0;
-       uint8_t kind = MONO_CLASS_DEF;
-       char *method_namespace = NULL;
-       const char *method_name = NULL;
-       char *method_signature = NULL;
-       bool verbose = (MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.Level >= (uint8_t)EP_EVENT_LEVEL_VERBOSE);
-
-       //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc.
-
-       if (method) {
-               method_id = (uint64_t)method;
-               method_token = method->token;
-
-               if (mono_jit_info_get_generic_sharing_context (ji))
-                       method_flags |= METHOD_FLAGS_SHARED_GENERIC_METHOD;
-
-               if (method->dynamic)
-                       method_flags |= METHOD_FLAGS_DYNAMIC_METHOD;
-
-               if (!ji->from_aot && !ji->from_llvm) {
-                       method_flags |= METHOD_FLAGS_JITTED_METHOD;
-                       if (method->wrapper_type != MONO_WRAPPER_NONE)
-                               method_flags |= METHOD_FLAGS_JITTED_HELPER_METHOD;
-               }
-
-               if (method->is_generic || method->is_inflated)
-                       method_flags |= METHOD_FLAGS_GENERIC_METHOD;
-
-               if (method->klass) {
-                       module_id = (uint64_t)m_class_get_image (method->klass);
-                       kind = m_class_get_class_kind (method->klass);
-                       if (kind == MONO_CLASS_GTD || kind == MONO_CLASS_GINST)
-                               method_flags |= METHOD_FLAGS_GENERIC_METHOD;
-               }
-
-               if (verbose) {
-                       method_name = method->name;
-                       method_signature = mono_signature_full_name (mono_method_signature_internal (method));
-                       if (method->klass)
-                               method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL);
-               }
-
-       }
-
-       uint32_t offset_entries = 0;
-       uint32_t *il_offsets = NULL;
-       uint32_t *native_offsets = NULL;
-
-       MonoDebugMethodJitInfo *debug_info = method ? mono_debug_find_method (method, events_data->domain) : NULL;
-       if (debug_info) {
-               offset_entries = debug_info->num_line_numbers;
-               if (offset_entries != 0) {
-                       size_t needed_size = (offset_entries * sizeof (uint32_t) * 2);
-                       if (!events_data->buffer || needed_size > events_data->buffer_size) {
-                               g_free (events_data->buffer);
-                               events_data->buffer_size = (size_t)(needed_size * 1.5);
-                               events_data->buffer = g_new (uint8_t, events_data->buffer_size);
-                       }
-
-                       if (events_data->buffer) {
-                               il_offsets = (uint32_t*)events_data->buffer;
-                               native_offsets = il_offsets + offset_entries;
-
-                               uint8_t *il_offsets_ptr = (uint8_t *)il_offsets;
-                               uint8_t *native_offsets_ptr = (uint8_t *)native_offsets;
-                               for (uint32_t offset_count = 0; offset_count < offset_entries; ++offset_count) {
-                                       ep_write_buffer_uint32_t (&il_offsets_ptr, debug_info->line_numbers [offset_count].il_offset);
-                                       ep_write_buffer_uint32_t (&native_offsets_ptr, debug_info->line_numbers [offset_count].native_offset);
-                               }
-                       }
-               }
-
-               mono_debug_free_method_jit_info (debug_info);
-       }
-
-       if (events_data->buffer && !il_offsets && !native_offsets) {
-               // No IL offset -> Native offset mapping available. Put all code on IL offset 0.
-               EP_ASSERT (events_data->buffer_size >= sizeof (uint32_t) * 2);
-               offset_entries = 1;
-               il_offsets = (uint32_t*)events_data->buffer;
-               native_offsets = il_offsets + offset_entries;
-               il_offsets [0] = 0;
-               native_offsets [0] = ep_rt_val_uint32_t ((uint32_t)ji->code_size);
-       }
-
-       events_data->method_events_func (
-               method_id,
-               module_id,
-               method_code_start,
-               method_code_size,
-               method_token,
-               method_flags,
-               (ep_char8_t *)method_namespace,
-               (ep_char8_t *)method_name,
-               (ep_char8_t *)method_signature,
-               GUINT32_TO_UINT16 (offset_entries),
-               il_offsets,
-               native_offsets,
-               (ji->from_aot || ji->from_llvm),
-               verbose,
-               NULL);
-
-       g_free (method_namespace);
-       g_free (method_signature);
-}
-
-static
-inline
-bool
-include_method (MonoMethod *method)
-{
-       if (!method) {
-               return false;
-       } else if (!m_method_is_wrapper (method)) {
-               return true;
-       } else {
-               WrapperInfo *wrapper = mono_marshal_get_wrapper_info (method);
-               return (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_PINVOKE) ? true : false;
-       }
-}
-
-static
-void
-eventpipe_fire_method_events_func (
-       MonoJitInfo *ji,
-       void  *user_data)
-{
-       EventPipeFireMethodEventsData *events_data = (EventPipeFireMethodEventsData *)user_data;
-       EP_ASSERT (events_data != NULL);
-
-       if (ji && !ji->is_trampoline && !ji->async) {
-               MonoMethod *method = jinfo_get_method (ji);
-               if (include_method (method))
-                       eventpipe_fire_method_events (ji, method, events_data);
-       }
-}
-
-static
-void
-eventpipe_fire_assembly_events (
-       MonoDomain *domain,
-       MonoAssembly *assembly,
-       ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func)
-{
-       EP_ASSERT (domain != NULL);
-       EP_ASSERT (assembly != NULL);
-       EP_ASSERT (assembly_events_func != NULL);
-
-       // Native methods are part of JIT table and already emitted.
-       // TODO: FireEtwMethodDCEndVerbose_V1_or_V2 for all native methods in module as well?
-
-       uint32_t binding_id = 0;
-
-       ModuleEventData module_data;
-       memset (&module_data, 0, sizeof (module_data));
-
-       get_module_event_data (assembly->image, &module_data);
-
-       uint32_t assembly_flags = 0;
-       if (assembly->dynamic)
-               assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY;
-
-       if (assembly->image && assembly->image->aot_module) {
-               assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY;
-       }
-
-       char *assembly_name = mono_stringify_assembly_name (&assembly->aname);
-
-       assembly_events_func (
-               module_data.domain_id,
-               module_data.assembly_id,
-               assembly_flags,
-               binding_id,
-               (const ep_char8_t*)assembly_name,
-               module_data.module_id,
-               module_data.module_flags,
-               module_data.reserved_flags,
-               (const ep_char8_t *)module_data.module_il_path,
-               (const ep_char8_t *)module_data.module_native_path,
-               module_data.module_il_pdb_signature,
-               module_data.module_il_pdb_age,
-               (const ep_char8_t *)module_data.module_il_pdb_path,
-               module_data.module_native_pdb_signature,
-               module_data.module_native_pdb_age,
-               (const ep_char8_t *)module_data.module_native_pdb_path,
-               NULL);
-
-       g_free (assembly_name);
-}
-
-static
-gboolean
-eventpipe_execute_rundown (
-       ep_rt_mono_fire_domain_rundown_events_func domain_events_func,
-       ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func,
-       ep_rt_mono_fire_method_rundown_events_func method_events_func)
-{
-       EP_ASSERT (domain_events_func != NULL);
-       EP_ASSERT (assembly_events_func != NULL);
-       EP_ASSERT (method_events_func != NULL);
-
-       // Under netcore we only have root domain.
-       MonoDomain *root_domain = mono_get_root_domain ();
-       if (root_domain) {
-               uint64_t domain_id = (uint64_t)root_domain;
-
-               // Emit all functions in use (JIT, AOT and Interpreter).
-               EventPipeFireMethodEventsData events_data;
-               events_data.domain = root_domain;
-               events_data.buffer_size = 1024 * sizeof(uint32_t);
-               events_data.buffer = g_new (uint8_t, events_data.buffer_size);
-               events_data.method_events_func = method_events_func;
-
-               // All called JIT/AOT methods should be included in jit info table.
-               mono_jit_info_table_foreach_internal (eventpipe_fire_method_events_func, &events_data);
-
-               // All called interpreted methods should be included in interpreter jit info table.
-               if (mono_get_runtime_callbacks ()->is_interpreter_enabled())
-                       mono_get_runtime_callbacks ()->interp_jit_info_foreach (eventpipe_fire_method_events_func, &events_data);
-
-               // Phantom methods injected in callstacks representing runtime functions.
-               if (_ep_rt_mono_runtime_helper_compile_method_jitinfo && _ep_rt_mono_runtime_helper_compile_method)
-                       eventpipe_fire_method_events (_ep_rt_mono_runtime_helper_compile_method_jitinfo, _ep_rt_mono_runtime_helper_compile_method, &events_data);
-               if (_ep_rt_mono_monitor_enter_method_jitinfo && _ep_rt_mono_monitor_enter_method)
-                       eventpipe_fire_method_events (_ep_rt_mono_monitor_enter_method_jitinfo, _ep_rt_mono_monitor_enter_method, &events_data);
-               if (_ep_rt_mono_monitor_enter_v4_method_jitinfo && _ep_rt_mono_monitor_enter_v4_method)
-                       eventpipe_fire_method_events (_ep_rt_mono_monitor_enter_v4_method_jitinfo, _ep_rt_mono_monitor_enter_v4_method, &events_data);
-
-               g_free (events_data.buffer);
-
-               // Iterate all assemblies in domain.
-               GPtrArray *assemblies = mono_alc_get_all_loaded_assemblies ();
-               if (assemblies) {
-                       for (uint32_t i = 0; i < assemblies->len; ++i) {
-                               MonoAssembly *assembly = (MonoAssembly *)g_ptr_array_index (assemblies, i);
-                               if (assembly)
-                                       eventpipe_fire_assembly_events (root_domain, assembly, assembly_events_func);
-                       }
-                       g_ptr_array_free (assemblies, TRUE);
-               }
-
-               uint32_t domain_flags = DOMAIN_FLAGS_DEFAULT_DOMAIN | DOMAIN_FLAGS_EXECUTABLE_DOMAIN;
-               const char *domain_name = root_domain->friendly_name ? root_domain->friendly_name : "";
-               uint32_t domain_index = 1;
-
-               domain_events_func (
-                       domain_id,
-                       domain_flags,
-                       (const ep_char8_t *)domain_name,
-                       domain_index,
-                       NULL);
-       }
-
-       return TRUE;
-}
-
-inline
-static
-bool
-in_safe_point_frame (EventPipeStackContents *stack_content, WrapperInfo *wrapper)
-{
-       EP_ASSERT (stack_content != NULL);
-
-       // If top of stack is a managed->native icall wrapper for one of the below subtypes, we are at a safe point frame.
-       if (wrapper && ep_stack_contents_get_length (stack_content) == 0 && wrapper->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER &&
-                       (wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_state_poll ||
-                       wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_enter_gc_safe_region_unbalanced ||
-                       wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_exit_gc_safe_region_unbalanced ||
-                       wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_enter_gc_unsafe_region_unbalanced ||
-                       wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_exit_gc_unsafe_region_unbalanced))
-               return true;
-
-       return false;
-}
-
-inline
-static
-bool
-in_runtime_invoke_frame (EventPipeStackContents *stack_content, WrapperInfo *wrapper)
-{
-       EP_ASSERT (stack_content != NULL);
-
-       // If top of stack is a managed->native runtime invoke wrapper, we are at a managed frame.
-       if (wrapper && ep_stack_contents_get_length (stack_content) == 0 &&
-                       (wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL ||
-                       wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT ||
-                       wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC ||
-                       wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL))
-               return true;
-
-       return false;
-}
-
-inline
-static
-bool
-in_monitor_enter_frame (WrapperInfo *wrapper)
-{
-       if (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER &&
-                       (wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_fast ||
-                       wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_internal))
-               return true;
-
-       return false;
-}
-
-inline
-static
-bool
-in_monitor_enter_v4_frame (WrapperInfo *wrapper)
-{
-       if (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER &&
-                       (wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_v4_fast ||
-                       wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_v4_internal))
-               return true;
-
-       return false;
-}
-
-static
-gboolean
-eventpipe_walk_managed_stack_for_thread (
-       MonoStackFrameInfo *frame,
-       MonoContext *ctx,
-       EventPipeStackWalkData *stack_walk_data)
-{
-       EP_ASSERT (frame != NULL);
-       EP_ASSERT (stack_walk_data != NULL);
-
-       switch (frame->type) {
-       case FRAME_TYPE_DEBUGGER_INVOKE:
-       case FRAME_TYPE_MANAGED_TO_NATIVE:
-       case FRAME_TYPE_TRAMPOLINE:
-       case FRAME_TYPE_INTERP_TO_MANAGED:
-       case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
-       case FRAME_TYPE_INTERP_ENTRY:
-               stack_walk_data->top_frame = false;
-               return FALSE;
-       case FRAME_TYPE_JIT_ENTRY:
-               // Frame in JIT compiler at top of callstack, add phantom frame representing call into JIT compiler.
-               // Makes it possible to detect stacks waiting on JIT compiler.
-               if (_ep_rt_mono_runtime_helper_compile_method && stack_walk_data->top_frame)
-                       ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)_ep_rt_mono_runtime_helper_compile_method), _ep_rt_mono_runtime_helper_compile_method);
-               stack_walk_data->top_frame = false;
-               return FALSE;
-       case FRAME_TYPE_MANAGED:
-       case FRAME_TYPE_INTERP:
-               if (frame->ji) {
-                       stack_walk_data->async_frame |= frame->ji->async;
-                       MonoMethod *method = frame->ji->async ? NULL : frame->actual_method;
-                       if (method && m_method_is_wrapper (method)) {
-                               WrapperInfo *wrapper = mono_marshal_get_wrapper_info (method);
-                               if (in_safe_point_frame (stack_walk_data->stack_contents, wrapper)) {
-                                       stack_walk_data->safe_point_frame = true;
-                               }else if (in_runtime_invoke_frame (stack_walk_data->stack_contents, wrapper)) {
-                                       stack_walk_data->runtime_invoke_frame = true;
-                               } else if (_ep_rt_mono_monitor_enter_method && in_monitor_enter_frame (wrapper)) {
-                                       ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)_ep_rt_mono_monitor_enter_method), _ep_rt_mono_monitor_enter_method);
-                               } else if (_ep_rt_mono_monitor_enter_v4_method && in_monitor_enter_v4_frame (wrapper)) {
-                                       ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)_ep_rt_mono_monitor_enter_v4_method), _ep_rt_mono_monitor_enter_v4_method);
-                               } else if (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_PINVOKE) {
-                                       ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)frame->ji->code_start + frame->native_offset), method);
-                               }
-                       } else if (method && !m_method_is_wrapper (method)) {
-                               ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)frame->ji->code_start + frame->native_offset), method);
-                       } else if (!method && frame->ji->async && !frame->ji->is_trampoline) {
-                               ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)frame->ji->code_start), method);
-                       }
-               }
-               stack_walk_data->top_frame = false;
-               return ep_stack_contents_get_length (stack_walk_data->stack_contents) >= EP_MAX_STACK_DEPTH;
-       default:
-               EP_UNREACHABLE ("eventpipe_walk_managed_stack_for_thread");
-               return FALSE;
-       }
-}
-
-static
-gboolean
-eventpipe_walk_managed_stack_for_thread_func (
-       MonoStackFrameInfo *frame,
-       MonoContext *ctx,
-       void *data)
-{
-       return eventpipe_walk_managed_stack_for_thread (frame, ctx, (EventPipeStackWalkData *)data);
-}
-
-static
-gboolean
-eventpipe_sample_profiler_walk_managed_stack_for_thread_func (
-       MonoStackFrameInfo *frame,
-       MonoContext *ctx,
-       void *data)
-{
-       EP_ASSERT (frame != NULL);
-       EP_ASSERT (data != NULL);
-
-       EventPipeSampleProfileStackWalkData *sample_data = (EventPipeSampleProfileStackWalkData *)data;
-
-       if (sample_data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR) {
-               switch (frame->type) {
-               case FRAME_TYPE_MANAGED:
-                       sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED;
-                       break;
-               case FRAME_TYPE_MANAGED_TO_NATIVE:
-               case FRAME_TYPE_TRAMPOLINE:
-                       sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL;
-                       break;
-               case FRAME_TYPE_JIT_ENTRY:
-                       sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL;
-                       break;
-               case FRAME_TYPE_INTERP:
-                       sample_data->payload_data = frame->managed ? EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED : EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL;
-                       break;
-               case FRAME_TYPE_INTERP_TO_MANAGED:
-               case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
-                       break;
-               default:
-                       sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED;
-               }
-       }
-
-       return eventpipe_walk_managed_stack_for_thread (frame, ctx, &sample_data->stack_walk_data);
-}
-
-static
-void
-profiler_eventpipe_runtime_initialized (MonoProfiler *prof)
-{
-       _ep_rt_mono_profiler_gc_can_collect_heap = true;
-}
-
-static
-void
-profiler_eventpipe_thread_exited (
-       MonoProfiler *prof,
-       uintptr_t tid)
-{
-       ep_rt_mono_thread_exited ();
-}
-
-static
-bool
-parse_mono_profiler_options (const ep_char8_t *option)
-{
-       do {
-               if (!*option)
-                       return false;
-
-               if (!strncmp (option, "alloc", 5)) {
-                       mono_profiler_enable_allocations ();
-                       option += 5;
-               } else if (!strncmp (option, "exception", 9)) {
-                       mono_profiler_enable_clauses ();
-                       option += 9;
-               /*} else if (!strncmp (option, "sample", 6)) {
-                       mono_profiler_enable_sampling (_ep_rt_dotnet_mono_profiler_provider);
-                       option += 6;*/
-               } else {
-                       return false;
-               }
-
-               if (*option == ',')
-                       option++;
-       } while (*option);
-
-       return true;
-}
-
-void
-ep_rt_mono_component_init (void)
-{
-       _ep_rt_default_profiler = mono_profiler_create (NULL);
-       _ep_rt_dotnet_runtime_profiler_provider = mono_profiler_create (NULL);
-       _ep_rt_dotnet_mono_profiler_provider = mono_profiler_create (NULL);
-       _ep_rt_dotnet_mono_profiler_heap_collect_provider = mono_profiler_create (NULL);
-
-       char *diag_env = g_getenv("MONO_DIAGNOSTICS");
-       if (diag_env) {
-               int diag_argc = 1;
-               char **diag_argv = g_new (char *, 1);
-               if (diag_argv) {
-                       diag_argv [0] = NULL;
-                       if (!mono_parse_options_from (diag_env, &diag_argc, &diag_argv)) {
-                               for (int i = 0; i < diag_argc; ++i) {
-                                       if (diag_argv [i]) {
-                                               if (strncmp (diag_argv [i], "--diagnostic-mono-profiler=", 27) == 0) {
-                                                       if (!parse_mono_profiler_options (diag_argv [i] + 27))
-                                                               mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed parsing MONO_DIAGNOSTICS environment variable option: %s", diag_argv [i]);
-                                               } else if (strncmp (diag_argv [i], "--diagnostic-mono-profiler-callspec=", 36) == 0) {
-                                                       char *errstr = NULL;
-                                                       if (!mono_callspec_parse (diag_argv [i] + 36, &_ep_rt_dotnet_mono_profiler_provider_callspec, &errstr)) {
-                                                               mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed parsing '%s': %s", diag_argv [i], errstr);
-                                                               g_free (errstr);
-                                                               mono_callspec_cleanup (&_ep_rt_dotnet_mono_profiler_provider_callspec);
-                                                       } else {
-                                                               mono_profiler_set_call_instrumentation_filter_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_instrumentation);
-                                                       }
-                                               } else if (strncmp (diag_argv [i], "--diagnostic-ports=", 19) == 0) {
-                                                       char *diag_ports_env = g_getenv("DOTNET_DiagnosticPorts");
-                                                       if (diag_ports_env)
-                                                               mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_DIAGNOSTICS, "DOTNET_DiagnosticPorts environment variable already set, ignoring --diagnostic-ports used in MONO_DIAGNOSTICS environment variable");
-                                                       else
-                                                               g_setenv ("DOTNET_DiagnosticPorts", diag_argv [i] + 19, TRUE);
-                                                       g_free (diag_ports_env);
-
-                                               } else {
-                                                       mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed parsing MONO_DIAGNOSTICS environment variable, unknown option: %s", diag_argv [i]);
-                                               }
-
-                                               g_free (diag_argv [i]);
-                                               diag_argv [i] = NULL;
-                                       }
-                               }
-
-                               g_free (diag_argv);
-                       } else {
-                               mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed parsing MONO_DIAGNOSTICS environment variable");
-                       }
-               }
-       }
-       g_free (diag_env);
-}
-
-void
-ep_rt_mono_init (void)
-{
-       mono_native_tls_alloc (&_ep_rt_mono_thread_holder_tls_id, NULL);
-       mono_native_tls_alloc (&_ep_rt_mono_thread_data_tls_id, NULL);
-
-       mono_100ns_ticks ();
-       mono_rand_open ();
-       _ep_rt_mono_rand_provider = mono_rand_init (NULL, 0);
-
-       _ep_rt_mono_initialized = TRUE;
-
-       EP_ASSERT (_ep_rt_default_profiler != NULL);
-       EP_ASSERT (_ep_rt_dotnet_runtime_profiler_provider != NULL);
-       EP_ASSERT (_ep_rt_dotnet_mono_profiler_provider != NULL);
-       EP_ASSERT (_ep_rt_dotnet_mono_profiler_heap_collect_provider != NULL);
-
-       ep_rt_spin_lock_alloc (&_ep_rt_mono_profiler_gc_state_lock);
-
-       mono_profiler_set_runtime_initialized_callback (_ep_rt_default_profiler, profiler_eventpipe_runtime_initialized);
-       mono_profiler_set_thread_stopped_callback (_ep_rt_default_profiler, profiler_eventpipe_thread_exited);
-
-       MonoMethodSignature *method_signature = mono_metadata_signature_alloc (mono_get_corlib (), 1);
-       if (method_signature) {
-               method_signature->params[0] = m_class_get_byval_arg (mono_get_object_class());
-               method_signature->ret = m_class_get_byval_arg (mono_get_void_class());
-
-               ERROR_DECL (error);
-               MonoClass *runtime_helpers = mono_class_from_name_checked (mono_get_corlib (), "System.Runtime.CompilerServices", "RuntimeHelpers", error);
-               if (is_ok (error) && runtime_helpers) {
-                       MonoMethodBuilder *method_builder = mono_mb_new (runtime_helpers, "CompileMethod", MONO_WRAPPER_RUNTIME_INVOKE);
-                       if (method_builder) {
-                               _ep_rt_mono_runtime_helper_compile_method = mono_mb_create_method (method_builder, method_signature, 1);
-                               mono_mb_free (method_builder);
-                       }
-               }
-               mono_error_cleanup (error);
-               mono_metadata_free_method_signature (method_signature);
-
-               if (_ep_rt_mono_runtime_helper_compile_method) {
-                       _ep_rt_mono_runtime_helper_compile_method_jitinfo = (MonoJitInfo *)g_new0 (MonoJitInfo, 1);
-                       if (_ep_rt_mono_runtime_helper_compile_method) {
-                               _ep_rt_mono_runtime_helper_compile_method_jitinfo->code_start = MINI_FTNPTR_TO_ADDR (_ep_rt_mono_runtime_helper_compile_method);
-                               _ep_rt_mono_runtime_helper_compile_method_jitinfo->code_size = 20;
-                               _ep_rt_mono_runtime_helper_compile_method_jitinfo->d.method = _ep_rt_mono_runtime_helper_compile_method;
-                       }
-               }
-       }
-
-       {
-               ERROR_DECL (error);
-               MonoMethodDesc *desc = NULL;
-               MonoClass *monitor = mono_class_from_name_checked (mono_get_corlib (), "System.Threading", "Monitor", error);
-               if (is_ok (error) && monitor) {
-                       desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE);
-                       if (desc) {
-                               _ep_rt_mono_monitor_enter_v4_method = mono_method_desc_search_in_class (desc, monitor);
-                               mono_method_desc_free (desc);
-
-                               if (_ep_rt_mono_monitor_enter_v4_method) {
-                                       _ep_rt_mono_monitor_enter_v4_method_jitinfo = (MonoJitInfo *)g_new0 (MonoJitInfo, 1);
-                                       if (_ep_rt_mono_monitor_enter_v4_method_jitinfo) {
-                                               _ep_rt_mono_monitor_enter_v4_method_jitinfo->code_start = MINI_FTNPTR_TO_ADDR (_ep_rt_mono_monitor_enter_v4_method);
-                                               _ep_rt_mono_monitor_enter_v4_method_jitinfo->code_size = 20;
-                                               _ep_rt_mono_monitor_enter_v4_method_jitinfo->d.method = _ep_rt_mono_monitor_enter_v4_method;
-                                       }
-                               }
-                       }
-
-                       desc = mono_method_desc_new ("Monitor:Enter(object)", FALSE);
-                       if (desc) {
-                               _ep_rt_mono_monitor_enter_method = mono_method_desc_search_in_class (desc, monitor);
-                               mono_method_desc_free (desc);
-
-                               if (_ep_rt_mono_monitor_enter_method ) {
-                                       _ep_rt_mono_monitor_enter_method_jitinfo = (MonoJitInfo *)g_new0 (MonoJitInfo, 1);
-                                       if (_ep_rt_mono_monitor_enter_method_jitinfo) {
-                                               _ep_rt_mono_monitor_enter_method_jitinfo->code_start = MINI_FTNPTR_TO_ADDR (_ep_rt_mono_monitor_enter_method);
-                                               _ep_rt_mono_monitor_enter_method_jitinfo->code_size = 20;
-                                               _ep_rt_mono_monitor_enter_method_jitinfo->d.method = _ep_rt_mono_monitor_enter_method;
-                                       }
-                               }
-                       }
-               }
-               mono_error_cleanup (error);
-       }
-}
-
-void
-ep_rt_mono_init_finish (void)
-{
-       if (mono_runtime_get_no_exec ())
-               return;
-
-       // Managed init of diagnostics classes, like registration of RuntimeEventSource (if available).
-       ERROR_DECL (error);
-
-       MonoClass *runtime_event_source = mono_class_from_name_checked (mono_get_corlib (), "System.Diagnostics.Tracing", "RuntimeEventSource", error);
-       if (is_ok (error) && runtime_event_source) {
-               MonoMethod *init = mono_class_get_method_from_name_checked (runtime_event_source, "Initialize", -1, 0, error);
-               if (is_ok (error) && init) {
-                       mono_runtime_try_invoke_handle (init, NULL_HANDLE, NULL, error);
-               }
-       }
-
-       mono_error_cleanup (error);
-}
-
-void
-ep_rt_mono_fini (void)
-{
-       if (_ep_rt_mono_sampled_thread_callstacks)
-               g_array_free (_ep_rt_mono_sampled_thread_callstacks, TRUE);
-
-       if (_ep_rt_mono_initialized)
-               mono_rand_close (_ep_rt_mono_rand_provider);
-
-       g_free (_ep_rt_mono_runtime_helper_compile_method_jitinfo);
-       _ep_rt_mono_runtime_helper_compile_method_jitinfo = NULL;
-
-       mono_free_method (_ep_rt_mono_runtime_helper_compile_method);
-       _ep_rt_mono_runtime_helper_compile_method = NULL;
-
-       g_free (_ep_rt_mono_monitor_enter_method_jitinfo);
-       _ep_rt_mono_monitor_enter_method_jitinfo = NULL;
-       _ep_rt_mono_monitor_enter_method = NULL;
-
-       g_free (_ep_rt_mono_monitor_enter_v4_method_jitinfo);
-       _ep_rt_mono_monitor_enter_v4_method_jitinfo = NULL;
-       _ep_rt_mono_monitor_enter_v4_method = NULL;
-
-       if (_ep_rt_dotnet_mono_profiler_provider_callspec.enabled) {
-               mono_profiler_set_call_instrumentation_filter_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-               mono_callspec_cleanup (&_ep_rt_dotnet_mono_profiler_provider_callspec);
-       }
-
-       mono_profiler_free_gc_heap_collect_param_requests ();
-       mono_profiler_free_provider_params ();
-
-       ep_rt_spin_lock_free (&_ep_rt_mono_profiler_gc_state_lock);
-
-       _ep_rt_mono_sampled_thread_callstacks = NULL;
-       _ep_rt_mono_rand_provider = NULL;
-       _ep_rt_mono_initialized = FALSE;
-}
-
-bool
-ep_rt_mono_rand_try_get_bytes (
-       uint8_t *buffer,
-       size_t buffer_size)
-{
-       EP_ASSERT (_ep_rt_mono_rand_provider != NULL);
-
-       ERROR_DECL (error);
-       return mono_rand_try_get_bytes (&_ep_rt_mono_rand_provider, (guchar *)buffer, (gssize)buffer_size, error);
-}
-
-char *
-ep_rt_mono_get_managed_cmd_line (void)
-{
-       return mono_runtime_get_managed_cmd_line ();
-}
-
-char *
-ep_rt_mono_get_os_cmd_line (void)
-{
-       MONO_REQ_GC_NEUTRAL_MODE;
-
-       // we only return the native host here since getting the full commandline is complicated and
-       // it's not super important to have the correct value since it'll only be used during startup
-       // until we have the managed commandline
-       char *host_path = minipal_getexepath ();
-
-       // minipal_getexepath doesn't use Mono APIs to allocate strings so
-       // we can't use g_free (which the callers of this method expect to do)
-       // so create another copy and return that one
-       char *res = g_strdup (host_path);
-       free (host_path);
-       return res;
-}
-
-#ifdef HOST_WIN32
-
-ep_rt_file_handle_t
-ep_rt_mono_file_open_write (const ep_char8_t *path)
-{
-       if (!path)
-               return INVALID_HANDLE_VALUE;
-
-       ep_char16_t *path_utf16 = ep_rt_utf8_to_utf16le_string (path, -1);
-
-       if (!path_utf16)
-               return INVALID_HANDLE_VALUE;
-
-       ep_rt_file_handle_t res;
-       MONO_ENTER_GC_SAFE;
-       res = (ep_rt_file_handle_t)CreateFileW (path_utf16, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-       MONO_EXIT_GC_SAFE;
-       ep_rt_utf16_string_free (path_utf16);
-
-       return res;
-}
-
-bool
-ep_rt_mono_file_close (ep_rt_file_handle_t handle)
-{
-       bool res;
-       MONO_ENTER_GC_SAFE;
-       res = CloseHandle (handle);
-       MONO_EXIT_GC_SAFE;
-       return res;
-}
-
-static
-void
-win32_io_interrupt_handler (void *ignored)
-{
-}
-
-bool
-ep_rt_mono_file_write (
-       ep_rt_file_handle_t handle,
-       const uint8_t *buffer,
-       uint32_t numbytes,
-       uint32_t *byteswritten)
-{
-       MONO_REQ_GC_UNSAFE_MODE;
-
-       bool res;
-       MonoThreadInfo *info = mono_thread_info_current ();
-       gboolean alerted = FALSE;
-
-       if (info) {
-               mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted);
-               if (alerted) {
-                       return false;
-               }
-               mono_win32_enter_blocking_io_call (info, handle);
-       }
-
-       MONO_ENTER_GC_SAFE;
-       if (info && mono_thread_info_is_interrupt_state (info)) {
-               res = false;
-       } else {
-               res = WriteFile (handle, buffer, numbytes, (PDWORD)byteswritten, NULL) ? true : false;
-       }
-       MONO_EXIT_GC_SAFE;
-
-       if (info) {
-               mono_win32_leave_blocking_io_call (info, handle);
-               mono_thread_info_uninstall_interrupt (&alerted);
-       }
-
-       return res;
-}
-
-#else
-
-#include <fcntl.h>
-#include <unistd.h>
-
-ep_rt_file_handle_t
-ep_rt_mono_file_open_write (const ep_char8_t *path)
-{
-       int fd;
-       mode_t perms = 0666;
-
-       if (!path)
-               return INVALID_HANDLE_VALUE;
-
-       MONO_ENTER_GC_SAFE;
-       fd = creat (path, perms);
-       MONO_EXIT_GC_SAFE;
-
-       if (fd == -1)
-               return INVALID_HANDLE_VALUE;
-
-       return (ep_rt_file_handle_t)(ptrdiff_t)fd;
-}
-
-bool
-ep_rt_mono_file_close (ep_rt_file_handle_t handle)
-{
-       int fd = (int)(ptrdiff_t)handle;
-
-       MONO_ENTER_GC_SAFE;
-       close (fd);
-       MONO_EXIT_GC_SAFE;
-
-       return true;
-}
-
-bool
-ep_rt_mono_file_write (
-       ep_rt_file_handle_t handle,
-       const uint8_t *buffer,
-       uint32_t numbytes,
-       uint32_t *byteswritten)
-{
-       MONO_REQ_GC_UNSAFE_MODE;
-
-       int fd = (int)(ptrdiff_t)handle;
-       uint32_t ret;
-       MonoThreadInfo *info = mono_thread_info_current ();
-
-       if (byteswritten != NULL)
-               *byteswritten = 0;
-
-       do {
-               MONO_ENTER_GC_SAFE;
-               ret = write (fd, buffer, numbytes);
-               MONO_EXIT_GC_SAFE;
-       } while (ret == -1 && errno == EINTR &&
-                !mono_thread_info_is_interrupt_state (info));
-
-       if (ret == -1) {
-               if (errno == EINTR)
-                       ret = 0;
-               else
-                       return false;
-       }
-
-       if (byteswritten != NULL)
-               *byteswritten = ret;
-
-       return true;
-}
-
-#endif // HOST_WIN32
-
-EventPipeThread *
-ep_rt_mono_thread_get_or_create (void)
-{
-       EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (_ep_rt_mono_thread_holder_tls_id);
-       if (!thread_holder) {
-               thread_holder = thread_holder_alloc_func ();
-               mono_native_tls_set_value (_ep_rt_mono_thread_holder_tls_id, thread_holder);
-       }
-       return ep_thread_holder_get_thread (thread_holder);
-}
-
-void *
-ep_rt_mono_thread_attach (bool background_thread)
-{
-       MonoThread *thread = NULL;
-
-       // NOTE, under netcore, only root domain exists.
-       if (!mono_thread_current ()) {
-               thread = mono_thread_internal_attach (mono_get_root_domain ());
-               if (background_thread && thread) {
-                       mono_thread_set_state (thread, ThreadState_Background);
-                       mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_SAMPLE);
-               }
-       }
-
-       return thread;
-}
-
-void *
-ep_rt_mono_thread_attach_2 (bool background_thread, EventPipeThreadType thread_type)
-{
-       void *result = ep_rt_mono_thread_attach (background_thread);
-       if (result && thread_type == EP_THREAD_TYPE_SAMPLING) {
-               // Increase sampling thread priority, accepting failures.
-#ifdef HOST_WIN32
-               SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
-#elif _POSIX_PRIORITY_SCHEDULING
-               int policy;
-               int priority;
-               struct sched_param param;
-               int schedparam_result = pthread_getschedparam (pthread_self (), &policy, &param);
-               if (schedparam_result == 0) {
-                       // Attempt to switch the thread to real time scheduling. This will not
-                       // necessarily work on all OSs; for example, most Linux systems will give
-                       // us EPERM here unless configured to allow this.
-                       priority = param.sched_priority;
-                       param.sched_priority = sched_get_priority_max (SCHED_RR);
-                       if (param.sched_priority != -1) {
-                               schedparam_result = pthread_setschedparam (pthread_self (), SCHED_RR, &param);
-                               if (schedparam_result != 0) {
-                                       // Fallback, attempt to increase to max priority using current policy.
-                                       param.sched_priority = sched_get_priority_max (policy);
-                                       if (param.sched_priority != -1 && param.sched_priority != priority)
-                                               pthread_setschedparam (pthread_self (), policy, &param);
-                               }
-                       }
-               }
-#endif
-       }
-
-       return result;
-}
-
-void
-ep_rt_mono_thread_detach (void)
-{
-       MonoThread *current_thread = mono_thread_current ();
-       if (current_thread)
-               mono_thread_internal_detach (current_thread);
-}
-
-void
-ep_rt_mono_thread_exited (void)
-{
-       if (_ep_rt_mono_initialized) {
-               EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (_ep_rt_mono_thread_holder_tls_id);
-               if (thread_holder)
-                       thread_holder_free_func (thread_holder);
-               mono_native_tls_set_value (_ep_rt_mono_thread_holder_tls_id, NULL);
-
-               EventPipeThreadData *thread_data = (EventPipeThreadData *)mono_native_tls_get_value (_ep_rt_mono_thread_data_tls_id);
-               if (thread_data)
-                       eventpipe_thread_data_free (thread_data);
-               mono_native_tls_set_value (_ep_rt_mono_thread_data_tls_id, NULL);
-       }
-}
-
-#ifdef HOST_WIN32
-int64_t
-ep_rt_mono_perf_counter_query (void)
-{
-       LARGE_INTEGER value;
-       if (QueryPerformanceCounter (&value))
-               return (int64_t)value.QuadPart;
-       else
-               return 0;
-}
-
-int64_t
-ep_rt_mono_perf_frequency_query (void)
-{
-       LARGE_INTEGER value;
-       if (QueryPerformanceFrequency (&value))
-               return (int64_t)value.QuadPart;
-       else
-               return 0;
-}
-
-void
-ep_rt_mono_system_time_get (EventPipeSystemTime *system_time)
-{
-       SYSTEMTIME value;
-       GetSystemTime (&value);
-
-       EP_ASSERT (system_time != NULL);
-       ep_system_time_set (
-               system_time,
-               value.wYear,
-               value.wMonth,
-               value.wDayOfWeek,
-               value.wDay,
-               value.wHour,
-               value.wMinute,
-               value.wSecond,
-               value.wMilliseconds);
-}
-
-int64_t
-ep_rt_mono_system_timestamp_get (void)
-{
-       FILETIME value;
-       GetSystemTimeAsFileTime (&value);
-       return (int64_t)((((uint64_t)value.dwHighDateTime) << 32) | (uint64_t)value.dwLowDateTime);
-}
-#else
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <utime.h>
-#include <time.h>
-
-#if HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif // HAVE_SYS_TIME_H
-
-#if HAVE_MACH_ABSOLUTE_TIME
-#include <mach/mach_time.h>
-static mono_lazy_init_t _ep_rt_mono_time_base_info_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
-static mach_timebase_info_data_t _ep_rt_mono_time_base_info = {0};
-#endif
-
-#ifdef HAVE_LOCALTIME_R
-#define HAVE_GMTIME_R 1
-#endif
-
-static const int64_t SECS_BETWEEN_1601_AND_1970_EPOCHS = 11644473600LL;
-static const int64_t SECS_TO_100NS = 10000000;
-static const int64_t SECS_TO_NS = 1000000000;
-static const int64_t MSECS_TO_MIS = 1000;
-
-/* clock_gettime () is found by configure on Apple builds, but its only present from ios 10, macos 10.12, tvos 10 and watchos 3 */
-#if defined (HAVE_CLOCK_MONOTONIC) && (defined(HOST_IOS) || defined(HOST_OSX) || defined(HOST_WATCHOS) || defined(HOST_TVOS))
-#undef HAVE_CLOCK_MONOTONIC
-#endif
-
-#ifndef HAVE_CLOCK_MONOTONIC
-static const int64_t MISECS_TO_NS = 1000;
-#endif
-
-static
-void
-time_base_info_lazy_init (void);
-
-static
-int64_t
-system_time_to_int64 (
-       time_t sec,
-       long nsec);
-
-#if HAVE_MACH_ABSOLUTE_TIME
-static
-void
-time_base_info_lazy_init (void)
-{
-       kern_return_t result = mach_timebase_info (&_ep_rt_mono_time_base_info);
-       if (result != KERN_SUCCESS)
-               memset (&_ep_rt_mono_time_base_info, 0, sizeof (_ep_rt_mono_time_base_info));
-}
-#endif
-
-int64_t
-ep_rt_mono_perf_counter_query (void)
-{
-#if HAVE_MACH_ABSOLUTE_TIME
-       return (int64_t)mach_absolute_time ();
-#elif HAVE_CLOCK_MONOTONIC
-       struct timespec ts;
-       int result = clock_gettime (CLOCK_MONOTONIC, &ts);
-       if (result == 0)
-               return ((int64_t)(ts.tv_sec) * (int64_t)(SECS_TO_NS)) + (int64_t)(ts.tv_nsec);
-#else
-       #error "ep_rt_mono_perf_counter_get requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported."
-#endif
-       return 0;
-}
-
-int64_t
-ep_rt_mono_perf_frequency_query (void)
-{
-#if HAVE_MACH_ABSOLUTE_TIME
-       // (numer / denom) gives you the nanoseconds per tick, so the below code
-       // computes the number of ticks per second. We explicitly do the multiplication
-       // first in order to help minimize the error that is produced by integer division.
-       mono_lazy_initialize (&_ep_rt_mono_time_base_info_init, time_base_info_lazy_init);
-       if (_ep_rt_mono_time_base_info.denom == 0 || _ep_rt_mono_time_base_info.numer == 0)
-               return 0;
-       return ((int64_t)(SECS_TO_NS) * (int64_t)(_ep_rt_mono_time_base_info.denom)) / (int64_t)(_ep_rt_mono_time_base_info.numer);
-#elif HAVE_CLOCK_MONOTONIC
-       // clock_gettime () returns a result in terms of nanoseconds rather than a count. This
-       // means that we need to either always scale the result by the actual resolution (to
-       // get a count) or we need to say the resolution is in terms of nanoseconds. We prefer
-       // the latter since it allows the highest throughput and should minimize error propagated
-       // to the user.
-       return (int64_t)(SECS_TO_NS);
-#else
-       #error "ep_rt_mono_perf_frequency_query requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported."
-#endif
-       return 0;
-}
-
-void
-ep_rt_mono_system_time_get (EventPipeSystemTime *system_time)
-{
-       time_t tt;
-#if HAVE_GMTIME_R
-       struct tm ut;
-#endif /* HAVE_GMTIME_R */
-       struct tm *ut_ptr;
-       struct timeval time_val;
-       int timeofday_retval;
-
-       EP_ASSERT (system_time != NULL);
-
-       tt = time (NULL);
-
-       /* We can't get millisecond resolution from time (), so we get it from gettimeofday () */
-       timeofday_retval = gettimeofday (&time_val, NULL);
-
-#if HAVE_GMTIME_R
-       ut_ptr = &ut;
-       if (gmtime_r (&tt, ut_ptr) == NULL)
-#else /* HAVE_GMTIME_R */
-       if ((ut_ptr = gmtime (&tt)) == NULL)
-#endif /* HAVE_GMTIME_R */
-               EP_UNREACHABLE ();
-
-       uint16_t milliseconds = 0;
-       if (timeofday_retval != -1) {
-               int old_seconds;
-               int new_seconds;
-
-               milliseconds = (uint16_t)(time_val.tv_usec / MSECS_TO_MIS);
-
-               old_seconds = ut_ptr->tm_sec;
-               new_seconds = time_val.tv_sec % 60;
-
-               /* just in case we reached the next second in the interval between time () and gettimeofday () */
-               if (old_seconds != new_seconds)
-                       milliseconds = 999;
-       }
-
-       ep_system_time_set (
-               system_time,
-               (uint16_t)(1900 + ut_ptr->tm_year),
-               (uint16_t)ut_ptr->tm_mon + 1,
-               (uint16_t)ut_ptr->tm_wday,
-               (uint16_t)ut_ptr->tm_mday,
-               (uint16_t)ut_ptr->tm_hour,
-               (uint16_t)ut_ptr->tm_min,
-               (uint16_t)ut_ptr->tm_sec,
-               milliseconds);
-}
-
-static
-inline
-int64_t
-system_time_to_int64 (
-       time_t sec,
-       long nsec)
-{
-       return ((int64_t)sec + SECS_BETWEEN_1601_AND_1970_EPOCHS) * SECS_TO_100NS + (nsec / 100);
-}
-
-int64_t
-ep_rt_mono_system_timestamp_get (void)
-{
-#if HAVE_CLOCK_MONOTONIC
-       struct timespec time;
-       if (clock_gettime (CLOCK_REALTIME, &time) == 0)
-               return system_time_to_int64 (time.tv_sec, time.tv_nsec);
-#else
-       struct timeval time;
-       if (gettimeofday (&time, NULL) == 0)
-               return system_time_to_int64 (time.tv_sec, time.tv_usec * MISECS_TO_NS);
-#endif
-       else
-               return system_time_to_int64 (0, 0);
-}
-#endif
-
-#ifndef HOST_WIN32
-#if defined(__APPLE__)
-#if defined (HOST_OSX)
-G_BEGIN_DECLS
-gchar ***_NSGetEnviron(void);
-G_END_DECLS
-#define environ (*_NSGetEnviron())
-#else
-static char *_ep_rt_mono_environ[1] = { NULL };
-#define environ _ep_rt_mono_environ
-#endif /* defined (HOST_OSX) */
-#else
-G_BEGIN_DECLS
-extern char **environ;
-G_END_DECLS
-#endif /* defined (__APPLE__) */
-#endif /* !defined (HOST_WIN32) */
-
-void
-ep_rt_mono_os_environment_get_utf16 (dn_vector_ptr_t *os_env)
-{
-       EP_ASSERT (os_env != NULL);
-#ifdef HOST_WIN32
-       LPWSTR envs = GetEnvironmentStringsW ();
-       if (envs) {
-               LPWSTR next = envs;
-               while (*next) {
-                       dn_vector_ptr_push_back (os_env, ep_rt_utf16_string_dup (next));
-                       next += ep_rt_utf16_string_len (next) + 1;
-               }
-               FreeEnvironmentStringsW (envs);
-       }
-#else
-       gchar **next = NULL;
-       for (next = environ; *next != NULL; ++next)
-               dn_vector_ptr_push_back (os_env, ep_rt_utf8_to_utf16le_string (*next, -1));
-#endif
-}
-
-void
-ep_rt_mono_init_providers_and_events (void)
-{
-       InitProvidersAndEvents ();
-}
-
-void
-ep_rt_mono_provider_config_init (EventPipeProviderConfiguration *provider_config)
-{
-       if (!ep_rt_utf8_string_compare (ep_config_get_rundown_provider_name_utf8 (), ep_provider_config_get_provider_name (provider_config))) {
-               MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.Level = (uint8_t)ep_provider_config_get_logging_level (provider_config);
-               MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = ep_provider_config_get_keywords (provider_config);
-               MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.IsEnabled = true;
-       }
-}
-
-bool
-ep_rt_mono_providers_validate_all_disabled (void)
-{
-       return (!MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.IsEnabled &&
-               !MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context.IsEnabled &&
-               !MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.IsEnabled &&
-               !MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.IsEnabled);
-}
-
-void
-ep_rt_mono_fini_providers_and_events (void)
-{
-       // dotnet/runtime: issue 12775: EventPipe shutdown race conditions
-       // Deallocating providers/events here might cause AV if a WriteEvent
-       // was to occur. Thus, we are not doing this cleanup.
-}
-
-bool
-ep_rt_mono_walk_managed_stack_for_thread (
-       ep_rt_thread_handle_t thread,
-       EventPipeStackContents *stack_contents)
-{
-       EP_ASSERT (thread != NULL && stack_contents != NULL);
-
-       EventPipeStackWalkData stack_walk_data;
-       stack_walk_data.stack_contents = stack_contents;
-       stack_walk_data.top_frame = true;
-       stack_walk_data.async_frame = false;
-       stack_walk_data.safe_point_frame = false;
-       stack_walk_data.runtime_invoke_frame = false;
-
-       bool restore_async_context = FALSE;
-       bool prevent_profiler_event_recursion = FALSE;
-       EventPipeThreadData *thread_data = eventpipe_thread_data_get_or_create ();
-       if (thread_data) {
-               prevent_profiler_event_recursion = thread_data->prevent_profiler_event_recursion;
-               if (prevent_profiler_event_recursion && !mono_thread_info_is_async_context ()) {
-                       // Running stackwalk in async context mode is currently the only way to prevent
-                       // unwinder to NOT load additional classes during stackwalk, making it signal unsafe and
-                       // potential triggering uncontrolled recursion in profiler class loading event.
-                       mono_thread_info_set_is_async_context (TRUE);
-                       restore_async_context = TRUE;
-               }
-               thread_data->prevent_profiler_event_recursion = TRUE;
-       }
-
-       if (thread == ep_rt_thread_get_handle () && mono_get_eh_callbacks ()->mono_walk_stack_with_ctx)
-               mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (eventpipe_walk_managed_stack_for_thread_func, NULL, MONO_UNWIND_SIGNAL_SAFE, &stack_walk_data);
-       else if (mono_get_eh_callbacks ()->mono_walk_stack_with_state)
-               mono_get_eh_callbacks ()->mono_walk_stack_with_state (eventpipe_walk_managed_stack_for_thread_func, mono_thread_info_get_suspend_state (thread), MONO_UNWIND_SIGNAL_SAFE, &stack_walk_data);
-
-       if (thread_data) {
-               if (restore_async_context)
-                       mono_thread_info_set_is_async_context (FALSE);
-               thread_data->prevent_profiler_event_recursion = prevent_profiler_event_recursion;
-       }
-
-       return true;
-}
-
-bool
-ep_rt_mono_method_get_simple_assembly_name (
-       ep_rt_method_desc_t *method,
-       ep_char8_t *name,
-       size_t name_len)
-{
-       EP_ASSERT (method != NULL);
-       EP_ASSERT (name != NULL);
-
-       MonoClass *method_class = mono_method_get_class (method);
-       MonoImage *method_image = method_class ? mono_class_get_image (method_class) : NULL;
-       const ep_char8_t *assembly_name = method_image ? mono_image_get_name (method_image) : NULL;
-
-       if (!assembly_name)
-               return false;
-
-       g_strlcpy (name, assembly_name, name_len);
-       return true;
-}
-
-bool
-ep_rt_mono_method_get_full_name (
-       ep_rt_method_desc_t *method,
-       ep_char8_t *name,
-       size_t name_len)
-{
-       EP_ASSERT (method != NULL);
-       EP_ASSERT (name != NULL);
-
-       char *full_method_name = mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL);
-       if (!full_method_name)
-               return false;
-
-       g_strlcpy (name, full_method_name, name_len);
-
-       g_free (full_method_name);
-       return true;
-}
-
-bool
-ep_rt_mono_sample_profiler_write_sampling_event_for_threads (
-       ep_rt_thread_handle_t sampling_thread,
-       EventPipeEvent *sampling_event)
-{
-       // Follows CoreClr implementation of sample profiler. Generic invasive/expensive way to do CPU sample profiling relying on STW and stackwalks.
-       // TODO: Investigate alternatives on platforms supporting Signals/SuspendThread (see Mono profiler) or CPU PMU's (see ETW/perf_event_open).
-
-       // Sample profiler only runs on one thread, no need to synchorinize.
-       if (!_ep_rt_mono_sampled_thread_callstacks)
-               _ep_rt_mono_sampled_thread_callstacks = g_array_sized_new (FALSE, FALSE, sizeof (EventPipeSampleProfileStackWalkData), _ep_rt_mono_max_sampled_thread_count);
-
-       // Make sure there is room based on previous max number of sampled threads.
-       // NOTE, there is a chance there are more threads than max, if that's the case we will
-       // miss those threads in this sample, but will be included in next when max has been adjusted.
-       g_array_set_size (_ep_rt_mono_sampled_thread_callstacks, _ep_rt_mono_max_sampled_thread_count);
-
-       uint32_t filtered_thread_count = 0;
-       uint32_t sampled_thread_count = 0;
-
-       mono_stop_world (MONO_THREAD_INFO_FLAGS_NO_GC);
-
-       bool restore_async_context = FALSE;
-       if (!mono_thread_info_is_async_context ()) {
-               mono_thread_info_set_is_async_context (TRUE);
-               restore_async_context = TRUE;
-       }
-
-       // Record all info needed in sample events while runtime is suspended, must be async safe.
-       FOREACH_THREAD_SAFE_EXCLUDE (thread_info, MONO_THREAD_INFO_FLAGS_NO_GC | MONO_THREAD_INFO_FLAGS_NO_SAMPLE) {
-               if (!mono_thread_info_is_running (thread_info)) {
-                       MonoThreadUnwindState *thread_state = mono_thread_info_get_suspend_state (thread_info);
-                       if (thread_state->valid) {
-                               if (sampled_thread_count < _ep_rt_mono_max_sampled_thread_count) {
-                                       EventPipeSampleProfileStackWalkData *data = &g_array_index (_ep_rt_mono_sampled_thread_callstacks, EventPipeSampleProfileStackWalkData, sampled_thread_count);
-                                       data->thread_id = ep_rt_thread_id_t_to_uint64_t (mono_thread_info_get_tid (thread_info));
-                                       data->thread_ip = (uintptr_t)MONO_CONTEXT_GET_IP (&thread_state->ctx);
-                                       data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR;
-                                       data->stack_walk_data.stack_contents = &data->stack_contents;
-                                       data->stack_walk_data.top_frame = true;
-                                       data->stack_walk_data.async_frame = false;
-                                       data->stack_walk_data.safe_point_frame = false;
-                                       data->stack_walk_data.runtime_invoke_frame = false;
-                                       ep_stack_contents_reset (&data->stack_contents);
-                                       mono_get_eh_callbacks ()->mono_walk_stack_with_state (eventpipe_sample_profiler_walk_managed_stack_for_thread_func, thread_state, MONO_UNWIND_SIGNAL_SAFE, data);
-                                       if (data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL && (data->stack_walk_data.safe_point_frame || data->stack_walk_data.runtime_invoke_frame)) {
-                                               // If classified as external code (managed->native frame on top of stack), but have a safe point or runtime invoke frame
-                                               // as second, re-classify current callstack to be executing managed code.
-                                               data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED;
-                                       }
-                                       if (data->stack_walk_data.top_frame && ep_stack_contents_get_length (&data->stack_contents) == 0) {
-                                               // If no managed frames (including helper frames) are located on stack, mark sample as beginning in external code.
-                                               // This can happen on attached embedding threads returning to native code between runtime invokes.
-                                               // Make sure sample is still written into EventPipe for all attached threads even if they are currently not having
-                                               // any managed frames on stack. Prevents some tools applying thread time heuristics to prolong duration of last sample
-                                               // when embedding thread returns to native code. It also opens ability to visualize number of samples in unmanaged code
-                                               // on attached threads when executing outside of runtime. If tooling is not interested in these sample events, they are easy
-                                               // to identify and filter out.
-                                               data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL;
-                                       }
-
-                                       sampled_thread_count++;
-                               }
-                       }
-               }
-               filtered_thread_count++;
-       } FOREACH_THREAD_SAFE_END
-
-       if (restore_async_context)
-               mono_thread_info_set_is_async_context (FALSE);
-
-       mono_restart_world (MONO_THREAD_INFO_FLAGS_NO_GC);
-
-       // Fire sample event for threads. Must be done after runtime is resumed since it's not async safe.
-       // Since we can't keep thread info around after runtime as been suspended, use an empty
-       // adapter instance and only set recorded tid as parameter inside adapter.
-       THREAD_INFO_TYPE adapter = { { 0 } };
-       for (uint32_t thread_count = 0; thread_count < sampled_thread_count; ++thread_count) {
-               EventPipeSampleProfileStackWalkData *data = &g_array_index (_ep_rt_mono_sampled_thread_callstacks, EventPipeSampleProfileStackWalkData, thread_count);
-               if ((data->stack_walk_data.top_frame && data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL) || (data->payload_data != EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR && ep_stack_contents_get_length (&data->stack_contents) > 0)) {
-                       // Check if we have an async frame, if so we will need to make sure all frames are registered in regular jit info table.
-                       // TODO: An async frame can contain wrapper methods (no way to check during stackwalk), we could skip writing profile event
-                       // for this specific stackwalk or we could cleanup stack_frames before writing profile event.
-                       if (data->stack_walk_data.async_frame) {
-                               for (uint32_t frame_count = 0; frame_count < data->stack_contents.next_available_frame; ++frame_count)
-                                       mono_jit_info_table_find_internal ((gpointer)data->stack_contents.stack_frames [frame_count], TRUE, FALSE);
-                       }
-                       mono_thread_info_set_tid (&adapter, ep_rt_uint64_t_to_thread_id_t (data->thread_id));
-                       uint32_t payload_data = ep_rt_val_uint32_t (data->payload_data);
-                       ep_write_sample_profile_event (sampling_thread, sampling_event, &adapter, &data->stack_contents, (uint8_t *)&payload_data, sizeof (payload_data));
-               }
-       }
-
-       // Current thread count will be our next maximum sampled threads.
-       _ep_rt_mono_max_sampled_thread_count = filtered_thread_count;
-
-       return true;
-}
-
-void
-ep_rt_mono_execute_rundown (dn_vector_ptr_t *execution_checkpoints)
-{
-       ep_char8_t runtime_module_path [256];
-       const uint8_t object_guid [EP_GUID_SIZE] = { 0 };
-       const uint16_t runtime_product_qfe_version = 0;
-       const uint8_t startup_flags = 0;
-       const uint8_t startup_mode = 0;
-       const ep_char8_t *command_line = "";
-
-       if (!g_module_address ((void *)mono_init, runtime_module_path, sizeof (runtime_module_path), NULL, NULL, 0, NULL))
-               runtime_module_path [0] = '\0';
-
-       FireEtwRuntimeInformationDCStart (
-               clr_instance_get_id (),
-               RUNTIME_SKU_MONO,
-               RuntimeProductMajorVersion,
-               RuntimeProductMinorVersion,
-               RuntimeProductPatchVersion,
-               runtime_product_qfe_version,
-               RuntimeFileMajorVersion,
-               RuntimeFileMajorVersion,
-               RuntimeFileBuildVersion,
-               RuntimeFileRevisionVersion,
-               startup_mode,
-               startup_flags,
-               command_line,
-               object_guid,
-               runtime_module_path,
-               NULL,
-               NULL);
-
-       if (execution_checkpoints) {
-               DN_VECTOR_PTR_FOREACH_BEGIN (EventPipeExecutionCheckpoint *, checkpoint, execution_checkpoints) {
-                       FireEtwExecutionCheckpointDCEnd (
-                               clr_instance_get_id (),
-                               checkpoint->name,
-                               checkpoint->timestamp,
-                               NULL,
-                               NULL);
-               } DN_VECTOR_PTR_FOREACH_END;
-       }
-
-       FireEtwDCEndInit_V1 (
-               clr_instance_get_id (),
-               NULL,
-               NULL);
-
-       eventpipe_execute_rundown (
-               fire_domain_rundown_events_func,
-               fire_assembly_rundown_events_func,
-               fire_method_rundown_events_func);
-
-       FireEtwDCEndComplete_V1 (
-               clr_instance_get_id (),
-               NULL,
-               NULL);
-}
-
-bool
-ep_rt_mono_write_event_ee_startup_start (void)
-{
-       return FireEtwEEStartupStart_V1 (
-               clr_instance_get_id (),
-               NULL,
-               NULL);
-}
-
-#define STACK_ALLOC 256
-
-// The maximum number of type parameters for a BulkTypeValue instance
-// Aligned with coreCLR StackSArray<ULONGLONG> rgTypeParameters
-#define INIT_SIZE_OF_TYPE_PARAMETER_ARRAY ((uint32_t)(STACK_ALLOC / sizeof (intptr_t)))
-
-// !!!!!!! NOTE !!!!!!!!
-// The flags must match those in the ETW manifest exactly
-// !!!!!!! NOTE !!!!!!!!
-
-typedef enum {
-       TYPE_FLAGS_DELEGATE = 0x1,
-       TYPE_FLAGS_FINALIZABLE = 0x2,
-       TYPE_FLAGS_EXTERNALLY_IMPLEMENTED_COM_OBJECT = 0x4,
-       TYPE_FLAGS_ARRAY = 0x8,
-
-       TYPE_FLAGS_ARRAY_RANK_MASK = 0x3F00,
-       TYPE_FLAGS_ARRAY_RANK_SHIFT = 8,
-       TYPE_FLAGS_ARRAY_RANK_MAX = TYPE_FLAGS_ARRAY_RANK_MASK >> TYPE_FLAGS_ARRAY_RANK_SHIFT
-} TypeFlags;
-
-// This only contains the fixed-size data at the top of each struct in
-// the bulk type event.  These fields must still match exactly the initial
-// fields of the struct described in the manifest.
-typedef struct _EventStructBulkTypeFixedSizedData {
-       uint64_t type_id;
-       uint64_t module_id;
-       uint32_t type_name_id;
-       uint32_t flags;
-       uint8_t cor_element_type;
-} EventStructBulkTypeFixedSizedData;
-
-// Represents one instance of the Value struct inside a single BulkType event
-typedef struct _BulkTypeValue {
-       EventStructBulkTypeFixedSizedData fixed_sized_data;
-       uint32_t type_parameters_count;
-       MonoType **mono_type_parameters;
-       ep_char8_t *name; // Currently should only be NULL, TODO if we want to provide the name in the BulkTypeEvent data, figure out memory management to use
-} BulkTypeValue;
-
-static
-void
-ep_rt_bulk_type_value_clear (BulkTypeValue *bulk_type_value);
-
-static
-int
-ep_rt_mono_get_byte_count_in_event (BulkTypeValue *bulk_type_value);
-
-static
-BulkTypeEventLogger*
-ep_rt_bulk_type_event_logger_alloc (void);
-
-static
-void
-ep_rt_bulk_type_event_logger_free (BulkTypeEventLogger *type_logger);
-
-static
-int
-write_event_buffer (
-       const uint8_t *val,
-       int size,
-       char *buf_start,
-       char **buf_next);
-
-static
-int
-write_event_buffer_int8 (
-       int8_t val,
-       char *buf_start,
-       char **buf_next);
-
-static
-int
-write_event_buffer_int16 (
-       int16_t val,
-       char *buf_start,
-       char **buf_next);
-
-static
-int
-write_event_buffer_int32 (
-       int32_t val,
-       char *buf_start,
-       char **buf_next);
-
-static
-int
-write_event_buffer_int64 (
-       int64_t val,
-       char *buf_start,
-       char **buf_next);
-
-static
-uint64_t
-get_typeid_for_type (MonoType *t);
-
-static
-uint64_t
-get_typeid_for_class (MonoClass *c);
-
-// Clear out BulkTypeValue before filling it out (array elements can get reused if there
-// are enough types that we need to flush to multiple events).
-static
-void
-ep_rt_bulk_type_value_clear (BulkTypeValue *bulk_type_value)
-{
-       memset (bulk_type_value, 0, sizeof(BulkTypeValue));
-}
-
-static
-int
-ep_rt_mono_get_byte_count_in_event (BulkTypeValue *bulk_type_value)
-{
-       int name_len = 0;
-
-       return sizeof (bulk_type_value->fixed_sized_data.type_id) +     // Fixed Sized Data
-               sizeof (bulk_type_value->fixed_sized_data.module_id) +
-               sizeof (bulk_type_value->fixed_sized_data.type_name_id) +
-               sizeof (bulk_type_value->fixed_sized_data.flags) +
-               sizeof (bulk_type_value->fixed_sized_data.cor_element_type) +
-               sizeof (bulk_type_value->type_parameters_count) +               // Type parameters
-               (name_len + 1) * sizeof (ep_char8_t) +          // Size of name, including null terminator
-               bulk_type_value->type_parameters_count * sizeof (uint64_t);     // Type parameters
-}
-
-// ETW has a limitation of 64K for TOTAL event Size, however there is overhead associated with
-// the event headers.   It is unclear exactly how much that is, but 1K should be sufficiently
-// far away to avoid problems without sacrificing the perf of bulk processing.
-#define MAX_EVENT_BYTE_COUNT (63 * 1024)
-
-// The maximum event size, and the size of the buffer that we allocate to hold the event contents.
-#define MAX_SIZE_OF_EVENT_BUFFER 65536
-
-// Estimate of how many bytes we can squeeze in the event data for the value struct
-// array. (Intentionally overestimate the size of the non-array parts to keep it safe.)
-// This follows CoreCLR's kMaxBytesTypeValues.
-#define MAX_TYPE_VALUES_BYTES (MAX_EVENT_BYTE_COUNT - 0x30)
-
-// Estimate of how many type value elements we can put into the struct array, while
-// staying under the ETW event size limit. Note that this is impossible to calculate
-// perfectly, since each element of the struct array has variable size.
-//
-// In addition to the byte-size limit per event, Windows always forces on us a
-// max-number-of-descriptors per event, which in the case of BulkType, will kick in
-// far sooner. There's a max number of 128 descriptors allowed per event. 2 are used
-// for Count + ClrInstanceID. Then 4 per batched value. (Might actually be 3 if there
-// are no type parameters to log, but let's overestimate at 4 per value).
-#define K_MAX_COUNT_TYPE_VALUES ((uint32_t)(128 - 2) / 4)
-
-struct _BulkTypeEventLogger {
-       BulkTypeValue bulk_type_values [K_MAX_COUNT_TYPE_VALUES];
-       uint8_t *bulk_type_event_buffer;
-       uint32_t bulk_type_value_count;
-       uint32_t bulk_type_value_byte_count;
-       MonoMemPool *mem_pool;
-};
-
-static
-BulkTypeEventLogger*
-ep_rt_bulk_type_event_logger_alloc (void)
-{
-       BulkTypeEventLogger *type_logger = g_malloc0 (sizeof (BulkTypeEventLogger));
-       type_logger->bulk_type_event_buffer = g_malloc0 (sizeof (uint8_t) * MAX_SIZE_OF_EVENT_BUFFER);
-       type_logger->mem_pool = mono_mempool_new ();
-       return type_logger;
-}
-
-static
-void
-ep_rt_bulk_type_event_logger_free (BulkTypeEventLogger *type_logger)
-{
-       mono_mempool_destroy (type_logger->mem_pool);
-       g_free (type_logger->bulk_type_event_buffer);
-       g_free (type_logger);
-}
-
-static
-int
-write_event_buffer (
-       const uint8_t *val,
-       int size,
-       char *buf_start,
-       char **buf_next)
-{
-       memcpy (buf_start, val, size);
-       *buf_next = buf_start + size;
-       return size;
-}
-
-static
-int
-write_event_buffer_int8 (
-       int8_t val,
-       char *buf_start,
-       char **buf_next)
-{
-       return write_event_buffer ((const uint8_t *)&val, sizeof (int8_t), buf_start, buf_next);
-}
-
-static
-int
-write_event_buffer_int16 (
-       int16_t val,
-       char *buf_start,
-       char **buf_next)
-{
-       return write_event_buffer ((const uint8_t *)&val, sizeof (int16_t), buf_start, buf_next);
-}
-
-static
-int
-write_event_buffer_int32 (
-       int32_t val,
-       char *buf_start,
-       char **buf_next)
-{
-       return write_event_buffer ((const uint8_t *)&val, sizeof (int32_t), buf_start, buf_next);
-}
-
-static
-int
-write_event_buffer_int64 (
-       int64_t val,
-       char *buf_start,
-       char **buf_next)
-{
-       return write_event_buffer ((const uint8_t *)&val, sizeof (int64_t), buf_start, buf_next);
-}
-
-//---------------------------------------------------------------------------------------
-//
-// ep_rt_mono_fire_bulk_type_event fires an ETW event for all the types batched so far,
-// it then resets the state to start batching new types at the beginning of the
-// bulk_type_values array.
-//
-// This follows CoreCLR's BulkTypeEventLogger::FireBulkTypeEvent
-
-void
-ep_rt_mono_fire_bulk_type_event (BulkTypeEventLogger *type_logger)
-{
-       if (type_logger->bulk_type_value_count == 0)
-               return;
-
-       uint16_t clr_instance_id = clr_instance_get_id ();
-
-       uint32_t values_element_size = 0;
-
-       uint8_t *ptr = type_logger->bulk_type_event_buffer;
-
-       for (uint32_t type_value_index = 0; type_value_index < type_logger->bulk_type_value_count; type_value_index++) {
-               BulkTypeValue *target = &type_logger->bulk_type_values [type_value_index];
-
-               values_element_size += ep_write_buffer_uint64_t (&ptr, target->fixed_sized_data.type_id);
-               values_element_size += ep_write_buffer_uint64_t (&ptr, target->fixed_sized_data.module_id);
-               values_element_size += ep_write_buffer_uint32_t (&ptr, target->fixed_sized_data.type_name_id);
-               values_element_size += ep_write_buffer_uint32_t (&ptr, target->fixed_sized_data.flags);
-               values_element_size += ep_write_buffer_uint8_t (&ptr, target->fixed_sized_data.cor_element_type);
-
-               g_assert (target->name == NULL);
-               values_element_size += ep_write_buffer_string_utf8_to_utf16_t (&ptr, "", 0);
-
-               values_element_size += ep_write_buffer_uint32_t (&ptr, target->type_parameters_count);
-
-               for (uint32_t i = 0; i < target->type_parameters_count; i++) {
-                       uint64_t type_parameter = get_typeid_for_type (target->mono_type_parameters [i]);
-                       values_element_size += ep_write_buffer_uint64_t (&ptr, type_parameter);
-               }
-       }
-
-       FireEtwBulkType (
-               type_logger->bulk_type_value_count,
-               clr_instance_id,
-               values_element_size,
-               type_logger->bulk_type_event_buffer,
-               NULL,
-               NULL);
-
-       memset (type_logger->bulk_type_event_buffer, 0, sizeof (uint8_t) * MAX_SIZE_OF_EVENT_BUFFER);
-       type_logger->bulk_type_value_count = 0;
-       type_logger->bulk_type_value_byte_count = 0;
-}
-
-//---------------------------------------------------------------------------------------
-//
-// get_typeid_for_type is responsible for obtaining the unique type identifier for a
-// particular MonoType. MonoTypes are structs that are not unique pointers. There
-// can be two different MonoTypes that both System.Thread or int32 or bool []. There
-// is exactly one MonoClass * for any type, so we leverage the MonoClass a MonoType
-// points to in order to obtain a unique type identifier in mono. With that unique
-// MonoClass, its fields this_arg and _byval_arg are unique as well.
-//
-// Arguments:
-//      * mono_type - MonoType to be logged
-//
-// Return Value:
-//      type_id - Unique type identifier of mono_type
-
-static
-uint64_t
-get_typeid_for_type (MonoType *t)
-{
-       if (m_type_is_byref (t))
-               return (uint64_t)m_class_get_this_arg (mono_class_from_mono_type_internal (t));
-       else
-               return (uint64_t)m_class_get_byval_arg (mono_class_from_mono_type_internal (t));
-}
-
-static
-uint64_t
-get_typeid_for_class (MonoClass *c)
-{
-       return get_typeid_for_type (m_class_get_byval_arg (c));
-}
-
-//---------------------------------------------------------------------------------------
-//
-// ep_rt_mono_log_single_type batches a single type into the bulk type array and flushes
-// the array to ETW if it fills up. Most interaction with the type system (type analysis)
-// is done here. This does not recursively batch up any parameter types (arrays or generics),
-// but does add their unique identifiers to the mono_type_parameters array.
-// ep_rt_mono_log_type_and_parameters is responsible for initiating any recursive calls to
-// deal with type parameters.
-//
-// Arguments:
-//     * type_logger - BulkTypeEventLogger instance
-//      * mono_type - MonoType to be logged
-//
-// Return Value:
-//      Index into array of where this type got batched. -1 if there was a failure.
-//
-// This follows CoreCLR's BulkTypeEventLogger::LogSingleType
-
-int
-ep_rt_mono_log_single_type (
-       BulkTypeEventLogger *type_logger,
-       MonoType *mono_type)
-{
-       // If there's no room for another type, flush what we've got
-       if (type_logger->bulk_type_value_count == K_MAX_COUNT_TYPE_VALUES)
-               ep_rt_mono_fire_bulk_type_event (type_logger);
-
-       EP_ASSERT (type_logger->bulk_type_value_count < K_MAX_COUNT_TYPE_VALUES);
-
-       BulkTypeValue *val = &type_logger->bulk_type_values [type_logger->bulk_type_value_count];
-       ep_rt_bulk_type_value_clear (val);
-
-       MonoClass *klass = mono_class_from_mono_type_internal (mono_type);
-       MonoType *mono_underlying_type = mono_type_get_underlying_type (mono_type);
-
-       // Initialize val fixed_sized_data
-       val->fixed_sized_data.type_id = get_typeid_for_type (mono_type);
-       val->fixed_sized_data.module_id = (uint64_t)m_class_get_image (klass);
-       val->fixed_sized_data.type_name_id = m_class_get_type_token (klass) ? mono_metadata_make_token (MONO_TABLE_TYPEDEF, mono_metadata_token_index (m_class_get_type_token (klass))) : 0;
-       if (mono_class_has_finalizer (klass))
-               val->fixed_sized_data.flags |= TYPE_FLAGS_FINALIZABLE;
-       if (m_class_is_delegate (klass))
-               val->fixed_sized_data.flags |= TYPE_FLAGS_DELEGATE;
-       if (mono_class_is_com_object (klass))
-               val->fixed_sized_data.flags |= TYPE_FLAGS_EXTERNALLY_IMPLEMENTED_COM_OBJECT;
-       val->fixed_sized_data.cor_element_type = (uint8_t)mono_underlying_type->type;
-
-       // Sets val variable sized parameter type data, type_parameters_count, and mono_type_parameters associated
-       // with arrays or generics to be recursively batched in the same ep_rt_mono_log_type_and_parameters call
-       switch (mono_underlying_type->type) {
-       case MONO_TYPE_ARRAY:
-       case MONO_TYPE_SZARRAY:
-       {
-               MonoArrayType *mono_array_type = mono_type_get_array_type (mono_type);
-               val->fixed_sized_data.flags |= TYPE_FLAGS_ARRAY;
-               if (mono_underlying_type->type == MONO_TYPE_ARRAY) {
-                       // Only ranks less than TypeFlagsArrayRankMax are supported.
-                       // Fortunately TypeFlagsArrayRankMax should be greater than the
-                       // number of ranks the type loader will support
-                       uint32_t rank = mono_array_type->rank;
-                       if (rank < TYPE_FLAGS_ARRAY_RANK_MAX) {
-                               rank <<= 8;
-                               val->fixed_sized_data.flags |= rank;
-                       }
-               }
-
-               // mono arrays are always arrays of by value types
-               val->mono_type_parameters = mono_mempool_alloc0 (type_logger->mem_pool, 1 * sizeof (MonoType*));
-               *val->mono_type_parameters = m_class_get_byval_arg (mono_array_type->eklass);
-               val->type_parameters_count++;
-               break;
-       }
-       case MONO_TYPE_GENERICINST:
-       {
-               MonoGenericInst *class_inst = mono_type->data.generic_class->context.class_inst;
-               val->type_parameters_count = class_inst->type_argc;
-               val->mono_type_parameters = mono_mempool_alloc0 (type_logger->mem_pool, val->type_parameters_count * sizeof (MonoType*));
-               memcpy (val->mono_type_parameters, class_inst->type_argv, val->type_parameters_count * sizeof (MonoType*));
-               break;
-       }
-       case MONO_TYPE_CLASS:
-       case MONO_TYPE_VALUETYPE:
-       case MONO_TYPE_PTR:
-       case MONO_TYPE_BYREF:
-       {
-               if (mono_underlying_type == mono_type)
-                       break;
-               val->mono_type_parameters = mono_mempool_alloc0 (type_logger->mem_pool, 1 * sizeof (MonoType*));
-               *val->mono_type_parameters = mono_underlying_type;
-               val->type_parameters_count++;
-               break;
-       }
-       default:
-               break;
-       }
-
-       // Now that we know the full size of this type's data, see if it fits in our
-       // batch or whether we need to flush
-       int val_byte_count = ep_rt_mono_get_byte_count_in_event (val);
-       if (val_byte_count > MAX_TYPE_VALUES_BYTES) {
-               // NOTE: If name is actively used, set it to NULL and relevant memory management to reduce byte count
-               // This type is apparently so huge, it's too big to squeeze into an event, even
-               // if it were the only type batched in the whole event.  Bail
-               mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed to log single mono type %p with typeID %llu. Type is too large for the BulkType Event.\n", (gpointer)mono_type, (unsigned long long)val->fixed_sized_data.type_id);
-               return -1;
-       }
-
-       if (type_logger->bulk_type_value_byte_count + val_byte_count > MAX_TYPE_VALUES_BYTES) {
-               // Although this type fits into the array, its size is so big that the entire
-               // array can't be logged via ETW. So flush the array, and start over by
-               // calling ourselves--this refetches the type info and puts it at the
-               // beginning of the array.  Since we know this type is small enough to be
-               // batched into an event on its own, this recursive call will not try to
-               // call itself again.
-               g_assert (type_logger->bulk_type_value_byte_count + val_byte_count > MAX_TYPE_VALUES_BYTES);
-               ep_rt_mono_fire_bulk_type_event (type_logger);
-               return ep_rt_mono_log_single_type (type_logger, mono_type);
-       }
-
-       // The type fits into the batch, so update our state
-       type_logger->bulk_type_value_count++;
-       type_logger->bulk_type_value_byte_count += val_byte_count;
-       return type_logger->bulk_type_value_count - 1;
-}
-
-//---------------------------------------------------------------------------------------
-//
-// High-level method to batch a type and (recursively) its type parameters, flushing to
-// ETW as needed.  This is called by ep_rt_mono_log_type_and_parameters_if_necessary.
-//
-// Arguments:
-//     * type_logger - BulkTypeEventLogger instance
-//      * mono_type - MonoType to be logged
-//
-// This follows CoreCLR's BulkTypeEventLogger::LogTypeAndParameter
-
-void
-ep_rt_mono_log_type_and_parameters (
-       BulkTypeEventLogger *type_logger,
-       MonoType *mono_type)
-{
-       // Batch up this type.  This grabs useful info about the type, including any
-       // type parameters it may have, and sticks it in bulk_type_values
-       int bulk_type_value_index = ep_rt_mono_log_single_type (type_logger, mono_type);
-       if (bulk_type_value_index == -1) {
-               // There was a failure trying to log the type, so don't bother with its type
-               // parameters
-               return;
-       }
-
-       // Look at the type info we just batched, so we can get the type parameters
-       BulkTypeValue *val = &type_logger->bulk_type_values [bulk_type_value_index];
-
-       // We're about to recursively call ourselves for the type parameters, so make a
-       // local copy of their type handles first (else, as we log them we could flush
-       // and clear out bulk_type_values, thus trashing val)
-       uint32_t param_count = val->type_parameters_count;
-       if (param_count == 0)
-               return;
-
-       MonoType **mono_type_parameters = mono_mempool_alloc0 (type_logger->mem_pool, param_count * sizeof (MonoType*));
-       memcpy (mono_type_parameters, val->mono_type_parameters, sizeof (MonoType*) * param_count);
-
-       for (uint32_t i = 0; i < param_count; i++)
-               ep_rt_mono_log_type_and_parameters_if_necessary (type_logger, mono_type_parameters [i]);
-}
-
-//---------------------------------------------------------------------------------------
-//
-// Outermost level of ETW-type-logging.  This method is used to log a unique type identifier
-// (in this case a MonoType) and (recursively) its type parameters when present.
-//
-// Arguments:
-//     * type_logger - BulkTypeEventLogger instance
-//      * mono_type - MonoType to be logged
-//
-// This follows CoreCLR's BulkTypeEventLogger::LogTypeAndParameters
-
-void
-ep_rt_mono_log_type_and_parameters_if_necessary (
-       BulkTypeEventLogger *type_logger,
-       MonoType *mono_type)
-{
-       // TODO Log the type if necessary
-
-       ep_rt_mono_log_type_and_parameters (type_logger, mono_type);
-}
-
-// ETW has a limit for maximum event size. Do not log overly large method type argument sets
-static const uint32_t MAX_METHOD_TYPE_ARGUMENT_COUNT = 1024;
-
-//---------------------------------------------------------------------------------------
-//
-// ep_rt_mono_send_method_details_event is the method responsible for sending details of
-// methods involved in events such as JitStart, Load/Unload, Rundown, R2R, and other
-// eventpipe events. It calls ep_rt_mono_log_type_and_parameters_if_necessary to log
-// unique types from the method type and available method instantiation parameter types
-// that are ultimately emitted as a BulkType event in ep_rt_mono_fire_bulk_type_event.
-// After appropriately logging type information, it sends method details outlined by
-// the generated dotnetruntime.c and ClrEtwAll manifest.
-//
-// Arguments:
-//      * method - a MonoMethod hit during an eventpipe event
-//
-// This follows CoreCLR's ETW::MethodLog::SendMethodDetailsEvent
-
-void
-ep_rt_mono_send_method_details_event (MonoMethod *method)
-{
-       if (method->wrapper_type != MONO_WRAPPER_NONE || method->dynamic)
-               return;
-
-       MonoGenericContext *method_ctx = mono_method_get_context (method);
-
-       MonoGenericInst *method_inst = NULL;
-       if (method_ctx)
-               method_inst = method_ctx->method_inst;
-
-       if (method_inst && method_inst->type_argc > MAX_METHOD_TYPE_ARGUMENT_COUNT)
-               return;
-
-       BulkTypeEventLogger *type_logger = ep_rt_bulk_type_event_logger_alloc ();
-
-       uint64_t method_type_id = 0;
-       g_assert (mono_metadata_token_index (method->token) != 0);
-       uint32_t method_token = mono_metadata_make_token (MONO_TABLE_METHOD, mono_metadata_token_index (method->token));
-       uint64_t loader_module_id = 0;
-       MonoClass *klass = method->klass;
-       if (klass) {
-               MonoType *method_mono_type = m_class_get_byval_arg (klass);
-               method_type_id = get_typeid_for_class (klass);
-
-               ep_rt_mono_log_type_and_parameters_if_necessary (type_logger, method_mono_type);
-
-               loader_module_id = (uint64_t)mono_class_get_image (klass);
-       }
-
-       uint32_t method_inst_parameter_types_count = 0;
-       if (method_inst)
-               method_inst_parameter_types_count = method_inst->type_argc;
-
-       uint64_t *method_inst_parameters_type_ids = mono_mempool_alloc0 (type_logger->mem_pool, method_inst_parameter_types_count * sizeof (uint64_t));
-       uint8_t *buffer = (uint8_t *)method_inst_parameters_type_ids;
-       for (uint32_t i = 0; i < method_inst_parameter_types_count; i++) {
-               ep_write_buffer_uint64_t (&buffer, get_typeid_for_type (method_inst->type_argv [i]));
-
-               ep_rt_mono_log_type_and_parameters_if_necessary (type_logger, method_inst->type_argv [i]);
-       }
-
-       ep_rt_mono_fire_bulk_type_event (type_logger);
-
-       FireEtwMethodDetails (
-               (uint64_t)method,
-               method_type_id,
-               method_token,
-               method_inst_parameter_types_count,
-               loader_module_id,
-               (uint64_t*)method_inst_parameters_type_ids,
-               NULL,
-               NULL);
-
-       ep_rt_bulk_type_event_logger_free (type_logger);
-}
-
-bool
-ep_rt_mono_write_event_jit_start (MonoMethod *method)
-{
-       if (!EventEnabledMethodJittingStarted_V1 ())
-               return true;
-
-       //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc.
-       if (method) {
-               uint64_t method_id = 0;
-               uint64_t module_id = 0;
-               uint32_t code_size = 0;
-               uint32_t method_token = 0;
-               char *method_namespace = NULL;
-               const char *method_name = NULL;
-               char *method_signature = NULL;
-
-               ep_rt_mono_send_method_details_event(method);
-
-               method_id = (uint64_t)method;
-
-               if (!method->dynamic)
-                       method_token = method->token;
-
-               if (!mono_method_has_no_body (method)) {
-                       ERROR_DECL (error);
-                       MonoMethodHeader *header = mono_method_get_header_internal (method, error);
-                       if (header)
-                               code_size = header->code_size;
-               }
-
-               method_name = method->name;
-               method_signature = mono_signature_full_name (mono_method_signature_internal (method));
-
-               if (method->klass) {
-                       module_id = (uint64_t)m_class_get_image (method->klass);
-                       method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL);
-               }
-
-               FireEtwMethodJittingStarted_V1 (
-                       method_id,
-                       module_id,
-                       method_token,
-                       code_size,
-                       method_namespace,
-                       method_name,
-                       method_signature,
-                       clr_instance_get_id (),
-                       NULL,
-                       NULL);
-
-               g_free (method_namespace);
-               g_free (method_signature);
-       }
-
-       return true;
-}
-
-bool
-ep_rt_mono_write_event_method_il_to_native_map (
-       MonoMethod *method,
-       MonoJitInfo *ji)
-{
-       if (!EventEnabledMethodILToNativeMap ())
-               return true;
-
-       if (method) {
-               // Under netcore we only have root domain.
-               MonoDomain *root_domain = mono_get_root_domain ();
-
-               uint64_t method_id = (uint64_t)method;
-               uint32_t fixed_buffer [64];
-               uint8_t *buffer = NULL;
-
-               uint32_t offset_entries = 0;
-               uint32_t *il_offsets = NULL;
-               uint32_t *native_offsets = NULL;
-
-               MonoDebugMethodJitInfo *debug_info = method ? mono_debug_find_method (method, root_domain) : NULL;
-               if (debug_info) {
-                       offset_entries = debug_info->num_line_numbers;
-                       if (offset_entries != 0) {
-                               size_t needed_size = (offset_entries * sizeof (uint32_t) * 2);
-                               if (needed_size > sizeof (fixed_buffer)) {
-                                       buffer = g_new (uint8_t, needed_size);
-                                       il_offsets = (uint32_t*)buffer;
-                               } else {
-                                       il_offsets = fixed_buffer;
-                               }
-                               if (il_offsets) {
-                                       native_offsets = il_offsets + offset_entries;
-                                       uint8_t *il_offsets_ptr = (uint8_t *)il_offsets;
-                                       uint8_t *native_offsets_ptr = (uint8_t *)native_offsets;
-                                       for (uint32_t offset_count = 0; offset_count < offset_entries; ++offset_count) {
-                                               ep_write_buffer_uint32_t (&il_offsets_ptr, debug_info->line_numbers [offset_count].il_offset);
-                                               ep_write_buffer_uint32_t (&native_offsets_ptr, debug_info->line_numbers [offset_count].native_offset);
-                                       }
-                               }
-                       }
-
-                       mono_debug_free_method_jit_info (debug_info);
-               }
-
-               if (!il_offsets && !native_offsets) {
-                       // No IL offset -> Native offset mapping available. Put all code on IL offset 0.
-                       EP_ASSERT (sizeof (fixed_buffer) >= sizeof (uint32_t) * 2);
-                       offset_entries = 1;
-                       il_offsets = fixed_buffer;
-                       native_offsets = il_offsets + offset_entries;
-                       il_offsets [0] = 0;
-                       native_offsets [0] = ji ? ep_rt_val_uint32_t ((uint32_t)ji->code_size) : 0;
-               }
-
-               FireEtwMethodILToNativeMap (
-                       method_id,
-                       0,
-                       0,
-                       GUINT32_TO_UINT16 (offset_entries),
-                       il_offsets,
-                       native_offsets,
-                       clr_instance_get_id (),
-                       NULL,
-                       NULL);
-
-               g_free (buffer);
-       }
-
-       return true;
-}
-
-bool
-ep_rt_mono_write_event_method_load (
-       MonoMethod *method,
-       MonoJitInfo *ji)
-{
-       if (!EventEnabledMethodLoad_V1 () && !EventEnabledMethodLoadVerbose_V1 ())
-               return true;
-
-       //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc.
-       if (method) {
-               uint64_t method_id = 0;
-               uint64_t module_id = 0;
-               uint64_t method_code_start = ji ? (uint64_t)ji->code_start : 0;
-               uint32_t method_code_size = ji ? (uint32_t)ji->code_size : 0;
-               uint32_t method_token = 0;
-               uint32_t method_flags = 0;
-               uint8_t kind = MONO_CLASS_DEF;
-               char *method_namespace = NULL;
-               const char *method_name = NULL;
-               char *method_signature = NULL;
-               bool verbose = (MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.Level >= (uint8_t)EP_EVENT_LEVEL_VERBOSE);
-
-               method_id = (uint64_t)method;
-
-               if (!method->dynamic)
-                       method_token = method->token;
-
-               if (ji && mono_jit_info_get_generic_sharing_context (ji)) {
-                       method_flags |= METHOD_FLAGS_SHARED_GENERIC_METHOD;
-                       verbose = true;
-               }
-
-               if (method->dynamic) {
-                       method_flags |= METHOD_FLAGS_DYNAMIC_METHOD;
-                       verbose = true;
-               }
-
-               if (ji && !ji->from_aot && !ji->from_llvm) {
-                       method_flags |= METHOD_FLAGS_JITTED_METHOD;
-                       if (method->wrapper_type != MONO_WRAPPER_NONE)
-                               method_flags |= METHOD_FLAGS_JITTED_HELPER_METHOD;
-               }
-
-               if (method->is_generic || method->is_inflated) {
-                       method_flags |= METHOD_FLAGS_GENERIC_METHOD;
-                       verbose = true;
-               }
-
-               if (method->klass) {
-                       module_id = (uint64_t)m_class_get_image (method->klass);
-                       kind = m_class_get_class_kind (method->klass);
-                       if (kind == MONO_CLASS_GTD || kind == MONO_CLASS_GINST)
-                               method_flags |= METHOD_FLAGS_GENERIC_METHOD;
-               }
-
-               ep_rt_mono_send_method_details_event(method);
-
-               if (verbose) {
-                       method_name = method->name;
-                       method_signature = mono_signature_full_name (mono_method_signature_internal (method));
-
-                       if (method->klass)
-                               method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL);
-
-                       FireEtwMethodLoadVerbose_V1 (
-                               method_id,
-                               module_id,
-                               method_code_start,
-                               method_code_size,
-                               method_token,
-                               method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION,
-                               method_namespace,
-                               method_name,
-                               method_signature,
-                               clr_instance_get_id (),
-                               NULL,
-                               NULL);
-
-                       if (ji && (ji->from_aot || ji->from_llvm))
-                               FireEtwMethodLoadVerbose_V1 (
-                                       method_id,
-                                       module_id,
-                                       method_code_start,
-                                       method_code_size,
-                                       method_token,
-                                       method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION,
-                                       method_namespace,
-                                       method_name,
-                                       method_signature,
-                                       clr_instance_get_id (),
-                                       NULL,
-                                       NULL);
-               } else {
-                       FireEtwMethodLoad_V1 (
-                               method_id,
-                               module_id,
-                               method_code_start,
-                               method_code_size,
-                               method_token,
-                               method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION,
-                               clr_instance_get_id (),
-                               NULL,
-                               NULL);
-
-                       if (ji && (ji->from_aot || ji->from_llvm))
-                               FireEtwMethodLoad_V1 (
-                                       method_id,
-                                       module_id,
-                                       method_code_start,
-                                       method_code_size,
-                                       method_token,
-                                       method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION,
-                                       clr_instance_get_id (),
-                                       NULL,
-                                       NULL);
-               }
-
-               g_free (method_namespace);
-               g_free (method_signature);
-       }
-
-       return true;
-}
-
-static
-bool
-get_module_event_data (
-       MonoImage *image,
-       ModuleEventData *module_data)
-{
-       if (module_data) {
-               memset (module_data->module_il_pdb_signature, 0, EP_GUID_SIZE);
-               memset (module_data->module_native_pdb_signature, 0, EP_GUID_SIZE);
-
-               // Under netcore we only have root domain.
-               MonoDomain *root_domain = mono_get_root_domain ();
-
-               module_data->domain_id = (uint64_t)root_domain;
-               module_data->module_id = (uint64_t)image;
-               module_data->assembly_id = image ? (uint64_t)image->assembly : 0;
-
-               // TODO: Extract all module native paths and pdb metadata when available.
-               module_data->module_native_path = "";
-               module_data->module_native_pdb_path = "";
-               module_data->module_native_pdb_age = 0;
-
-               module_data->reserved_flags = 0;
-
-               // Netcore has a 1:1 between assemblies and modules, so its always a manifest module.
-               module_data->module_flags = MODULE_FLAGS_MANIFEST_MODULE;
-               if (image && image->dynamic)
-                       module_data->module_flags |= MODULE_FLAGS_DYNAMIC_MODULE;
-               if (image && image->aot_module)
-                       module_data->module_flags |= MODULE_FLAGS_NATIVE_MODULE;
-
-               module_data->module_il_path = NULL;
-               if (image && image->filename) {
-                       /* if there's a filename, use it */
-                       module_data->module_il_path = image->filename;
-               } else if (image && image->module_name) {
-                       /* otherwise, use the module name */
-                       module_data->module_il_path = image->module_name;
-               }
-               if (!module_data->module_il_path)
-                       module_data->module_il_path = "";
-
-               module_data->module_il_pdb_path = "";
-               module_data->module_il_pdb_age = 0;
-
-               if (image && image->image_info) {
-                       MonoPEDirEntry *debug_dir_entry = (MonoPEDirEntry *)&image->image_info->cli_header.datadir.pe_debug;
-                       if (debug_dir_entry->size) {
-                               ImageDebugDirectory debug_dir;
-                               memset (&debug_dir, 0, sizeof (debug_dir));
-
-                               uint32_t offset = mono_cli_rva_image_map (image, debug_dir_entry->rva);
-                               for (uint32_t idx = 0; idx < debug_dir_entry->size / sizeof (ImageDebugDirectory); ++idx) {
-                                       uint8_t *data = (uint8_t *) ((ImageDebugDirectory *) (image->raw_data + offset) + idx);
-                                       debug_dir.major_version = read16 (data + 8);
-                                       debug_dir.minor_version = read16 (data + 10);
-                                       debug_dir.type = read32 (data + 12);
-                                       debug_dir.pointer = read32 (data + 24);
-
-                                       if (debug_dir.type == DEBUG_DIR_ENTRY_CODEVIEW && debug_dir.major_version == 0x100 && debug_dir.minor_version == 0x504d) {
-                                               data  = (uint8_t *)(image->raw_data + debug_dir.pointer);
-                                               int32_t signature = read32 (data);
-                                               if (signature == 0x53445352) {
-                                                       memcpy (module_data->module_il_pdb_signature, data + 4, EP_GUID_SIZE);
-                                                       module_data->module_il_pdb_age = read32 (data + 20);
-                                                       module_data->module_il_pdb_path = (const char *)(data + 24);
-                                                       break;
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-
-       return true;
-}
-
-bool
-ep_rt_mono_write_event_module_load (MonoImage *image)
-{
-       if (!EventEnabledModuleLoad_V2 () && !EventEnabledDomainModuleLoad_V1 ())
-               return true;
-
-       if (image) {
-               ModuleEventData module_data;
-               memset (&module_data, 0, sizeof (module_data));
-               if (get_module_event_data (image, &module_data)) {
-                       FireEtwModuleLoad_V2 (
-                               module_data.module_id,
-                               module_data.assembly_id,
-                               module_data.module_flags,
-                               module_data.reserved_flags,
-                               module_data.module_il_path,
-                               module_data.module_native_path,
-                               clr_instance_get_id (),
-                               module_data.module_il_pdb_signature,
-                               module_data.module_il_pdb_age,
-                               module_data.module_il_pdb_path,
-                               module_data.module_native_pdb_signature,
-                               module_data.module_native_pdb_age,
-                               module_data.module_native_pdb_path,
-                               NULL,
-                               NULL);
-
-                       FireEtwDomainModuleLoad_V1 (
-                               module_data.module_id,
-                               module_data.assembly_id,
-                               module_data.domain_id,
-                               module_data.module_flags,
-                               module_data.reserved_flags,
-                               module_data.module_il_path,
-                               module_data.module_native_path,
-                               clr_instance_get_id (),
-                               NULL,
-                               NULL);
-               }
-       }
-
-       return true;
-}
-
-bool
-ep_rt_mono_write_event_module_unload (MonoImage *image)
-{
-       if (!EventEnabledModuleUnload_V2())
-               return true;
-
-       if (image) {
-               ModuleEventData module_data;
-               memset (&module_data, 0, sizeof (module_data));
-               if (get_module_event_data (image, &module_data)) {
-                       FireEtwModuleUnload_V2 (
-                               module_data.module_id,
-                               module_data.assembly_id,
-                               module_data.module_flags,
-                               module_data.reserved_flags,
-                               module_data.module_il_path,
-                               module_data.module_native_path,
-                               clr_instance_get_id (),
-                               module_data.module_il_pdb_signature,
-                               module_data.module_il_pdb_age,
-                               module_data.module_il_pdb_path,
-                               module_data.module_native_pdb_signature,
-                               module_data.module_native_pdb_age,
-                               module_data.module_native_pdb_path,
-                               NULL,
-                               NULL);
-               }
-       }
-
-       return true;
-}
-
-static
-bool
-get_assembly_event_data (
-       MonoAssembly *assembly,
-       AssemblyEventData *assembly_data)
-{
-       if (assembly && assembly_data) {
-               // Under netcore we only have root domain.
-               MonoDomain *root_domain = mono_get_root_domain ();
-
-               assembly_data->domain_id = (uint64_t)root_domain;
-               assembly_data->assembly_id = (uint64_t)assembly;
-               assembly_data->binding_id = 0;
-
-               assembly_data->assembly_flags = 0;
-               if (assembly->dynamic)
-                       assembly_data->assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY;
-
-               if (assembly->image && assembly->image->aot_module)
-                       assembly_data->assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY;
-
-               assembly_data->assembly_name = mono_stringify_assembly_name (&assembly->aname);
-       }
-
-       return true;
-}
-
-bool
-ep_rt_mono_write_event_assembly_load (MonoAssembly *assembly)
-{
-       if (!EventEnabledAssemblyLoad_V1 ())
-               return true;
-
-       if (assembly) {
-               AssemblyEventData assembly_data;
-               memset (&assembly_data, 0, sizeof (assembly_data));
-               if (get_assembly_event_data (assembly, &assembly_data)) {
-                       FireEtwAssemblyLoad_V1 (
-                               assembly_data.assembly_id,
-                               assembly_data.domain_id,
-                               assembly_data.binding_id,
-                               assembly_data.assembly_flags,
-                               assembly_data.assembly_name,
-                               clr_instance_get_id (),
-                               NULL,
-                               NULL);
-
-                       g_free (assembly_data.assembly_name);
-               }
-       }
-
-       return true;
-}
-
-bool
-ep_rt_mono_write_event_assembly_unload (MonoAssembly *assembly)
-{
-       if (!EventEnabledAssemblyUnload_V1 ())
-               return true;
-
-       if (assembly) {
-               AssemblyEventData assembly_data;
-               memset (&assembly_data, 0, sizeof (assembly_data));
-               if (get_assembly_event_data (assembly, &assembly_data)) {
-                       FireEtwAssemblyUnload_V1 (
-                               assembly_data.assembly_id,
-                               assembly_data.domain_id,
-                               assembly_data.binding_id,
-                               assembly_data.assembly_flags,
-                               assembly_data.assembly_name,
-                               clr_instance_get_id (),
-                               NULL,
-                               NULL);
-
-                       g_free (assembly_data.assembly_name);
-               }
-       }
-
-       return true;
-}
-
-bool
-ep_rt_mono_write_event_thread_created (ep_rt_thread_id_t tid)
-{
-       if (!EventEnabledThreadCreated ())
-               return true;
-
-       uint64_t managed_thread = 0;
-       uint32_t native_thread_id = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
-       uint32_t managed_thread_id = 0;
-       uint32_t flags = 0;
-
-       MonoThread *thread = mono_thread_current ();
-       if (thread && mono_thread_info_get_tid (thread->thread_info) == tid) {
-               managed_thread_id = mono_thread_get_managed_id (thread);
-               managed_thread = (uint64_t)thread;
-
-               switch (mono_thread_info_get_flags (thread->thread_info)) {
-               case MONO_THREAD_INFO_FLAGS_NO_GC:
-               case MONO_THREAD_INFO_FLAGS_NO_SAMPLE:
-                       flags |= THREAD_FLAGS_GC_SPECIAL;
-               }
-
-               if (mono_gc_is_finalizer_thread (thread))
-                       flags |= THREAD_FLAGS_FINALIZER;
-
-               if (thread->threadpool_thread)
-                       flags |= THREAD_FLAGS_THREADPOOL_WORKER;
-       }
-
-       FireEtwThreadCreated (
-               managed_thread,
-               (uint64_t)mono_get_root_domain (),
-               flags,
-               managed_thread_id,
-               native_thread_id,
-               clr_instance_get_id (),
-               NULL,
-               NULL);
-
-       return true;
-}
-
-bool
-ep_rt_mono_write_event_thread_terminated (ep_rt_thread_id_t tid)
-{
-       if (!EventEnabledThreadTerminated ())
-               return true;
-
-       uint64_t managed_thread = 0;
-       MonoThread *thread = mono_thread_current ();
-       if (thread && mono_thread_info_get_tid (thread->thread_info) == tid)
-               managed_thread = (uint64_t)thread;
-
-       FireEtwThreadTerminated (
-               managed_thread,
-               (uint64_t)mono_get_root_domain (),
-               clr_instance_get_id (),
-               NULL,
-               NULL);
-
-       return true;
-}
-
-static
-uint32_t
-get_type_start_id (MonoType *type)
-{
-       uint32_t start_id = (uint32_t)(uintptr_t)type;
-
-       start_id = (((start_id * 215497) >> 16) ^ ((start_id * 1823231) + start_id));
-
-MONO_DISABLE_WARNING(4127) /* conditional expression is constant */
-       // Mix in highest bits on 64-bit systems only
-       if (sizeof (type) > 4)
-               start_id = start_id ^ GUINT64_TO_UINT32 ((((uint64_t)type >> 31) >> 1));
-MONO_RESTORE_WARNING
-
-       return start_id;
-}
-
-bool
-ep_rt_mono_write_event_type_load_start (MonoType *type)
-{
-       if (!EventEnabledTypeLoadStart ())
-               return true;
-
-       FireEtwTypeLoadStart (
-               get_type_start_id (type),
-               clr_instance_get_id (),
-               NULL,
-               NULL);
-
-       return true;
-}
-
-bool
-ep_rt_mono_write_event_type_load_stop (MonoType *type)
-{
-       if (!EventEnabledTypeLoadStop ())
-               return true;
-
-       char *type_name = NULL;
-       if (type)
-               type_name = mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
-
-       FireEtwTypeLoadStop (
-               get_type_start_id (type),
-               clr_instance_get_id (),
-               6 /* CLASS_LOADED */,
-               (uint64_t)type,
-               type_name,
-               NULL,
-               NULL);
-
-       g_free (type_name);
-
-       return true;
-}
-
-static
-gboolean
-get_exception_ip_func (
-       MonoStackFrameInfo *frame,
-       MonoContext *ctx,
-       void *data)
-{
-       *(uintptr_t *)data = (uintptr_t)MONO_CONTEXT_GET_IP (ctx);
-       return TRUE;
-}
-
-bool
-ep_rt_mono_write_event_exception_thrown (MonoObject *obj)
-{
-       if (!EventEnabledExceptionThrown_V1 ())
-               return true;
-
-       if (obj) {
-               ERROR_DECL (error);
-               char *type_name = NULL;
-               char *exception_message = NULL;
-               uint16_t flags = 0;
-               uint32_t hresult = 0;
-               uintptr_t ip = 0;
-
-               if (mono_object_isinst_checked ((MonoObject *) obj, mono_get_exception_class (), error)) {
-                       MonoException *exception = (MonoException *)obj;
-                       flags |= EXCEPTION_THROWN_FLAGS_IS_CLS_COMPLIANT;
-                       if (exception->inner_ex)
-                               flags |= EXCEPTION_THROWN_FLAGS_HAS_INNER;
-                       if (exception->message)
-                               exception_message = ep_rt_utf16_to_utf8_string (mono_string_chars_internal (exception->message), mono_string_length_internal (exception->message));
-                       hresult = exception->hresult;
-               }
-
-               if (exception_message == NULL)
-                       exception_message = g_strdup ("");
-
-               if (mono_get_eh_callbacks ()->mono_walk_stack_with_ctx)
-                       mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (get_exception_ip_func, NULL, MONO_UNWIND_SIGNAL_SAFE, (void *)&ip);
-
-               type_name = mono_type_get_name_full (m_class_get_byval_arg (mono_object_class (obj)), MONO_TYPE_NAME_FORMAT_IL);
-
-               FireEtwExceptionThrown_V1 (
-                       type_name,
-                       exception_message,
-                       (void *)&ip,
-                       hresult,
-                       flags,
-                       clr_instance_get_id (),
-                       NULL,
-                       NULL);
-
-               if (!mono_component_profiler_clauses_enabled ()) {
-                       FireEtwExceptionThrownStop (
-                               NULL,
-                               NULL);
-               }
-
-               g_free (exception_message);
-               g_free (type_name);
-
-               mono_error_cleanup (error);
-       }
-
-       return true;
-}
-
-bool
-ep_rt_mono_write_event_exception_clause (
-       MonoMethod *method,
-       uint32_t clause_num,
-       MonoExceptionEnum clause_type,
-       MonoObject *obj)
-{
-       if (!mono_component_profiler_clauses_enabled ())
-               return true;
-
-       if ((clause_type == MONO_EXCEPTION_CLAUSE_FAULT || clause_type == MONO_EXCEPTION_CLAUSE_NONE) && (!EventEnabledExceptionCatchStart() || !EventEnabledExceptionCatchStop()))
-               return true;
-
-       if (clause_type == MONO_EXCEPTION_CLAUSE_FILTER && (!EventEnabledExceptionFilterStart() || !EventEnabledExceptionFilterStop()))
-               return true;
-
-       if (clause_type == MONO_EXCEPTION_CLAUSE_FINALLY && (!EventEnabledExceptionFinallyStart() || !EventEnabledExceptionFinallyStop()))
-               return true;
-
-       uintptr_t ip = 0; //TODO: Have profiler pass along IP of handler block.
-       uint64_t method_id = (uint64_t)method;
-       char *method_name = NULL;
-
-       method_name = mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL);
-
-       if ((clause_type == MONO_EXCEPTION_CLAUSE_FAULT || clause_type == MONO_EXCEPTION_CLAUSE_NONE)) {
-               FireEtwExceptionCatchStart (
-                       (uint64_t)ip,
-                       method_id,
-                       (const ep_char8_t *)method_name,
-                       clr_instance_get_id (),
-                       NULL,
-                       NULL);
-
-               FireEtwExceptionCatchStop (
-                       NULL,
-                       NULL);
-
-               FireEtwExceptionThrownStop (
-                       NULL,
-                       NULL);
-       }
-
-       if (clause_type == MONO_EXCEPTION_CLAUSE_FILTER) {
-               FireEtwExceptionFilterStart (
-                       (uint64_t)ip,
-                       method_id,
-                       (const ep_char8_t *)method_name,
-                       clr_instance_get_id (),
-                       NULL,
-                       NULL);
-
-               FireEtwExceptionFilterStop (
-                       NULL,
-                       NULL);
-       }
-
-       if (clause_type == MONO_EXCEPTION_CLAUSE_FINALLY) {
-               FireEtwExceptionFinallyStart (
-                       (uint64_t)ip,
-                       method_id,
-                       (const ep_char8_t *)method_name,
-                       clr_instance_get_id (),
-                       NULL,
-                       NULL);
-
-               FireEtwExceptionFinallyStop (
-                       NULL,
-                       NULL);
-       }
-
-       g_free (method_name);
-       return true;
-}
-
-bool
-ep_rt_mono_write_event_monitor_contention_start (MonoObject *obj)
-{
-       if (!EventEnabledContentionStart_V1 ())
-               return true;
-
-       FireEtwContentionStart_V1 (
-               0 /* ManagedContention */,
-               clr_instance_get_id (),
-               NULL,
-               NULL);
-
-       return true;
-}
-
-bool
-ep_rt_mono_write_event_monitor_contention_stop (MonoObject *obj)
-{
-       if (!EventEnabledContentionStop ())
-               return true;
-
-       FireEtwContentionStop (
-               0 /* ManagedContention */,
-               clr_instance_get_id (),
-               NULL,
-               NULL);
-
-       return true;
-}
-
-bool
-ep_rt_mono_write_event_method_jit_memory_allocated_for_code (
-       const uint8_t *buffer,
-       uint64_t size,
-       MonoProfilerCodeBufferType type,
-       const void *data)
-{
-       if (!EventEnabledMethodJitMemoryAllocatedForCode ())
-               return true;
-
-       if (type != MONO_PROFILER_CODE_BUFFER_METHOD)
-               return true;
-
-       uint64_t method_id = 0;
-       uint64_t module_id = 0;
-
-       if (data) {
-               MonoMethod *method;
-               method = (MonoMethod *)data;
-               method_id = (uint64_t)method;
-               if (method->klass)
-                       module_id = (uint64_t)(uint64_t)m_class_get_image (method->klass);
-       }
-
-       FireEtwMethodJitMemoryAllocatedForCode (
-               method_id,
-               module_id,
-               size,
-               0,
-               size,
-               0 /* CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN */,
-               clr_instance_get_id (),
-               NULL,
-               NULL);
-
-       return true;
-}
-
-bool
-ep_rt_write_event_threadpool_worker_thread_start (
-       uint32_t active_thread_count,
-       uint32_t retired_worker_thread_count,
-       uint16_t clr_instance_id)
-{
-       return FireEtwThreadPoolWorkerThreadStart (
-               active_thread_count,
-               retired_worker_thread_count,
-               clr_instance_id,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-bool
-ep_rt_write_event_threadpool_worker_thread_stop (
-       uint32_t active_thread_count,
-       uint32_t retired_worker_thread_count,
-       uint16_t clr_instance_id)
-{
-       return FireEtwThreadPoolWorkerThreadStop (
-               active_thread_count,
-               retired_worker_thread_count,
-               clr_instance_id,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-bool
-ep_rt_write_event_threadpool_worker_thread_wait (
-       uint32_t active_thread_count,
-       uint32_t retired_worker_thread_count,
-       uint16_t clr_instance_id)
-{
-       return FireEtwThreadPoolWorkerThreadWait (
-               active_thread_count,
-               retired_worker_thread_count,
-               clr_instance_id,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-bool
-ep_rt_write_event_threadpool_min_max_threads (
-       uint16_t min_worker_threads,
-       uint16_t max_worker_threads,
-       uint16_t min_io_completion_threads,
-       uint16_t max_io_completion_threads,
-       uint16_t clr_instance_id)
-{
-       return FireEtwThreadPoolMinMaxThreads (
-               min_worker_threads,
-               max_worker_threads,
-               min_io_completion_threads,
-               max_io_completion_threads,
-               clr_instance_id,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-bool
-ep_rt_write_event_threadpool_worker_thread_adjustment_sample (
-       double throughput,
-       uint16_t clr_instance_id)
-{
-       return FireEtwThreadPoolWorkerThreadAdjustmentSample (
-               throughput,
-               clr_instance_id,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-bool
-ep_rt_write_event_threadpool_worker_thread_adjustment_adjustment (
-       double average_throughput,
-       uint32_t networker_thread_count,
-       /*NativeRuntimeEventSource.ThreadAdjustmentReasonMap*/ int32_t reason,
-       uint16_t clr_instance_id)
-{
-       return FireEtwThreadPoolWorkerThreadAdjustmentAdjustment (
-               average_throughput,
-               networker_thread_count,
-               reason,
-               clr_instance_id,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-bool
-ep_rt_write_event_threadpool_worker_thread_adjustment_stats (
-       double duration,
-       double throughput,
-       double threadpool_worker_thread_wait,
-       double throughput_wave,
-       double throughput_error_estimate,
-       double average_throughput_error_estimate,
-       double throughput_ratio,
-       double confidence,
-       double new_control_setting,
-       uint16_t new_thread_wave_magnitude,
-       uint16_t clr_instance_id)
-{
-       return FireEtwThreadPoolWorkerThreadAdjustmentStats (
-               duration,
-               throughput,
-               threadpool_worker_thread_wait,
-               throughput_wave,
-               throughput_error_estimate,
-               average_throughput_error_estimate,
-               throughput_ratio,
-               confidence,
-               new_control_setting,
-               new_thread_wave_magnitude,
-               clr_instance_id,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-bool
-ep_rt_write_event_threadpool_io_enqueue (
-       intptr_t native_overlapped,
-       intptr_t overlapped,
-       bool multi_dequeues,
-       uint16_t clr_instance_id)
-{
-       return FireEtwThreadPoolIOEnqueue (
-               (const void *)native_overlapped,
-               (const void *)overlapped,
-               multi_dequeues,
-               clr_instance_id,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-bool
-ep_rt_write_event_threadpool_io_dequeue (
-       intptr_t native_overlapped,
-       intptr_t overlapped,
-       uint16_t clr_instance_id)
-{
-       return FireEtwThreadPoolIODequeue (
-               (const void *)native_overlapped,
-               (const void *)overlapped,
-               clr_instance_id,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-bool
-ep_rt_write_event_threadpool_working_thread_count (
-       uint16_t count,
-       uint16_t clr_instance_id)
-{
-       return FireEtwThreadPoolWorkingThreadCount (
-               count,
-               clr_instance_id,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-bool
-ep_rt_write_event_threadpool_io_pack (
-       intptr_t native_overlapped,
-       intptr_t overlapped,
-       uint16_t clr_instance_id)
-{
-       return FireEtwThreadPoolIOPack (
-               (const void *)native_overlapped,
-               (const void *)overlapped,
-               clr_instance_id,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-bool
-ep_rt_write_event_contention_lock_created (
-       intptr_t lock_id,
-       intptr_t associated_object_id,
-       uint16_t clr_instance_id)
-{
-       return FireEtwContentionLockCreated (
-               (const void *)lock_id,
-               (const void *)associated_object_id,
-               clr_instance_id,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-bool
-ep_rt_write_event_contention_start (
-       uint8_t contention_flags,
-       uint16_t clr_instance_id,
-       intptr_t lock_id,
-       intptr_t associated_object_id,
-       uint64_t lock_owner_thread_id)
-{
-       return FireEtwContentionStart_V2 (
-               contention_flags,
-               clr_instance_id,
-               (const void *)lock_id,
-               (const void *)associated_object_id,
-               lock_owner_thread_id,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-bool
-ep_rt_write_event_contention_stop (
-       uint8_t contention_flags,
-       uint16_t clr_instance_id,
-       double duration_ns)
-{
-       return FireEtwContentionStop_V1 (
-               contention_flags,
-               clr_instance_id,
-               duration_ns,
-               NULL,
-               NULL) == 0 ? true : false;
-}
-
-static
-void
-runtime_profiler_jit_begin (
-       MonoProfiler *prof,
-       MonoMethod *method)
-{
-       ep_rt_mono_write_event_jit_start (method);
-}
-
-static
-void
-runtime_profiler_jit_failed (
-       MonoProfiler *prof,
-       MonoMethod *method)
-{
-       //TODO: CoreCLR doesn't have this case, so no failure event currently exists.
-}
-
-static
-void
-runtime_profiler_jit_done (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       MonoJitInfo *ji)
-{
-       ep_rt_mono_write_event_method_load (method, ji);
-       ep_rt_mono_write_event_method_il_to_native_map (method, ji);
-}
-
-static
-void
-runtime_profiler_image_loaded (
-       MonoProfiler *prof,
-       MonoImage *image)
-{
-       if (image && image->heap_pdb.size == 0)
-               ep_rt_mono_write_event_module_load (image);
-}
-
-static
-void
-runtime_profiler_image_unloaded (
-       MonoProfiler *prof,
-       MonoImage *image)
-{
-       if (image && image->heap_pdb.size == 0)
-               ep_rt_mono_write_event_module_unload (image);
-}
-
-static
-void
-runtime_profiler_assembly_loaded (
-       MonoProfiler *prof,
-       MonoAssembly *assembly)
-{
-       ep_rt_mono_write_event_assembly_load (assembly);
-}
-
-static
-void
-runtime_profiler_assembly_unloaded (
-       MonoProfiler *prof,
-       MonoAssembly *assembly)
-{
-       ep_rt_mono_write_event_assembly_unload (assembly);
-}
-
-static
-void
-runtime_profiler_thread_started (
-       MonoProfiler *prof,
-       uintptr_t tid)
-{
-       ep_rt_mono_write_event_thread_created (ep_rt_uint64_t_to_thread_id_t (tid));
-}
-
-static
-void
-runtime_profiler_thread_stopped (
-       MonoProfiler *prof,
-       uintptr_t tid)
-{
-       ep_rt_mono_write_event_thread_terminated (ep_rt_uint64_t_to_thread_id_t (tid));
-}
-
-static
-void
-runtime_profiler_class_loading (
-       MonoProfiler *prof,
-       MonoClass *klass)
-{
-       bool prevent_profiler_event_recursion = FALSE;
-       EventPipeThreadData *thread_data = eventpipe_thread_data_get_or_create ();
-       if (thread_data) {
-               // Prevent additional class loading to happen recursively as part of fire TypeLoadStart event.
-               // Additional class loading can happen as part of capturing callstack for TypeLoadStart event.
-               prevent_profiler_event_recursion = thread_data->prevent_profiler_event_recursion;
-               thread_data->prevent_profiler_event_recursion = TRUE;
-       }
-
-       ep_rt_mono_write_event_type_load_start (m_class_get_byval_arg (klass));
-
-       if (thread_data)
-               thread_data->prevent_profiler_event_recursion = prevent_profiler_event_recursion;
-}
-
-static
-void
-runtime_profiler_class_failed (
-       MonoProfiler *prof,
-       MonoClass *klass)
-{
-       ep_rt_mono_write_event_type_load_stop (m_class_get_byval_arg (klass));
-}
-
-static
-void
-runtime_profiler_class_loaded (
-       MonoProfiler *prof,
-       MonoClass *klass)
-{
-       ep_rt_mono_write_event_type_load_stop (m_class_get_byval_arg (klass));
-}
-
-static
-void
-runtime_profiler_exception_throw (
-       MonoProfiler *prof,
-       MonoObject *exc)
-{
-       ep_rt_mono_write_event_exception_thrown (exc);
-}
-
-static
-void
-runtime_profiler_exception_clause (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       uint32_t clause_num,
-       MonoExceptionEnum clause_type,
-       MonoObject *exc)
-{
-       ep_rt_mono_write_event_exception_clause (method, clause_num, clause_type, exc);
-}
-
-static
-void
-runtime_profiler_monitor_contention (
-       MonoProfiler *prof,
-       MonoObject *obj)
-{
-       ep_rt_mono_write_event_monitor_contention_start (obj);
-}
-
-static
-void
-runtime_profiler_monitor_acquired (
-       MonoProfiler *prof,
-       MonoObject *obj)
-{
-       ep_rt_mono_write_event_monitor_contention_stop (obj);
-}
-
-static
-void
-runtime_profiler_monitor_failed (
-       MonoProfiler *prof,
-       MonoObject *obj)
-{
-       ep_rt_mono_write_event_monitor_contention_stop (obj);
-}
-
-static
-void
-runtime_profiler_jit_code_buffer (
-       MonoProfiler *prof,
-       const mono_byte *buffer,
-       uint64_t size,
-       MonoProfilerCodeBufferType type,
-       const void *data)
-{
-       ep_rt_mono_write_event_method_jit_memory_allocated_for_code ((const uint8_t *)buffer, size, type, data);
-}
-
-void
-EventPipeEtwCallbackDotNETRuntime (
-       const uint8_t *source_id,
-       unsigned long is_enabled,
-       uint8_t level,
-       uint64_t match_any_keywords,
-       uint64_t match_all_keywords,
-       EventFilterDescriptor *filter_data,
-       void *callback_data)
-{
-       ep_rt_config_requires_lock_not_held ();
-
-       EP_ASSERT(is_enabled == 0 || is_enabled == 1) ;
-       EP_ASSERT (_ep_rt_dotnet_runtime_profiler_provider != NULL);
-
-       match_any_keywords = (is_enabled == 1) ? match_any_keywords : 0;
-
-       EP_LOCK_ENTER (section1)
-               uint64_t enabled_keywords = MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask;
-
-               if (profiler_callback_is_enabled(match_any_keywords, JIT_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, JIT_KEYWORD)) {
-                               mono_profiler_set_jit_begin_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_jit_begin);
-                               mono_profiler_set_jit_failed_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_jit_failed);
-                               mono_profiler_set_jit_done_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_jit_done);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, JIT_KEYWORD)) {
-                               mono_profiler_set_jit_begin_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                               mono_profiler_set_jit_failed_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                               mono_profiler_set_jit_done_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, LOADER_KEYWORD)) {
-                       if (!profiler_callback_is_enabled(enabled_keywords, LOADER_KEYWORD)) {
-                               mono_profiler_set_image_loaded_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_image_loaded);
-                               mono_profiler_set_image_unloaded_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_image_unloaded);
-                               mono_profiler_set_assembly_loaded_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_assembly_loaded);
-                               mono_profiler_set_assembly_unloaded_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_assembly_unloaded);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, LOADER_KEYWORD)) {
-                               mono_profiler_set_image_loaded_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                               mono_profiler_set_image_unloaded_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                               mono_profiler_set_assembly_loaded_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                               mono_profiler_set_assembly_unloaded_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD) || profiler_callback_is_enabled(match_any_keywords, THREADING_KEYWORD)) {
-                       if (!(profiler_callback_is_enabled(enabled_keywords, APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD) && profiler_callback_is_enabled(enabled_keywords, THREADING_KEYWORD))) {
-                               mono_profiler_set_thread_started_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_thread_started);
-                               mono_profiler_set_thread_stopped_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_thread_stopped);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD) || profiler_callback_is_enabled (enabled_keywords, THREADING_KEYWORD)) {
-                               mono_profiler_set_thread_started_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                               mono_profiler_set_thread_stopped_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, TYPE_DIAGNOSTIC_KEYWORD)) {
-                       if (!profiler_callback_is_enabled(enabled_keywords, TYPE_DIAGNOSTIC_KEYWORD)) {
-                               mono_profiler_set_class_loading_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_class_loading);
-                               mono_profiler_set_class_failed_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_class_failed);
-                               mono_profiler_set_class_loaded_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_class_loaded);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, TYPE_DIAGNOSTIC_KEYWORD)) {
-                               mono_profiler_set_class_loading_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                               mono_profiler_set_class_failed_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                               mono_profiler_set_class_loaded_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, EXCEPTION_KEYWORD)) {
-                       if (!profiler_callback_is_enabled(enabled_keywords, EXCEPTION_KEYWORD)) {
-                               mono_profiler_set_exception_throw_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_exception_throw);
-                               mono_profiler_set_exception_clause_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_exception_clause);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, EXCEPTION_KEYWORD)) {
-                               mono_profiler_set_exception_throw_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                               mono_profiler_set_exception_clause_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, CONTENTION_KEYWORD)) {
-                       if (!profiler_callback_is_enabled(enabled_keywords, CONTENTION_KEYWORD)) {
-                               mono_profiler_set_monitor_contention_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_monitor_contention);
-                               mono_profiler_set_monitor_acquired_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_monitor_acquired);
-                               mono_profiler_set_monitor_failed_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_monitor_failed);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, CONTENTION_KEYWORD)) {
-                               mono_profiler_set_monitor_contention_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                               mono_profiler_set_monitor_acquired_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                               mono_profiler_set_monitor_failed_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL);
-                       }
-               }
-
-               MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.Level = level;
-               MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords;
-               MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false);
-       EP_LOCK_EXIT (section1)
-
-ep_on_exit:
-       ep_rt_config_requires_lock_not_held ();
-       return;
-
-ep_on_error:
-       ep_exit_error_handler ();
-}
-
-void
-EventPipeEtwCallbackDotNETRuntimeRundown (
-       const uint8_t *source_id,
-       unsigned long is_enabled,
-       uint8_t level,
-       uint64_t match_any_keywords,
-       uint64_t match_all_keywords,
-       EventFilterDescriptor *filter_data,
-       void *callback_data)
-{
-       MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.Level = level;
-       MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords;
-       MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false);
-}
-
-void
-EventPipeEtwCallbackDotNETRuntimePrivate (
-       const uint8_t *source_id,
-       unsigned long is_enabled,
-       uint8_t level,
-       uint64_t match_any_keywords,
-       uint64_t match_all_keywords,
-       EventFilterDescriptor *filter_data,
-       void *callback_data)
-{
-       MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context.Level = level;
-       MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords;
-       MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false);
-}
-
-void
-EventPipeEtwCallbackDotNETRuntimeStress (
-       const uint8_t *source_id,
-       unsigned long is_enabled,
-       uint8_t level,
-       uint64_t match_any_keywords,
-       uint64_t match_all_keywords,
-       EventFilterDescriptor *filter_data,
-       void *callback_data)
-{
-       MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_EVENTPIPE_Context.Level = level;
-       MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords;
-       MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false);
-}
-
-static
-inline
-mono_profiler_gc_state_t
-mono_profiler_volatile_load_gc_state_t (const volatile mono_profiler_gc_state_t *ptr)
-{
-       return ep_rt_volatile_load_uint32_t ((const volatile uint32_t *)ptr);
-}
-
-static
-inline
-mono_profiler_gc_state_t
-mono_profiler_atomic_cas_gc_state_t (volatile mono_profiler_gc_state_t *target, mono_profiler_gc_state_t expected, mono_profiler_gc_state_t value)
-{
-       return (mono_profiler_gc_state_t)(mono_atomic_cas_i32 ((volatile gint32 *)(target), (gint32)(value), (gint32)(expected)));
-}
-
-static
-void
-mono_profiler_fire_event_enter (void)
-{
-       mono_profiler_gc_state_t old_state = 0;
-       mono_profiler_gc_state_t new_state = 0;
-
-       // NOTE, mono_profiler_fire_event_start should never be called recursivly.
-       do {
-               old_state = mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state);
-               if (MONO_PROFILER_GC_STATE_IS_GC_IN_PROGRESS (old_state)) {
-                       // GC in progress and thread tries to fire event (this should be an unlikely scenario). Wait until GC is done.
-                       ep_rt_spin_lock_acquire (&_ep_rt_mono_profiler_gc_state_lock);
-                       ep_rt_spin_lock_release (&_ep_rt_mono_profiler_gc_state_lock);
-                       old_state = mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state);
-               }
-               // Increase number of fire event calls.
-               new_state = MONO_PROFILER_GC_STATE_INC_FIRE_EVENT_COUNT (old_state);
-       } while (mono_profiler_atomic_cas_gc_state_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state);
-}
-
-static
-void
-mono_profiler_fire_event_exit (void)
-{
-       mono_profiler_gc_state_t old_state = 0;
-       mono_profiler_gc_state_t new_state = 0;
-
-       do {
-               old_state = mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state);
-               new_state = MONO_PROFILER_GC_STATE_DEC_FIRE_EVENT_COUNT (old_state);
-       } while (mono_profiler_atomic_cas_gc_state_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state);
-}
-
-static
-void
-mono_profiler_gc_in_progress_start (void)
-{
-       mono_profiler_gc_state_t old_state = 0;
-       mono_profiler_gc_state_t new_state = 0;
-
-       // Make sure fire event calls will block and wait for GC completion.
-       ep_rt_spin_lock_acquire (&_ep_rt_mono_profiler_gc_state_lock);
-
-       // Set gc in progress state, preventing new fire event requests.
-       do {
-               old_state = mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state);
-               EP_ASSERT (!MONO_PROFILER_GC_STATE_IS_GC_IN_PROGRESS (old_state));
-               new_state = MONO_PROFILER_GC_STATE_GC_IN_PROGRESS_START (old_state);
-       } while (mono_profiler_atomic_cas_gc_state_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state);
-
-       mono_profiler_gc_state_count_t count = MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT (new_state);
-
-       // Wait for all fire events to complete before progressing with gc.
-       // NOTE, mono_profiler_fire_event_start should never be called recursivly.
-       // Default yield count used in SpinLock.cs.
-       int yield_count = 40;
-       while (count) {
-               if (yield_count > 0) {
-                       ep_rt_mono_thread_yield ();
-                       yield_count--;
-               } else {
-                       ep_rt_thread_sleep (200);
-               }
-               count = MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT (mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state));
-       }
-}
-
-static
-void
-mono_profiler_gc_in_progress_stop (void)
-{
-       mono_profiler_gc_state_t old_state = 0;
-       mono_profiler_gc_state_t new_state = 0;
-
-       // Reset gc in progress state.
-       do {
-               old_state = mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state);
-               EP_ASSERT (MONO_PROFILER_GC_STATE_IS_GC_IN_PROGRESS (old_state));
-
-               new_state = MONO_PROFILER_GC_STATE_GC_IN_PROGRESS_STOP (old_state);
-               EP_ASSERT (!MONO_PROFILER_GC_STATE_IS_GC_IN_PROGRESS (new_state));
-       } while (mono_profiler_atomic_cas_gc_state_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state);
-
-       // Make sure fire events can continune to execute.
-       ep_rt_spin_lock_release (&_ep_rt_mono_profiler_gc_state_lock);
-}
-
-static
-inline
-bool
-mono_profiler_gc_in_progress (void)
-{
-       return MONO_PROFILER_GC_STATE_IS_GC_IN_PROGRESS (mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state));
-}
-
-static
-inline
-bool
-mono_profiler_gc_can_collect_heap (void)
-{
-       return _ep_rt_mono_profiler_gc_can_collect_heap;
-}
-
-static
-inline
-void
-mono_profiler_gc_heap_collect_requests_inc (void)
-{
-       EP_ASSERT (mono_profiler_gc_can_collect_heap ());
-       ep_rt_atomic_inc_uint32_t (&_ep_rt_mono_profiler_gc_heap_collect_requests);
-}
-
-static
-inline
-void
-mono_profiler_gc_heap_collect_requests_dec (void)
-{
-       EP_ASSERT (mono_profiler_gc_can_collect_heap ());
-       ep_rt_atomic_dec_uint32_t (&_ep_rt_mono_profiler_gc_heap_collect_requests);
-}
-
-static
-inline
-bool
-mono_profiler_gc_heap_collect_requested (void)
-{
-       if (!mono_profiler_gc_can_collect_heap ())
-               return false;
-
-       return ep_rt_volatile_load_uint32_t(&_ep_rt_mono_profiler_gc_heap_collect_requests) != 0 ? true : false;
-}
-
-static
-inline
-bool
-mono_profiler_gc_heap_collect_in_progress (void)
-{
-       ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock);
-       return ep_rt_volatile_load_uint32_t_without_barrier (&_ep_rt_mono_profiler_gc_heap_collect_in_progress) != 0 ? true : false;
-}
-
-static
-inline
-void
-mono_profiler_gc_heap_collect_in_progress_start (void)
-{
-       EP_ASSERT (mono_profiler_gc_can_collect_heap ());
-
-       ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock);
-       ep_rt_volatile_store_uint32_t_without_barrier (&_ep_rt_mono_profiler_gc_heap_collect_in_progress, 1);
-}
-
-static
-inline
-void
-mono_profiler_gc_heap_collect_in_progress_stop (void)
-{
-       EP_ASSERT (mono_profiler_gc_can_collect_heap ());
-
-       ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock);
-       ep_rt_volatile_store_uint32_t_without_barrier (&_ep_rt_mono_profiler_gc_heap_collect_in_progress, 0);
-}
-
-static
-MonoProfilerMemBlock *
-mono_profiler_mem_block_alloc (uint32_t req_size)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       MonoProfilerMemBlock *prev = NULL;
-
-       uint32_t size = MONO_PROFILER_MEM_DEFAULT_BLOCK_SIZE;
-       while (size - sizeof(MonoProfilerMemBlock) < req_size)
-               size += MONO_PROFILER_MEM_BLOCK_SIZE_INC;
-
-       MonoProfilerMemBlock *block = mono_valloc (NULL, size, MONO_MMAP_READ | MONO_MMAP_WRITE | MONO_MMAP_ANON | MONO_MMAP_PRIVATE, MONO_MEM_ACCOUNT_PROFILER);
-       if (block) {
-               block->alloc_size = size;
-               block->start = (uint8_t *)ALIGN_PTR_TO ((uint8_t *)block + sizeof (MonoProfilerMemBlock), 16);
-               block->size = (uint32_t)(((uint8_t*)block + size) - (uint8_t*)block->start);
-               block->offset = 0;
-               block->last_used_offset = 0;
-
-               while (true) {
-                       prev = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_mem_blocks);
-                       if (mono_atomic_cas_ptr ((volatile gpointer*)&_ep_rt_mono_profiler_mem_blocks, block, prev) == prev)
-                               break;
-               }
-
-               if (prev)
-                       prev->next = block;
-               block->prev = prev;
-       }
-
-       return block;
-}
-
-static
-uint8_t *
-mono_profiler_mem_alloc (uint32_t req_size)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       MonoProfilerMemBlock *current_block = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_current_mem_block);
-       uint8_t *buffer = NULL;
-
-       if (!current_block) {
-               current_block = mono_profiler_mem_block_alloc (req_size);
-               if (current_block) {
-                       mono_memory_barrier ();
-                       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_current_mem_block, current_block);
-               }
-       }
-
-       if (current_block) {
-               uint32_t prev_offset = (uint32_t)mono_atomic_fetch_add_i32 ((volatile int32_t *)&current_block->offset, (int32_t)req_size);
-               if (prev_offset + req_size > current_block->size) {
-                       if (prev_offset <= current_block->size)
-                               current_block->last_used_offset = prev_offset;
-                       current_block = mono_profiler_mem_block_alloc (req_size);
-                       if (current_block) {
-                               buffer = current_block->start;
-                               current_block->offset += req_size;
-                               mono_memory_barrier ();
-                               ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_current_mem_block, current_block);
-                       }
-               } else {
-                       buffer = (uint8_t*)current_block->start + prev_offset;
-               }
-       }
-
-       return buffer;
-}
-
-static
-void
-mono_profiler_mem_block_free_all (void)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       MonoProfilerMemBlock *current_block = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr ((volatile void **)&_ep_rt_mono_profiler_current_mem_block);
-
-       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_current_mem_block, NULL);
-       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_mem_blocks, NULL);
-
-       mono_memory_barrier ();
-
-       while (current_block) {
-               MonoProfilerMemBlock *prev_block = current_block->prev;
-               mono_vfree ((uint8_t *)current_block, current_block->alloc_size, MONO_MEM_ACCOUNT_MEM_MANAGER);
-               current_block = prev_block;
-       }
-}
-
-static
-void
-mono_profiler_mem_block_free_all_but_current (void)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       MonoProfilerMemBlock *block_to_keep = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr ((volatile void **)&_ep_rt_mono_profiler_current_mem_block);
-       MonoProfilerMemBlock *current_block = block_to_keep;
-
-       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_current_mem_block, NULL);
-       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_mem_blocks, NULL);
-
-       mono_memory_barrier ();
-
-       if (current_block) {
-               if (current_block->prev) {
-                       current_block = current_block->prev;
-                       while (current_block) {
-                               MonoProfilerMemBlock *prev_block = current_block->prev;
-                               mono_vfree ((uint8_t *)current_block, current_block->alloc_size, MONO_MEM_ACCOUNT_MEM_MANAGER);
-                               current_block = prev_block;
-                       }
-               }
-       }
-
-       if (block_to_keep) {
-               block_to_keep->prev = NULL;
-               block_to_keep->next = NULL;
-               block_to_keep->offset = 0;
-               block_to_keep->last_used_offset = 0;
-       }
-
-       mono_memory_barrier ();
-
-       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_current_mem_block, block_to_keep);
-       ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_mem_blocks, block_to_keep);
-}
-
-static
-inline
-uint8_t *
-mono_profiler_buffered_gc_event_alloc (uint32_t req_size)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-       return mono_profiler_mem_alloc (req_size + sizeof (MonoProfilerBufferedGCEvent));
-}
-
-static
-void
-mono_profiler_trigger_heap_collect (MonoProfiler *prof)
-{
-       if (mono_profiler_gc_heap_collect_requested ()) {
-               ep_rt_spin_lock_acquire (&_ep_rt_mono_profiler_gc_state_lock);
-                       mono_profiler_gc_heap_collect_requests_dec ();
-                       mono_profiler_gc_heap_collect_in_progress_start ();
-               ep_rt_spin_lock_release (&_ep_rt_mono_profiler_gc_state_lock);
-
-               mono_gc_collect (mono_gc_max_generation ());
-
-               ep_rt_spin_lock_acquire (&_ep_rt_mono_profiler_gc_state_lock);
-                       mono_profiler_pop_gc_heap_collect_param_request_value ();
-                       mono_profiler_gc_heap_collect_in_progress_stop ();
-               ep_rt_spin_lock_release (&_ep_rt_mono_profiler_gc_state_lock);
-       }
-}
-
-static
-void
-mono_profiler_fire_gc_event_root_register (
-       uint8_t *data,
-       uint32_t payload_size)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       uintptr_t root_id;
-       uintptr_t root_size;
-       uint8_t root_source;
-       uintptr_t root_key;
-
-       memcpy (&root_id, data, sizeof (root_id));
-       data += sizeof (root_id);
-
-       memcpy (&root_size, data, sizeof (root_size));
-       data += sizeof (root_size);
-
-       memcpy (&root_source, data, sizeof (root_source));
-       data += sizeof (root_source);
-
-       memcpy (&root_key, data, sizeof (root_key));
-       data += sizeof (root_key);
-
-       FireEtwMonoProfilerGCRootRegister (
-               (const void *)root_id,
-               (uint64_t)root_size,
-               root_source,
-               (uint64_t)root_key,
-               (const ep_char8_t *)data,
-               NULL,
-               NULL);
-}
-
-static
-void
-mono_profiler_fire_buffered_gc_event_root_register (
-       MonoProfiler *prof,
-       const mono_byte *start,
-       uintptr_t size,
-       MonoGCRootSource source,
-       const void * key,
-       const char * name)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       uintptr_t root_id = (uintptr_t)start;
-       uintptr_t root_size = size;
-       uint8_t root_source = (uint8_t)source;
-       uintptr_t root_key = (uintptr_t)key;
-       const char *root_name = (name ? name : "");
-       size_t root_name_len = strlen (root_name) + 1;
-
-       MonoProfilerBufferedGCEvent gc_event_data;
-       gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT_ROOT_REGISTER;
-       gc_event_data.payload_size = (uint32_t)
-               (sizeof (root_id) +
-               sizeof (root_size) +
-               sizeof (root_source) +
-               sizeof (root_key) +
-               root_name_len);
-
-       uint8_t * buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size);
-       if (buffer) {
-               // Internal header
-               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
-               buffer += sizeof (gc_event_data);
-
-               // GCEvent.RootID
-               memcpy(buffer, &root_id, sizeof (root_id));
-               buffer += sizeof (root_id);
-
-               // GCEvent.RootSize
-               memcpy(buffer, &root_size, sizeof (root_size));
-               buffer += sizeof (root_size);
-
-               // GCEvent.RootType
-               memcpy(buffer, &root_source, sizeof (root_source));
-               buffer += sizeof (root_source);
-
-               // GCEvent.RootKeyID
-               memcpy(buffer, &root_key, sizeof (root_key));
-               buffer += sizeof (root_key);
-
-               // GCEvent.RootKeyName
-               memcpy(buffer, root_name, root_name_len);
-       }
-}
-
-static
-void
-mono_profiler_fire_gc_event_root_unregister (
-       uint8_t *data,
-       uint32_t payload_size)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       uintptr_t root_id;
-
-       memcpy (&root_id, data, sizeof (root_id));
-
-       FireEtwMonoProfilerGCRootUnregister (
-               (const void *)root_id,
-               NULL,
-               NULL);
-}
-
-static
-void
-mono_profiler_fire_buffered_gc_event_root_unregister (
-       MonoProfiler *prof,
-       const mono_byte *start)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       uintptr_t root_id = (uintptr_t)start;
-
-       MonoProfilerBufferedGCEvent gc_event_data;
-       gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT_ROOT_UNREGISTER;
-       gc_event_data.payload_size = sizeof (root_id);
-
-       uint8_t * buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size);
-       if (buffer) {
-               // Internal header
-               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
-               buffer += sizeof (gc_event_data);
-
-               // GCEvent.RootID
-               memcpy(buffer, &root_id, sizeof (root_id));
-       }
-}
-
-static
-void
-mono_profiler_fire_gc_event (
-       uint8_t *data,
-       uint32_t payload_size)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       uint8_t gc_event_type;
-       uint32_t generation;
-
-       memcpy (&gc_event_type, data, sizeof (gc_event_type));
-       data += sizeof (gc_event_type);
-
-       memcpy (&generation, data, sizeof (generation));
-
-       FireEtwMonoProfilerGCEvent (
-               gc_event_type,
-               generation,
-               NULL,
-               NULL);
-}
-
-static
-void
-mono_profiler_fire_buffered_gc_event (
-       uint8_t gc_event_type,
-       uint32_t generation)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       MonoProfilerBufferedGCEvent gc_event_data;
-       gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT;
-       gc_event_data.payload_size =
-               sizeof (gc_event_type) +
-               sizeof (generation);
-
-       uint8_t * buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size);
-       if (buffer) {
-               // Internal header
-               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
-               buffer += sizeof (gc_event_data);
-
-               // GCEvent.GCEventType
-               memcpy(buffer, &gc_event_type, sizeof (gc_event_type));
-               buffer += sizeof (gc_event_type);
-
-               // GCEvent.GCGeneration
-               memcpy(buffer, &generation, sizeof (generation));
-       }
-}
-
-static
-void
-mono_profiler_fire_gc_event_resize (
-       uint8_t *data,
-       uint32_t payload_size)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       uintptr_t size;
-
-       memcpy (&size, data, sizeof (size));
-
-       FireEtwMonoProfilerGCResize (
-               (uint64_t)size,
-               NULL,
-               NULL);
-}
-
-static
-void
-mono_profiler_fire_buffered_gc_event_resize (
-       MonoProfiler *prof,
-       uintptr_t size)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       MonoProfilerBufferedGCEvent gc_event_data;
-       gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT_RESIZE;
-       gc_event_data.payload_size = sizeof (size);
-
-       uint8_t * buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size);
-       if (buffer) {
-               // Internal header
-               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
-               buffer += sizeof (gc_event_data);
-
-               // GCResize.NewSize
-               memcpy(buffer, &size, sizeof (size));
-       }
-}
-
-static
-void
-mono_profiler_fire_gc_event_moves (
-       uint8_t *data,
-       uint32_t payload_size)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       uint64_t count;
-
-       memcpy (&count, data, sizeof (count));
-       data += sizeof (count);
-
-       FireEtwMonoProfilerGCMoves (
-               (uint32_t)count,
-               sizeof (uintptr_t) + sizeof (uintptr_t),
-               data,
-               NULL,
-               NULL);
-}
-
-static
-void
-mono_profiler_fire_buffered_gc_event_moves (
-       MonoProfiler *prof,
-       MonoObject *const* objects,
-       uint64_t count)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       uintptr_t object_id;
-       uintptr_t address_id;
-
-       // Serialized as object_id/address_id pairs.
-       count = count / 2;
-
-       MonoProfilerBufferedGCEvent gc_event_data;
-       gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT_MOVES;
-       gc_event_data.payload_size =
-               (uint32_t)(sizeof (count) +
-               (count * (sizeof (uintptr_t) + sizeof (uintptr_t))));
-
-       uint8_t * buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size);
-       if (buffer) {
-               // Internal header
-               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
-               buffer += sizeof (gc_event_data);
-
-               // GCMoves.Count
-               memcpy (buffer, &count, sizeof (count));
-               buffer += sizeof (count);
-
-               // Serialize directly as memory stream expected by FireEtwMonoProfilerGCMoves.
-               for (uint64_t i = 0; i < count; i++) {
-                       // GCMoves.Values[].ObjectID.
-                       object_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (*objects);
-                       ep_write_buffer_uintptr_t (&buffer, object_id);
-                       objects++;
-
-                       // GCMoves.Values[].AddressID.
-                       address_id = (uintptr_t)*objects;
-                       ep_write_buffer_uintptr_t (&buffer, address_id);
-                       objects++;
-               }
-       }
-}
-
-static
-void
-mono_profiler_fire_gc_event_roots (
-       uint8_t *data,
-       uint32_t payload_size)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       uint64_t count;
-
-       memcpy (&count, data, sizeof (count));
-       data += sizeof (count);
-
-       FireEtwMonoProfilerGCRoots (
-               (uint32_t)count,
-               sizeof (uintptr_t) + sizeof (uintptr_t),
-               data,
-               NULL,
-               NULL);
-}
-
-static
-void
-mono_profiler_fire_buffered_gc_event_roots (
-       MonoProfiler *prof,
-       uint64_t count,
-       const mono_byte *const * addresses,
-       MonoObject *const * objects)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       uintptr_t object_id;
-       uintptr_t address_id;
-
-       MonoProfilerBufferedGCEvent gc_event_data;
-       gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT_ROOTS;
-       gc_event_data.payload_size =
-               (uint32_t)(sizeof (count) +
-               (count * (sizeof (uintptr_t) + sizeof (uintptr_t))));
-
-       uint8_t * buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size);
-       if (buffer) {
-               // Internal header
-               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
-               buffer += sizeof (gc_event_data);
-
-               // GCRoots.Count
-               memcpy (buffer, &count, sizeof (count));
-               buffer += sizeof (count);
-
-               // Serialize directly as memory stream expected by FireEtwMonoProfilerGCRoots.
-               for (uint64_t i = 0; i < count; i++) {
-                       // GCRoots.Values[].ObjectID.
-                       object_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (*objects);
-                       ep_write_buffer_uintptr_t (&buffer, object_id);
-                       objects++;
-
-                       // GCRoots.Values[].AddressID.
-                       address_id = (uintptr_t)*addresses;
-                       ep_write_buffer_uintptr_t (&buffer, address_id);
-                       addresses++;
-               }
-       }
-}
-
-static
-void
-mono_profiler_fire_gc_event_heap_dump_object_reference (
-       uint8_t *data,
-       uint32_t payload_size,
-       GHashTable *cache)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       uintptr_t object_id;
-       uintptr_t vtable_id;
-       uintptr_t object_size;
-       uint8_t object_gen;
-       uintptr_t object_ref_count;
-
-       memcpy (&object_id, data, sizeof (object_id));
-       data += sizeof (object_id);
-
-       memcpy (&vtable_id, data, sizeof (vtable_id));
-       data += sizeof (vtable_id);
-
-       memcpy (&object_size, data, sizeof (object_size));
-       data += sizeof (object_size);
-
-       memcpy (&object_gen, data, sizeof (object_gen));
-       data += sizeof (object_gen);
-
-       memcpy (&object_ref_count, data, sizeof (object_ref_count));
-       data += sizeof (object_ref_count);
-
-       FireEtwMonoProfilerGCHeapDumpObjectReference (
-               (const void *)object_id,
-               (uint64_t)vtable_id,
-               (uint64_t)object_size,
-               object_gen,
-               (uint32_t)object_ref_count,
-               sizeof (uint32_t) + sizeof (uintptr_t),
-               data,
-               NULL,
-               NULL);
-
-       if (cache)
-               g_hash_table_insert (cache, (MonoVTable *)SGEN_POINTER_UNTAG_ALL (vtable_id), NULL);
-}
-
-static
-int
-mono_profiler_fire_buffered_gc_event_heap_dump_object_reference (
-       MonoObject *obj,
-       MonoClass *klass,
-       uintptr_t size,
-       uintptr_t num,
-       MonoObject **refs,
-       uintptr_t *offsets,
-       void *data)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       uintptr_t object_id;
-       uintptr_t vtable_id;
-       uint8_t object_gen;
-       uintptr_t object_size = size;
-       uintptr_t object_ref_count = num;
-       uint32_t object_ref_offset;
-
-       /* account for object alignment */
-       object_size += 7;
-       object_size &= ~7;
-
-       size_t payload_size =
-               sizeof (object_id) +
-               sizeof (vtable_id) +
-               sizeof (object_size) +
-               sizeof (object_gen) +
-               sizeof (object_ref_count) +
-               (object_ref_count * (sizeof (uint32_t) + sizeof (uintptr_t)));
-
-       MonoProfilerBufferedGCEvent gc_event_data;
-       gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT_OBJECT_REF;
-       gc_event_data.payload_size = GSIZE_TO_UINT32 (payload_size);
-
-       uint8_t *buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size);
-       if (buffer) {
-               // Internal header
-               memcpy (buffer, &gc_event_data, sizeof (gc_event_data));
-               buffer += sizeof (gc_event_data);
-
-               // GCEvent.ObjectID
-               object_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (obj);
-               memcpy (buffer, &object_id, sizeof (object_id));
-               buffer += sizeof (object_id);
-
-               // GCEvent.VTableID
-               vtable_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (mono_object_get_vtable_internal (obj));
-               memcpy (buffer, &vtable_id, sizeof (vtable_id));
-               buffer += sizeof (vtable_id);
-
-               // GCEvent.ObjectSize
-               memcpy (buffer, &object_size, sizeof (object_size));
-               buffer += sizeof (object_size);
-
-               // GCEvent.ObjectGeneration
-               object_gen = (uint8_t)mono_gc_get_generation (obj);
-               memcpy (buffer, &object_gen, sizeof (object_gen));
-               buffer += sizeof (object_gen);
-
-               // GCEvent.Count
-               memcpy (buffer, &object_ref_count, sizeof (object_ref_count));
-               buffer += sizeof (object_ref_count);
-
-               // Serialize directly as memory stream expected by FireEtwMonoProfilerGCHeapDumpObjectReference.
-               uintptr_t last_offset = 0;
-               for (uintptr_t i = 0; i < object_ref_count; i++) {
-                       // GCEvent.Values[].ReferencesOffset
-                       object_ref_offset = GUINTPTR_TO_UINT32 (offsets [i] - last_offset);
-                       ep_write_buffer_uint32_t (&buffer, object_ref_offset);
-
-                       // GCEvent.Values[].ObjectID
-                       object_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (refs[i]);
-                       ep_write_buffer_uintptr_t (&buffer, object_id);
-
-                       last_offset = offsets [i];
-               }
-       }
-
-       return 0;
-}
-
-static
-void
-mono_profiler_fire_buffered_gc_events (
-       MonoProfilerMemBlock *block,
-       GHashTable *cache)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       if (block) {
-               uint32_t current_offset = 0;
-               uint32_t used_size = (block->offset < block->size) ? block->offset : block->last_used_offset;
-               MonoProfilerBufferedGCEvent gc_event;
-               while ((current_offset + sizeof (gc_event)) <= used_size) {
-                       uint8_t *data = block->start + current_offset;
-                       memcpy (&gc_event, data, sizeof (gc_event));
-                       data += sizeof (gc_event);
-                       if ((current_offset + sizeof (gc_event) + gc_event.payload_size) <= used_size) {
-                               switch (gc_event.type) {
-                               case MONO_PROFILER_BUFFERED_GC_EVENT:
-                                       mono_profiler_fire_gc_event (data, gc_event.payload_size);
-                                       break;
-                               case MONO_PROFILER_BUFFERED_GC_EVENT_RESIZE:
-                                       mono_profiler_fire_gc_event_resize (data, gc_event.payload_size);
-                                       break;
-                               case MONO_PROFILER_BUFFERED_GC_EVENT_ROOTS:
-                                       mono_profiler_fire_gc_event_roots (data, gc_event.payload_size);
-                                       break;
-                               case MONO_PROFILER_BUFFERED_GC_EVENT_MOVES:
-                                       mono_profiler_fire_gc_event_moves (data, gc_event.payload_size);
-                                       break;
-                               case MONO_PROFILER_BUFFERED_GC_EVENT_OBJECT_REF:
-                                       mono_profiler_fire_gc_event_heap_dump_object_reference (data, gc_event.payload_size, cache);
-                                       break;
-                               case MONO_PROFILER_BUFFERED_GC_EVENT_ROOT_REGISTER:
-                                       mono_profiler_fire_gc_event_root_register (data, gc_event.payload_size);
-                                       break;
-                               case MONO_PROFILER_BUFFERED_GC_EVENT_ROOT_UNREGISTER:
-                                       mono_profiler_fire_gc_event_root_unregister (data, gc_event.payload_size);
-                                       break;
-                               default:
-                                       EP_ASSERT (!"Unknown buffered GC event type.");
-                               }
-
-                               current_offset += sizeof (gc_event) + gc_event.payload_size;
-                       } else {
-                               break;
-                       }
-               }
-       }
-}
-
-static
-void
-mono_profiler_fire_buffered_gc_events_in_alloc_order (GHashTable *cache)
-{
-       EP_ASSERT (mono_profiler_gc_in_progress ());
-
-       MonoProfilerMemBlock *first_block = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr ((volatile void **)&_ep_rt_mono_profiler_current_mem_block);
-       while (first_block && first_block->prev)
-               first_block = first_block->prev;
-
-       MonoProfilerMemBlock *current_block = first_block;
-       while (current_block) {
-               MonoProfilerMemBlock *next_block = current_block->next;
-               mono_profiler_fire_buffered_gc_events (current_block, cache);
-               current_block = next_block;
-       }
-
-       mono_profiler_mem_block_free_all_but_current ();
-}
-
-static
-void
-mono_profiler_fire_cached_gc_events (GHashTable *cache)
-{
-       if (cache) {
-               GHashTableIter iter;
-               MonoVTable *object_vtable;
-               g_hash_table_iter_init (&iter, cache);
-               while (g_hash_table_iter_next (&iter, (void**)&object_vtable, NULL)) {
-                       if (object_vtable) {
-                               uint64_t vtable_id = (uint64_t)object_vtable;
-                               uint64_t class_id;
-                               uint64_t module_id;
-                               ep_char8_t *class_name;
-                               mono_profiler_get_class_data (object_vtable->klass, &class_id, &module_id, &class_name, NULL, NULL);
-                               FireEtwMonoProfilerGCHeapDumpVTableClassReference (
-                                       vtable_id,
-                                       class_id,
-                                       module_id,
-                                       class_name,
-                                       NULL,
-                                       NULL);
-                               g_free (class_name);
-                       }
-               }
-       }
-}
-
-static
-void
-mono_profiler_app_domain_loading (
-       MonoProfiler *prof,
-       MonoDomain *domain)
-{
-       if (!EventEnabledMonoProfilerAppDomainLoading ())
-               return;
-
-       uint64_t domain_id = (uint64_t)domain;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerAppDomainLoading (
-               domain_id,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_app_domain_loaded (
-       MonoProfiler *prof,
-       MonoDomain *domain)
-{
-       if (!EventEnabledMonoProfilerAppDomainLoaded ())
-               return;
-
-       uint64_t domain_id = (uint64_t)domain;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerAppDomainLoaded (
-               domain_id,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_app_domain_unloading (
-       MonoProfiler *prof,
-       MonoDomain *domain)
-{
-       if (!EventEnabledMonoProfilerAppDomainUnloading ())
-               return;
-
-       uint64_t domain_id = (uint64_t)domain;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerAppDomainUnloading (
-               domain_id,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_app_domain_unloaded (
-       MonoProfiler *prof,
-       MonoDomain *domain)
-{
-       if (!EventEnabledMonoProfilerAppDomainUnloaded ())
-               return;
-
-       uint64_t domain_id = (uint64_t)domain;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerAppDomainUnloaded (
-               domain_id,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_app_domain_name (
-       MonoProfiler *prof,
-       MonoDomain *domain,
-       const char *name)
-{
-       if (!EventEnabledMonoProfilerAppDomainName ())
-               return;
-
-       uint64_t domain_id = (uint64_t)domain;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerAppDomainName (
-               domain_id,
-               (const ep_char8_t *)(name ? name : ""),
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_get_generic_types (
-       MonoGenericInst *generic_instance,
-       uint32_t *generic_type_count,
-       uint8_t **generic_types)
-{
-       if (generic_instance) {
-               uint8_t *buffer = g_malloc (generic_instance->type_argc * (sizeof (uint8_t) + sizeof (uint64_t)));
-               if (buffer) {
-                       *generic_types = buffer;
-                       *generic_type_count = generic_instance->type_argc;
-                       for (uint32_t i = 0; i < generic_instance->type_argc; ++i) {
-                               uint8_t type = generic_instance->type_argv [i]->type;
-                               ep_write_buffer_uint8_t (&buffer, type);
-
-                               uint64_t class_id = (uint64_t)mono_class_from_mono_type_internal (generic_instance->type_argv [i]);
-                               ep_write_buffer_uint64_t (&buffer, class_id);
-                       }
-               }
-       }
-}
-
-static
-void
-mono_profiler_get_jit_data (
-       MonoMethod *method,
-       uint64_t *method_id,
-       uint64_t *module_id,
-       uint32_t *method_token,
-       uint32_t *method_generic_type_count,
-       uint8_t **method_generic_types)
-{
-       *method_id = (uint64_t)method;
-       *module_id = 0;
-       *method_token = 0;
-
-       if (method) {
-               *method_token = method->token;
-               if (method->klass)
-                       *module_id = (uint64_t)m_class_get_image (method->klass);
-
-               if (method_generic_type_count && method_generic_types) {
-                       if (method->is_inflated) {
-                               MonoGenericContext *context = mono_method_get_context (method);
-                               MonoGenericInst *method_instance = (context && context->method_inst) ? context->method_inst : NULL;
-                               mono_profiler_get_generic_types (method_instance, method_generic_type_count, method_generic_types);
-                       }
-               }
-       }
-}
-
-static
-void
-mono_profiler_jit_begin (
-       MonoProfiler *prof,
-       MonoMethod *method)
-{
-       if (!EventEnabledMonoProfilerJitBegin ())
-               return;
-
-       uint64_t method_id;
-       uint64_t module_id;
-       uint32_t method_token;
-
-       mono_profiler_get_jit_data (method, &method_id, &module_id, &method_token, NULL, NULL);
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerJitBegin (
-               method_id,
-               module_id,
-               method_token,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_jit_failed (
-       MonoProfiler *prof,
-       MonoMethod *method)
-{
-       if (!EventEnabledMonoProfilerJitFailed ())
-               return;
-
-       uint64_t method_id;
-       uint64_t module_id;
-       uint32_t method_token;
-
-       mono_profiler_get_jit_data (method, &method_id, &module_id, &method_token, NULL, NULL);
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerJitFailed (
-               method_id,
-               module_id,
-               method_token,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_jit_done (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       MonoJitInfo *ji)
-{
-       if (!EventEnabledMonoProfilerJitDone () && !EventEnabledMonoProfilerJitDone_V1 () && !EventEnabledMonoProfilerJitDoneVerbose ())
-               return;
-
-       bool verbose = (MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.Level >= (uint8_t)EP_EVENT_LEVEL_VERBOSE);
-
-       uint64_t method_id;
-       uint64_t module_id;
-       uint32_t method_token;
-
-       uint32_t method_generic_type_count = 0;
-       uint8_t *method_generic_types = NULL;
-
-       char *method_namespace = NULL;
-       const char *method_name = NULL;
-       char *method_signature = NULL;
-
-       mono_profiler_get_jit_data (method, &method_id, &module_id, &method_token, &method_generic_type_count, &method_generic_types);
-
-       if (verbose) {
-               //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc.
-               method_name = method->name;
-               method_signature = mono_signature_full_name (mono_method_signature_internal (method));
-               if (method->klass)
-                       method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL);
-       }
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerJitDone_V1 (
-               method_id,
-               module_id,
-               method_token,
-               method_generic_type_count,
-               sizeof (uint8_t) + sizeof (uint64_t),
-               method_generic_types,
-               NULL,
-               NULL);
-
-       if (verbose) {
-               FireEtwMonoProfilerJitDoneVerbose (
-                       method_id,
-                       (const ep_char8_t *)method_namespace,
-                       (const ep_char8_t *)method_name,
-                       (const ep_char8_t *)method_signature,
-                       NULL,
-                       NULL);
-       }
-
-       mono_profiler_fire_event_exit ();
-
-       g_free (method_namespace);
-       g_free (method_signature);
-       g_free (method_generic_types);
-}
-
-static
-void
-mono_profiler_jit_chunk_created (
-       MonoProfiler *prof,
-       const mono_byte *chunk,
-       uintptr_t size)
-{
-       if (!EventEnabledMonoProfilerJitChunkCreated ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerJitChunkCreated (
-               chunk,
-               (uint64_t)size,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_jit_chunk_destroyed (
-       MonoProfiler *prof,
-       const mono_byte *chunk)
-{
-       if (!EventEnabledMonoProfilerJitChunkDestroyed ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerJitChunkDestroyed (
-               chunk,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_jit_code_buffer (
-       MonoProfiler *prof,
-       const mono_byte *buffer,
-       uint64_t size,
-       MonoProfilerCodeBufferType type,
-       const void *data)
-{
-       if (!EventEnabledMonoProfilerJitCodeBuffer ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerJitCodeBuffer (
-               buffer,
-               size,
-               (uint8_t)type,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_get_class_data (
-       MonoClass *klass,
-       uint64_t *class_id,
-       uint64_t *module_id,
-       ep_char8_t **class_name,
-       uint32_t *class_generic_type_count,
-       uint8_t **class_generic_types)
-{
-       *class_id = (uint64_t)klass;
-       *module_id = 0;
-
-       if (klass)
-               *module_id = (uint64_t)m_class_get_image (klass);
-
-       if (klass && class_name)
-               *class_name = (ep_char8_t *)mono_type_get_name_full (m_class_get_byval_arg (klass), MONO_TYPE_NAME_FORMAT_IL);
-       else if (class_name)
-               *class_name = NULL;
-
-       if (class_generic_type_count && class_generic_types) {
-               if (mono_class_is_ginst (klass)) {
-                       MonoGenericContext *context = mono_class_get_context (klass);
-                       MonoGenericInst *class_instance = (context && context->class_inst) ? context->class_inst : NULL;
-                       mono_profiler_get_generic_types (class_instance, class_generic_type_count, class_generic_types);
-               }
-       }
-}
-
-static
-void
-mono_profiler_class_loading (
-       MonoProfiler *prof,
-       MonoClass *klass)
-{
-       if (!EventEnabledMonoProfilerClassLoading ())
-               return;
-
-       uint64_t class_id;
-       uint64_t module_id;
-
-       mono_profiler_get_class_data (klass, &class_id, &module_id, NULL, NULL, NULL);
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerClassLoading (
-               class_id,
-               module_id,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_class_failed (
-       MonoProfiler *prof,
-       MonoClass *klass)
-{
-       if (!EventEnabledMonoProfilerClassFailed ())
-               return;
-
-       uint64_t class_id;
-       uint64_t module_id;
-
-       mono_profiler_get_class_data (klass, &class_id, &module_id, NULL, NULL, NULL);
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerClassFailed (
-               class_id,
-               module_id,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_class_loaded (
-       MonoProfiler *prof,
-       MonoClass *klass)
-{
-       if (!EventEnabledMonoProfilerClassLoaded () && !EventEnabledMonoProfilerClassLoaded_V1 ())
-               return;
-
-       uint64_t class_id;
-       uint64_t module_id;
-       ep_char8_t *class_name;
-
-       uint32_t class_generic_type_count = 0;
-       uint8_t *class_generic_types = NULL;
-
-       mono_profiler_get_class_data (klass, &class_id, &module_id, &class_name, &class_generic_type_count, &class_generic_types);
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerClassLoaded_V1 (
-               class_id,
-               module_id,
-               class_name ? class_name : "",
-               class_generic_type_count,
-               sizeof (uint8_t) + sizeof (uint64_t),
-               class_generic_types,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-
-       g_free (class_name);
-       g_free (class_generic_types);
-}
-
-static
-inline
-void
-get_vtable_data (
-       MonoVTable *vtable,
-       uint64_t *vtable_id,
-       uint64_t *class_id,
-       uint64_t *domain_id)
-{
-       *vtable_id = (uint64_t)vtable;
-       *class_id = 0;
-       *domain_id = 0;
-
-       if (vtable) {
-               *class_id = (uint64_t)mono_vtable_class_internal (vtable);
-               *domain_id = (uint64_t)mono_vtable_domain_internal (vtable);
-       }
-}
-
-static
-void
-mono_profiler_vtable_loading (
-       MonoProfiler *prof,
-       MonoVTable *vtable)
-{
-       if (!EventEnabledMonoProfilerVTableLoading ())
-               return;
-
-       uint64_t vtable_id;
-       uint64_t class_id;
-       uint64_t domain_id;
-
-       get_vtable_data (vtable, &vtable_id, &class_id, &domain_id);
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerVTableLoading (
-               vtable_id,
-               class_id,
-               domain_id,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_vtable_failed (
-       MonoProfiler *prof,
-       MonoVTable *vtable)
-{
-       if (!EventEnabledMonoProfilerVTableFailed ())
-               return;
-
-       uint64_t vtable_id;
-       uint64_t class_id;
-       uint64_t domain_id;
-
-       get_vtable_data (vtable, &vtable_id, &class_id, &domain_id);
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerVTableFailed (
-               vtable_id,
-               class_id,
-               domain_id,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_vtable_loaded (
-       MonoProfiler *prof,
-       MonoVTable *vtable)
-{
-       if (!EventEnabledMonoProfilerVTableLoaded ())
-               return;
-
-       uint64_t vtable_id;
-       uint64_t class_id;
-       uint64_t domain_id;
-
-       get_vtable_data (vtable, &vtable_id, &class_id, &domain_id);
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerVTableLoaded (
-               vtable_id,
-               class_id,
-               domain_id,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_module_loading (
-       MonoProfiler *prof,
-       MonoImage *image)
-{
-       if (!EventEnabledMonoProfilerModuleLoading ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerModuleLoading (
-               (uint64_t)image,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_module_failed (
-       MonoProfiler *prof,
-       MonoImage *image)
-{
-       if (!EventEnabledMonoProfilerModuleFailed ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerModuleFailed (
-               (uint64_t)image,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_module_loaded (
-       MonoProfiler *prof,
-       MonoImage *image)
+void *
+ep_rt_mono_thread_attach (bool background_thread)
 {
-       if (!EventEnabledMonoProfilerModuleLoaded ())
-               return;
-
-       uint64_t module_id = (uint64_t)image;
-       const ep_char8_t *module_path = NULL;
-       const ep_char8_t *module_guid = NULL;
+       MonoThread *thread = NULL;
 
-       if (image) {
-               ModuleEventData module_data;
-               memset (&module_data, 0, sizeof (module_data));
-               if (get_module_event_data (image, &module_data))
-                       module_path = (const ep_char8_t *)module_data.module_il_path;
-               module_guid = (const ep_char8_t *)mono_image_get_guid (image);
+       // NOTE, under netcore, only root domain exists.
+       if (!mono_thread_current ()) {
+               thread = mono_thread_internal_attach (mono_get_root_domain ());
+               if (background_thread && thread) {
+                       mono_thread_set_state (thread, ThreadState_Background);
+                       mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_SAMPLE);
+               }
        }
 
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerModuleLoaded (
-               module_id,
-               module_path ? module_path : "",
-               module_guid ? module_guid : "",
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_module_unloading (
-       MonoProfiler *prof,
-       MonoImage *image)
-{
-       if (!EventEnabledMonoProfilerModuleUnloading ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerModuleUnloading (
-               (uint64_t)image,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
+       return thread;
 }
 
-static
-void
-mono_profiler_module_unloaded (
-       MonoProfiler *prof,
-       MonoImage *image)
+void *
+ep_rt_mono_thread_attach_2 (bool background_thread, EventPipeThreadType thread_type)
 {
-       if (!EventEnabledMonoProfilerModuleUnloaded ())
-               return;
-
-       uint64_t module_id = (uint64_t)image;
-       const ep_char8_t *module_path = NULL;
-       const ep_char8_t *module_guid = NULL;
-
-       if (image) {
-               ModuleEventData module_data;
-               memset (&module_data, 0, sizeof (module_data));
-               if (get_module_event_data (image, &module_data))
-                       module_path = (const ep_char8_t *)module_data.module_il_path;
-               module_guid = (const ep_char8_t *)mono_image_get_guid (image);
+       void *result = ep_rt_mono_thread_attach (background_thread);
+       if (result && thread_type == EP_THREAD_TYPE_SAMPLING) {
+               // Increase sampling thread priority, accepting failures.
+#ifdef HOST_WIN32
+               SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
+#elif _POSIX_PRIORITY_SCHEDULING
+               int policy;
+               int priority;
+               struct sched_param param;
+               int schedparam_result = pthread_getschedparam (pthread_self (), &policy, &param);
+               if (schedparam_result == 0) {
+                       // Attempt to switch the thread to real time scheduling. This will not
+                       // necessarily work on all OSs; for example, most Linux systems will give
+                       // us EPERM here unless configured to allow this.
+                       priority = param.sched_priority;
+                       param.sched_priority = sched_get_priority_max (SCHED_RR);
+                       if (param.sched_priority != -1) {
+                               schedparam_result = pthread_setschedparam (pthread_self (), SCHED_RR, &param);
+                               if (schedparam_result != 0) {
+                                       // Fallback, attempt to increase to max priority using current policy.
+                                       param.sched_priority = sched_get_priority_max (policy);
+                                       if (param.sched_priority != -1 && param.sched_priority != priority)
+                                               pthread_setschedparam (pthread_self (), policy, &param);
+                               }
+                       }
+               }
+#endif
        }
 
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerModuleUnloaded (
-               module_id,
-               module_path ? module_path : "",
-               module_guid ? module_guid : "",
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-inline
-void
-get_assembly_data (
-       MonoAssembly *assembly,
-       uint64_t *assembly_id,
-       uint64_t *module_id,
-       ep_char8_t **assembly_name)
-{
-       *assembly_id = (uint64_t)assembly;
-       *module_id = 0;
-
-       if (assembly)
-               *module_id = (uint64_t)mono_assembly_get_image_internal (assembly);
-
-       if (assembly && assembly_name)
-               *assembly_name = (ep_char8_t *)mono_stringify_assembly_name (&assembly->aname);
-       else if (assembly_name)
-               *assembly_name = NULL;
-}
-
-static
-void
-mono_profiler_assembly_loading (
-       MonoProfiler *prof,
-       MonoAssembly *assembly)
-{
-       if (!EventEnabledMonoProfilerAssemblyLoading ())
-               return;
-
-       uint64_t assembly_id;
-       uint64_t module_id;
-
-       get_assembly_data (assembly, &assembly_id, &module_id, NULL);
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerAssemblyLoading (
-               assembly_id,
-               module_id,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_assembly_loaded (
-       MonoProfiler *prof,
-       MonoAssembly *assembly)
-{
-       if (!EventEnabledMonoProfilerAssemblyLoaded ())
-               return;
-
-       uint64_t assembly_id;
-       uint64_t module_id;
-       ep_char8_t *assembly_name;
-
-       get_assembly_data (assembly, &assembly_id, &module_id, &assembly_name);
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerAssemblyLoaded (
-               assembly_id,
-               module_id,
-               assembly_name ? assembly_name : "",
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-
-       g_free (assembly_name);
-}
-
-static
-void
-mono_profiler_assembly_unloading (
-       MonoProfiler *prof,
-       MonoAssembly *assembly)
-{
-       if (!EventEnabledMonoProfilerAssemblyUnloading ())
-               return;
-
-       uint64_t assembly_id;
-       uint64_t module_id;
-
-       get_assembly_data (assembly, &assembly_id, &module_id, NULL);
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerAssemblyUnloading (
-               assembly_id,
-               module_id,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_assembly_unloaded (
-       MonoProfiler *prof,
-       MonoAssembly *assembly)
-{
-       if (!EventEnabledMonoProfilerAssemblyUnloaded ())
-               return;
-
-       uint64_t assembly_id;
-       uint64_t module_id;
-       ep_char8_t *assembly_name;
-
-       get_assembly_data (assembly, &assembly_id, &module_id, &assembly_name);
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerAssemblyUnloaded (
-               assembly_id,
-               module_id,
-               assembly_name ? assembly_name : "",
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-
-       g_free (assembly_name);
-}
-
-static
-void
-mono_profiler_method_enter (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       MonoProfilerCallContext *context)
-{
-       if (!EventEnabledMonoProfilerMethodEnter ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerMethodEnter (
-               (uint64_t)method,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_method_leave (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       MonoProfilerCallContext *context)
-{
-       if (!EventEnabledMonoProfilerMethodLeave ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerMethodLeave (
-               (uint64_t)method,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_method_tail_call (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       MonoMethod *target_method)
-{
-       if (!EventEnabledMonoProfilerMethodTailCall ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerMethodTailCall (
-               (uint64_t)method,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_method_exception_leave (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       MonoObject *exc)
-{
-       if (!EventEnabledMonoProfilerMethodExceptionLeave ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerMethodExceptionLeave (
-               (uint64_t)method,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_method_free (
-       MonoProfiler *prof,
-       MonoMethod *method)
-{
-       if (!EventEnabledMonoProfilerMethodFree ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerMethodFree (
-               (uint64_t)method,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_method_begin_invoke (
-       MonoProfiler *prof,
-       MonoMethod *method)
-{
-       if (!EventEnabledMonoProfilerMethodBeginInvoke ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerMethodBeginInvoke (
-               (uint64_t)method,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-void
-mono_profiler_method_end_invoke (
-       MonoProfiler *prof,
-       MonoMethod *method)
-{
-       if (!EventEnabledMonoProfilerMethodEndInvoke ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerMethodEndInvoke (
-               (uint64_t)method,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
-}
-
-static
-MonoProfilerCallInstrumentationFlags
-mono_profiler_method_instrumentation (
-       MonoProfiler *prof,
-       MonoMethod *method)
-{
-       if (_ep_rt_dotnet_mono_profiler_provider_callspec.len > 0 && !mono_callspec_eval (method, &_ep_rt_dotnet_mono_profiler_provider_callspec))
-               return MONO_PROFILER_CALL_INSTRUMENTATION_NONE;
-
-       return MONO_PROFILER_CALL_INSTRUMENTATION_ENTER |
-                       MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE |
-                       MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL |
-                       MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE;
-}
-
-static
-void
-mono_profiler_exception_throw (
-       MonoProfiler *prof,
-       MonoObject *exc)
-{
-       if (!EventEnabledMonoProfilerExceptionThrow ())
-               return;
-
-       uint64_t type_id = 0;
-
-       if (exc && mono_object_class(exc))
-               type_id = (uint64_t)m_class_get_byval_arg (mono_object_class(exc));
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerExceptionThrow (
-               type_id,
-               SGEN_POINTER_UNTAG_ALL (exc),
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
+       return result;
 }
 
-static
 void
-mono_profiler_exception_clause (
-       MonoProfiler *prof,
-       MonoMethod *method,
-       uint32_t clause_num,
-       MonoExceptionEnum clause_type,
-       MonoObject *exc)
+ep_rt_mono_thread_detach (void)
 {
-       if (!EventEnabledMonoProfilerExceptionClause ())
-               return;
-
-       uint64_t type_id = 0;
-
-       if (exc && mono_object_class(exc))
-               type_id = (uint64_t)m_class_get_byval_arg (mono_object_class(exc));
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerExceptionClause (
-               (uint8_t)clause_type,
-               clause_num,
-               (uint64_t)method,
-               type_id,
-               SGEN_POINTER_UNTAG_ALL (exc),
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
+       MonoThread *current_thread = mono_thread_current ();
+       if (current_thread)
+               mono_thread_internal_detach (current_thread);
 }
 
-static
-void
-mono_profiler_gc_event (
-       MonoProfiler *prof,
-       MonoProfilerGCEvent gc_event,
-       uint32_t generation,
-       mono_bool serial)
+#ifdef HOST_WIN32
+int64_t
+ep_rt_mono_perf_counter_query (void)
 {
-       switch (gc_event) {
-       case MONO_GC_EVENT_PRE_STOP_WORLD:
-       case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED:
-       {
-               FireEtwMonoProfilerGCEvent (
-                       (uint8_t)gc_event,
-                       generation,
-                       NULL,
-                       NULL);
-               break;
-       }
-       case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED:
-       {
-               FireEtwMonoProfilerGCEvent (
-                       (uint8_t)gc_event,
-                       generation,
-                       NULL,
-                       NULL);
-
-               mono_profiler_gc_in_progress_start ();
-
-               if (mono_profiler_gc_heap_collect_in_progress ()) {
-                       FireEtwMonoProfilerGCHeapDumpStart (
-                               mono_profiler_get_gc_heap_collect_param_request_value (),
-                               NULL,
-                               NULL);
-               }
-
-               break;
-       }
-       case MONO_GC_EVENT_POST_STOP_WORLD:
-       {
-               if (mono_profiler_gc_in_progress ()) {
-                       uint64_t enabled_keywords = MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask;
-
-                       if (profiler_callback_is_enabled (enabled_keywords, GC_ROOT_KEYWORD)) {
-                               mono_profiler_set_gc_root_register_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_gc_root_register_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, mono_profiler_fire_buffered_gc_event_root_register);
-                               mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, mono_profiler_fire_buffered_gc_event_root_unregister);
-                       }
-
-                       if (mono_profiler_gc_heap_collect_in_progress ()) {
-                               if (profiler_callback_is_enabled (enabled_keywords, GC_ROOT_KEYWORD)) {
-                                       mono_profiler_set_gc_roots_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, mono_profiler_fire_buffered_gc_event_roots);
-                               }
-
-                               if (profiler_callback_is_enabled (enabled_keywords, GC_MOVES_KEYWORD)) {
-                                       mono_profiler_set_gc_moves_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, mono_profiler_fire_buffered_gc_event_moves);
-                               }
-
-                               if (profiler_callback_is_enabled (enabled_keywords, GC_RESIZE_KEYWORD)) {
-                                       mono_profiler_set_gc_resize_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, mono_profiler_fire_buffered_gc_event_resize);
-                               }
-                       }
-
-                       mono_profiler_fire_buffered_gc_event (
-                               (uint8_t)gc_event,
-                               generation);
-               }
-               break;
-       }
-       case MONO_GC_EVENT_START:
-       case MONO_GC_EVENT_END:
-       {
-               if (mono_profiler_gc_in_progress ()) {
-                       mono_profiler_fire_buffered_gc_event (
-                               (uint8_t)gc_event,
-                               generation);
-               }
-               break;
-       }
-       case MONO_GC_EVENT_PRE_START_WORLD:
-       {
-               if (mono_profiler_gc_in_progress ()) {
-                       uint64_t enabled_keywords = MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask;
-
-                       if (mono_profiler_gc_heap_collect_in_progress () && profiler_callback_is_enabled (enabled_keywords, GC_HEAP_DUMP_KEYWORD))
-                               mono_gc_walk_heap (0, mono_profiler_fire_buffered_gc_event_heap_dump_object_reference, NULL);
-
-                       mono_profiler_set_gc_root_register_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, NULL);
-                       mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, NULL);
-                       mono_profiler_set_gc_roots_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, NULL);
-                       mono_profiler_set_gc_moves_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, NULL);
-                       mono_profiler_set_gc_resize_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, NULL);
-
-                       if (profiler_callback_is_enabled (enabled_keywords, GC_ROOT_KEYWORD)) {
-                               mono_profiler_set_gc_root_register_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_root_register);
-                               mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_root_unregister);
-                       }
-
-                       mono_profiler_fire_buffered_gc_event (
-                               (uint8_t)gc_event,
-                               generation);
-               }
-
-               break;
-       }
-       case MONO_GC_EVENT_POST_START_WORLD:
-       {
-               if (mono_profiler_gc_in_progress ()) {
-                       GHashTable *cache = NULL;
-                       uint64_t enabled_keywords = MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask;
-
-                       if (mono_profiler_gc_heap_collect_in_progress () && profiler_callback_is_enabled (enabled_keywords, GC_HEAP_DUMP_VTABLE_CLASS_REF_KEYWORD))
-                               cache = g_hash_table_new_full (NULL, NULL, NULL, NULL);
-
-                       mono_profiler_fire_buffered_gc_events_in_alloc_order (cache);
-                       mono_profiler_fire_cached_gc_events (cache);
-
-                       if (cache)
-                               g_hash_table_destroy (cache);
-
-                       if (mono_profiler_gc_heap_collect_in_progress ()) {
-                               FireEtwMonoProfilerGCHeapDumpStop (
-                                       NULL,
-                                       NULL);
-                       }
+       LARGE_INTEGER value;
+       if (QueryPerformanceCounter (&value))
+               return (int64_t)value.QuadPart;
+       else
+               return 0;
+}
 
-                       FireEtwMonoProfilerGCEvent (
-                               (uint8_t)gc_event,
-                               generation,
-                               NULL,
-                               NULL);
+int64_t
+ep_rt_mono_perf_frequency_query (void)
+{
+       LARGE_INTEGER value;
+       if (QueryPerformanceFrequency (&value))
+               return (int64_t)value.QuadPart;
+       else
+               return 0;
+}
 
-                       if (!profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD))
-                               mono_profiler_set_gc_event_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
+void
+ep_rt_mono_system_time_get (EventPipeSystemTime *system_time)
+{
+       SYSTEMTIME value;
+       GetSystemTime (&value);
 
-                       mono_profiler_gc_heap_collect_in_progress_stop ();
-                       mono_profiler_gc_in_progress_stop ();
-               }
-               break;
-       }
-       default:
-               break;
-       }
+       EP_ASSERT (system_time != NULL);
+       ep_system_time_set (
+               system_time,
+               value.wYear,
+               value.wMonth,
+               value.wDayOfWeek,
+               value.wDay,
+               value.wHour,
+               value.wMinute,
+               value.wSecond,
+               value.wMilliseconds);
 }
 
-static
-void
-mono_profiler_gc_allocation (
-       MonoProfiler *prof,
-       MonoObject *object)
+int64_t
+ep_rt_mono_system_timestamp_get (void)
 {
-       if (!EventEnabledMonoProfilerGCAllocation ())
-               return;
+       FILETIME value;
+       GetSystemTimeAsFileTime (&value);
+       return (int64_t)((((uint64_t)value.dwHighDateTime) << 32) | (uint64_t)value.dwLowDateTime);
+}
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <utime.h>
+#include <time.h>
 
-       uint64_t vtable_id = 0;
-       uint64_t object_size = 0;
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif // HAVE_SYS_TIME_H
 
-       if (object) {
-               vtable_id = (uint64_t)mono_object_get_vtable_internal (object);
-               object_size = (uint64_t)mono_object_get_size_internal (object);
+#if HAVE_MACH_ABSOLUTE_TIME
+#include <mach/mach_time.h>
+static mono_lazy_init_t _ep_rt_mono_time_base_info_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
+static mach_timebase_info_data_t _ep_rt_mono_time_base_info = {0};
+#endif
 
-               /* account for object alignment */
-               object_size += 7;
-               object_size &= ~7;
-       }
+#ifdef HAVE_LOCALTIME_R
+#define HAVE_GMTIME_R 1
+#endif
 
-       mono_profiler_fire_event_enter ();
+static const int64_t SECS_BETWEEN_1601_AND_1970_EPOCHS = 11644473600LL;
+static const int64_t SECS_TO_100NS = 10000000;
+static const int64_t SECS_TO_NS = 1000000000;
+static const int64_t MSECS_TO_MIS = 1000;
 
-       FireEtwMonoProfilerGCAllocation (
-               vtable_id,
-               SGEN_POINTER_UNTAG_ALL (object),
-               object_size,
-               NULL,
-               NULL);
+/* clock_gettime () is found by configure on Apple builds, but its only present from ios 10, macos 10.12, tvos 10 and watchos 3 */
+#if defined (HAVE_CLOCK_MONOTONIC) && (defined(HOST_IOS) || defined(HOST_OSX) || defined(HOST_WATCHOS) || defined(HOST_TVOS))
+#undef HAVE_CLOCK_MONOTONIC
+#endif
 
-       mono_profiler_fire_event_exit ();
-}
+#ifndef HAVE_CLOCK_MONOTONIC
+static const int64_t MISECS_TO_NS = 1000;
+#endif
 
 static
 void
-mono_profiler_gc_handle_created (
-       MonoProfiler *prof,
-       uint32_t handle,
-       MonoGCHandleType type,
-       MonoObject *object)
-{
-       if (!EventEnabledMonoProfilerGCHandleCreated ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerGCHandleCreated (
-               handle,
-               (uint8_t)type,
-               SGEN_POINTER_UNTAG_ALL (object),
-               NULL,
-               NULL);
+time_base_info_lazy_init (void);
 
-       mono_profiler_fire_event_exit ();
-}
+static
+int64_t
+system_time_to_int64 (
+       time_t sec,
+       long nsec);
 
+#if HAVE_MACH_ABSOLUTE_TIME
 static
 void
-mono_profiler_gc_handle_deleted (
-       MonoProfiler *prof,
-       uint32_t handle,
-       MonoGCHandleType type)
+time_base_info_lazy_init (void)
 {
-       if (!EventEnabledMonoProfilerGCHandleDeleted ())
-               return;
-
-       mono_profiler_fire_event_enter ();
+       kern_return_t result = mach_timebase_info (&_ep_rt_mono_time_base_info);
+       if (result != KERN_SUCCESS)
+               memset (&_ep_rt_mono_time_base_info, 0, sizeof (_ep_rt_mono_time_base_info));
+}
+#endif
 
-       FireEtwMonoProfilerGCHandleDeleted (
-               handle,
-               (uint8_t)type,
-               NULL,
-               NULL);
+int64_t
+ep_rt_mono_perf_counter_query (void)
+{
+#if HAVE_MACH_ABSOLUTE_TIME
+       return (int64_t)mach_absolute_time ();
+#elif HAVE_CLOCK_MONOTONIC
+       struct timespec ts;
+       int result = clock_gettime (CLOCK_MONOTONIC, &ts);
+       if (result == 0)
+               return ((int64_t)(ts.tv_sec) * (int64_t)(SECS_TO_NS)) + (int64_t)(ts.tv_nsec);
+#else
+       #error "ep_rt_mono_perf_counter_get requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported."
+#endif
+       return 0;
+}
 
-       mono_profiler_fire_event_exit ();
+int64_t
+ep_rt_mono_perf_frequency_query (void)
+{
+#if HAVE_MACH_ABSOLUTE_TIME
+       // (numer / denom) gives you the nanoseconds per tick, so the below code
+       // computes the number of ticks per second. We explicitly do the multiplication
+       // first in order to help minimize the error that is produced by integer division.
+       mono_lazy_initialize (&_ep_rt_mono_time_base_info_init, time_base_info_lazy_init);
+       if (_ep_rt_mono_time_base_info.denom == 0 || _ep_rt_mono_time_base_info.numer == 0)
+               return 0;
+       return ((int64_t)(SECS_TO_NS) * (int64_t)(_ep_rt_mono_time_base_info.denom)) / (int64_t)(_ep_rt_mono_time_base_info.numer);
+#elif HAVE_CLOCK_MONOTONIC
+       // clock_gettime () returns a result in terms of nanoseconds rather than a count. This
+       // means that we need to either always scale the result by the actual resolution (to
+       // get a count) or we need to say the resolution is in terms of nanoseconds. We prefer
+       // the latter since it allows the highest throughput and should minimize error propagated
+       // to the user.
+       return (int64_t)(SECS_TO_NS);
+#else
+       #error "ep_rt_mono_perf_frequency_query requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported."
+#endif
+       return 0;
 }
 
-static
 void
-mono_profiler_gc_finalizing (MonoProfiler *prof)
+ep_rt_mono_system_time_get (EventPipeSystemTime *system_time)
 {
-       if (!EventEnabledMonoProfilerGCFinalizing ())
-               return;
+       time_t tt;
+#if HAVE_GMTIME_R
+       struct tm ut;
+#endif /* HAVE_GMTIME_R */
+       struct tm *ut_ptr;
+       struct timeval time_val;
+       int timeofday_retval;
 
-       mono_profiler_fire_event_enter ();
+       EP_ASSERT (system_time != NULL);
 
-       FireEtwMonoProfilerGCFinalizing (
-               NULL,
-               NULL);
+       tt = time (NULL);
 
-       mono_profiler_fire_event_exit ();
-}
+       /* We can't get millisecond resolution from time (), so we get it from gettimeofday () */
+       timeofday_retval = gettimeofday (&time_val, NULL);
 
-static
-void
-mono_profiler_gc_finalized (MonoProfiler *prof)
-{
-       if (!EventEnabledMonoProfilerGCFinalized ())
-               return;
+#if HAVE_GMTIME_R
+       ut_ptr = &ut;
+       if (gmtime_r (&tt, ut_ptr) == NULL)
+#else /* HAVE_GMTIME_R */
+       if ((ut_ptr = gmtime (&tt)) == NULL)
+#endif /* HAVE_GMTIME_R */
+               EP_UNREACHABLE ();
+
+       uint16_t milliseconds = 0;
+       if (timeofday_retval != -1) {
+               int old_seconds;
+               int new_seconds;
 
-       mono_profiler_fire_event_enter ();
+               milliseconds = (uint16_t)(time_val.tv_usec / MSECS_TO_MIS);
+
+               old_seconds = ut_ptr->tm_sec;
+               new_seconds = time_val.tv_sec % 60;
 
-       FireEtwMonoProfilerGCFinalized (
-               NULL,
-               NULL);
+               /* just in case we reached the next second in the interval between time () and gettimeofday () */
+               if (old_seconds != new_seconds)
+                       milliseconds = 999;
+       }
 
-       mono_profiler_fire_event_exit ();
+       ep_system_time_set (
+               system_time,
+               (uint16_t)(1900 + ut_ptr->tm_year),
+               (uint16_t)ut_ptr->tm_mon + 1,
+               (uint16_t)ut_ptr->tm_wday,
+               (uint16_t)ut_ptr->tm_mday,
+               (uint16_t)ut_ptr->tm_hour,
+               (uint16_t)ut_ptr->tm_min,
+               (uint16_t)ut_ptr->tm_sec,
+               milliseconds);
 }
 
 static
-void
-mono_profiler_gc_finalizing_object (
-       MonoProfiler *prof,
-       MonoObject *object)
+int64_t
+system_time_to_int64 (
+       time_t sec,
+       long nsec)
 {
-       if (!EventEnabledMonoProfilerGCFinalizingObject ())
-               return;
+       return ((int64_t)sec + SECS_BETWEEN_1601_AND_1970_EPOCHS) * SECS_TO_100NS + (nsec / 100);
+}
 
-       mono_profiler_fire_event_enter ();
+int64_t
+ep_rt_mono_system_timestamp_get (void)
+{
+#if HAVE_CLOCK_MONOTONIC
+       struct timespec time;
+       if (clock_gettime (CLOCK_REALTIME, &time) == 0)
+               return system_time_to_int64 (time.tv_sec, time.tv_nsec);
+#else
+       struct timeval time;
+       if (gettimeofday (&time, NULL) == 0)
+               return system_time_to_int64 (time.tv_sec, time.tv_usec * MISECS_TO_NS);
+#endif
+       else
+               return system_time_to_int64 (0, 0);
+}
+#endif
 
-       FireEtwMonoProfilerGCFinalizingObject (
-               SGEN_POINTER_UNTAG_ALL (object),
-               NULL,
-               NULL);
+#ifndef HOST_WIN32
+#if defined(__APPLE__)
+#if defined (HOST_OSX)
+G_BEGIN_DECLS
+gchar ***_NSGetEnviron(void);
+G_END_DECLS
+#define environ (*_NSGetEnviron())
+#else
+static char *_ep_rt_mono_environ[1] = { NULL };
+#define environ _ep_rt_mono_environ
+#endif /* defined (HOST_OSX) */
+#else
+G_BEGIN_DECLS
+extern char **environ;
+G_END_DECLS
+#endif /* defined (__APPLE__) */
+#endif /* !defined (HOST_WIN32) */
 
-       mono_profiler_fire_event_exit ();
+void
+ep_rt_mono_os_environment_get_utf16 (dn_vector_ptr_t *os_env)
+{
+       EP_ASSERT (os_env != NULL);
+#ifdef HOST_WIN32
+       LPWSTR envs = GetEnvironmentStringsW ();
+       if (envs) {
+               LPWSTR next = envs;
+               while (*next) {
+                       dn_vector_ptr_push_back (os_env, ep_rt_utf16_string_dup (next));
+                       next += ep_rt_utf16_string_len (next) + 1;
+               }
+               FreeEnvironmentStringsW (envs);
+       }
+#else
+       gchar **next = NULL;
+       for (next = environ; *next != NULL; ++next)
+               dn_vector_ptr_push_back (os_env, ep_rt_utf8_to_utf16le_string (*next, -1));
+#endif
 }
 
-static
 void
-mono_profiler_gc_finalized_object (
-       MonoProfiler *prof,
-       MonoObject * object)
+ep_rt_mono_init_providers_and_events (void)
 {
-       if (!EventEnabledMonoProfilerGCFinalizedObject ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerGCFinalizedObject (
-               SGEN_POINTER_UNTAG_ALL (object),
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
+       InitProvidersAndEvents ();
 }
 
-static
 void
-mono_profiler_gc_root_register (
-       MonoProfiler *prof,
-       const mono_byte *start,
-       uintptr_t size,
-       MonoGCRootSource source,
-       const void * key,
-       const char * name)
+ep_rt_mono_provider_config_init (EventPipeProviderConfiguration *provider_config)
 {
-       if (!EventEnabledMonoProfilerGCRootRegister ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerGCRootRegister (
-               start,
-               (uint64_t)size,
-               (uint8_t) source,
-               (uint64_t)key,
-               (const ep_char8_t *)(name ? name : ""),
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
+       if (!ep_rt_utf8_string_compare (ep_config_get_rundown_provider_name_utf8 (), ep_provider_config_get_provider_name (provider_config))) {
+               RUNTIME_RUNDOWN_PROVIDER_CONTEXT.Level = (uint8_t)ep_provider_config_get_logging_level (provider_config);
+               RUNTIME_RUNDOWN_PROVIDER_CONTEXT.EnabledKeywordsBitmask = ep_provider_config_get_keywords (provider_config);
+               RUNTIME_RUNDOWN_PROVIDER_CONTEXT.IsEnabled = true;
+       }
 }
 
-static
-void
-mono_profiler_gc_root_unregister (
-       MonoProfiler *prof,
-       const mono_byte *start)
+bool
+ep_rt_mono_providers_validate_all_disabled (void)
 {
-       if (!EventEnabledMonoProfilerGCRootUnregister ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerGCRootUnregister (
-               start,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
+       return (!RUNTIME_PROVIDER_CONTEXT.IsEnabled &&
+               !RUNTIME_PRIVATE_PROVIDER_CONTEXT.IsEnabled &&
+               !RUNTIME_RUNDOWN_PROVIDER_CONTEXT.IsEnabled &&
+               !RUNTIME_STRESS_PROVIDER_CONTEXT.IsEnabled &&
+               !RUNTIME_MONO_PROFILER_PROVIDER_CONTEXT.IsEnabled);
 }
 
-static
-void
-mono_profiler_monitor_contention (
-       MonoProfiler *prof,
-       MonoObject *object)
+bool
+ep_rt_mono_method_get_simple_assembly_name (
+       ep_rt_method_desc_t *method,
+       ep_char8_t *name,
+       size_t name_len)
 {
-       if (!EventEnabledMonoProfilerMonitorContention ())
-               return;
+       EP_ASSERT (method != NULL);
+       EP_ASSERT (name != NULL);
 
-       mono_profiler_fire_event_enter ();
+       MonoClass *method_class = mono_method_get_class (method);
+       MonoImage *method_image = method_class ? mono_class_get_image (method_class) : NULL;
+       const ep_char8_t *assembly_name = method_image ? mono_image_get_name (method_image) : NULL;
 
-       FireEtwMonoProfilerMonitorContention (
-               SGEN_POINTER_UNTAG_ALL (object),
-               NULL,
-               NULL);
+       if (!assembly_name)
+               return false;
 
-       mono_profiler_fire_event_exit ();
+       g_strlcpy (name, assembly_name, name_len);
+       return true;
 }
 
-static
-void
-mono_profiler_monitor_failed (
-       MonoProfiler *prof,
-       MonoObject *object)
+bool
+ep_rt_mono_method_get_full_name (
+       ep_rt_method_desc_t *method,
+       ep_char8_t *name,
+       size_t name_len)
 {
-       if (!EventEnabledMonoProfilerMonitorFailed ())
-               return;
+       EP_ASSERT (method != NULL);
+       EP_ASSERT (name != NULL);
 
-       mono_profiler_fire_event_enter ();
+       char *full_method_name = mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL);
+       if (!full_method_name)
+               return false;
 
-       FireEtwMonoProfilerMonitorFailed (
-               SGEN_POINTER_UNTAG_ALL (object),
-               NULL,
-               NULL);
+       g_strlcpy (name, full_method_name, name_len);
 
-       mono_profiler_fire_event_exit ();
+       g_free (full_method_name);
+       return true;
 }
 
 static
-void
-mono_profiler_monitor_acquired (
-       MonoProfiler *prof,
-       MonoObject *object)
+bool
+is_keword_enabled (uint64_t enabled_keywords, uint64_t keyword)
 {
-       if (!EventEnabledMonoProfilerMonitorAcquired ())
-               return;
+       return (enabled_keywords & keyword) == keyword;
+}
 
-       mono_profiler_fire_event_enter ();
+uint64_t
+ep_rt_mono_session_calculate_and_count_all_keywords (
+       const ep_char8_t *provider,
+       uint64_t keywords[],
+       uint64_t count[],
+       size_t len)
+{
+       ep_requires_lock_held ();
+
+       uint64_t keywords_for_all_sessions = 0;
+
+       for (int i = 0; i < EP_MAX_NUMBER_OF_SESSIONS; i++) {
+               EventPipeSession *session = ep_volatile_load_session_without_barrier (i);
+               if (session) {
+                       EventPipeSessionProviderList *providers = ep_session_get_providers (session);
+                       EP_ASSERT (providers != NULL);
+
+                       EventPipeSessionProvider *session_provider = ep_session_provider_list_find_by_name (ep_session_provider_list_get_providers (providers), provider);
+                       if (session_provider) {
+                               uint64_t session_keywords = ep_session_provider_get_keywords (session_provider);
+                               for (uint64_t j = 0; j < len; j++) {
+                                       if (is_keword_enabled (session_keywords, keywords [j]))
+                                               count [j]++;
+                               }
+                               keywords_for_all_sessions = keywords_for_all_sessions | session_keywords;
+                       }
+               }
+       }
 
-       FireEtwMonoProfilerMonitorAcquired (
-               SGEN_POINTER_UNTAG_ALL (object),
-               NULL,
-               NULL);
+       ep_requires_lock_held ();
 
-       mono_profiler_fire_event_exit ();
+       return keywords_for_all_sessions;
 }
 
-static
-void
-mono_profiler_thread_started (
-       MonoProfiler *prof,
-       uintptr_t tid)
+bool
+ep_rt_mono_sesion_has_all_started (void)
 {
-       if (!EventEnabledMonoProfilerThreadStarted ())
-               return;
+       ep_requires_lock_held ();
 
-       mono_profiler_fire_event_enter ();
+       bool all_started = true;
+       for (uint32_t i = 0; i < EP_MAX_NUMBER_OF_SESSIONS; ++i) {
+               EventPipeSession *session = ep_volatile_load_session_without_barrier (i);
+               if (session) {
+                       all_started = ep_session_has_started (session);
+                       if (!all_started)
+                               break;
+               }
+       }
 
-       FireEtwMonoProfilerThreadStarted (
-               (uint64_t)tid,
-               NULL,
-               NULL);
+       ep_requires_lock_held ();
 
-       mono_profiler_fire_event_exit ();
+       return all_started;
 }
 
 static
 void
-mono_profiler_thread_stopping (
-       MonoProfiler *prof,
-       uintptr_t tid)
+runtime_initialized_callback (MonoProfiler *prof)
 {
-       if (!EventEnabledMonoProfilerThreadStopping ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerThreadStopping (
-               (uint64_t)tid,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
+       _ep_rt_mono_runtime_initialized = TRUE;
 }
 
 static
 void
-mono_profiler_thread_stopped (
+thread_started_callback (
        MonoProfiler *prof,
        uintptr_t tid)
 {
-       if (!EventEnabledMonoProfilerThreadStopped ())
-               return;
-
-       mono_profiler_fire_event_enter ();
-
-       FireEtwMonoProfilerThreadStopped (
-               (uint64_t)tid,
-               NULL,
-               NULL);
-
-       mono_profiler_fire_event_exit ();
+       ep_rt_mono_runtime_provider_thread_started_callback (prof, tid);
 }
 
 static
 void
-mono_profiler_thread_exited (
+thread_stopped_callback (
        MonoProfiler *prof,
        uintptr_t tid)
 {
-       if (!EventEnabledMonoProfilerThreadExited ())
-               return;
-
-       mono_profiler_fire_event_enter ();
+       ep_rt_mono_runtime_provider_thread_stopped_callback (prof, tid);
 
-       FireEtwMonoProfilerThreadExited (
-               (uint64_t)tid,
-               NULL,
-               NULL);
+       if (_eventpipe_initialized) {
+               EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (_ep_rt_mono_thread_holder_tls_id);
+               if (thread_holder)
+                       thread_holder_free_func (thread_holder);
+               mono_native_tls_set_value (_ep_rt_mono_thread_holder_tls_id, NULL);
 
-       mono_profiler_fire_event_exit ();
+               EventPipeMonoThreadData *thread_data = (EventPipeMonoThreadData *)mono_native_tls_get_value (_thread_data_tls_id);
+               if (thread_data)
+                       ep_rt_object_free (thread_data);
+               mono_native_tls_set_value (_thread_data_tls_id, NULL);
+       }
 }
 
-static
 void
-mono_profiler_thread_name (
-       MonoProfiler *prof,
-       uintptr_t tid,
-       const char *name)
+ep_rt_mono_component_init (void)
 {
-       if (!EventEnabledMonoProfilerThreadName ())
-               return;
+       ep_rt_spin_lock_alloc (&_ep_rt_mono_config_lock);
 
-       mono_profiler_fire_event_enter ();
+       RUNTIME_PROVIDER_CONTEXT = MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context;
+       RUNTIME_PRIVATE_PROVIDER_CONTEXT = MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context;
+       RUNTIME_RUNDOWN_PROVIDER_CONTEXT = MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context;
+       RUNTIME_STRESS_PROVIDER_CONTEXT = MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_EVENTPIPE_Context;
+       RUNTIME_MONO_PROFILER_PROVIDER_CONTEXT = MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context;
 
-       FireEtwMonoProfilerThreadName (
-               (uint64_t)tid,
-               (ep_char8_t *)(name ? name : ""),
-               NULL,
-               NULL);
+       _ep_rt_mono_default_profiler_provider = mono_profiler_create (NULL);
 
-       mono_profiler_fire_event_exit ();
-}
+       char *diag_env = g_getenv("MONO_DIAGNOSTICS");
+       if (diag_env) {
+               int diag_argc = 1;
+               char **diag_argv = g_new (char *, 1);
+               if (diag_argv) {
+                       diag_argv [0] = NULL;
+                       if (!mono_parse_options_from (diag_env, &diag_argc, &diag_argv)) {
+                               for (int i = 0; i < diag_argc; ++i) {
+                                       if (diag_argv [i]) {
+                                               if (strncmp (diag_argv [i], "--diagnostic-ports=", 19) == 0) {
+                                                       char *diag_ports_env = g_getenv("DOTNET_DiagnosticPorts");
+                                                       if (diag_ports_env)
+                                                               mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_DIAGNOSTICS, "DOTNET_DiagnosticPorts environment variable already set, ignoring --diagnostic-ports used in MONO_DIAGNOSTICS environment variable");
+                                                       else
+                                                               g_setenv ("DOTNET_DiagnosticPorts", diag_argv [i] + 19, TRUE);
+                                                       g_free (diag_ports_env);
+                                               } else if (ep_rt_mono_profiler_provider_parse_options (diag_argv [i])) {
+                                                       ;
+                                               } else {
+                                                       mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed parsing MONO_DIAGNOSTICS environment variable, unknown option: %s", diag_argv [i]);
+                                               }
 
-static
-const EventFilterDescriptor *
-mono_profiler_add_provider_param (const EventFilterDescriptor *key)
-{
-       ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock);
-
-       EventFilterDescriptor *param = NULL;
-       if (key && key->ptr && key->size) {
-               uint64_t param_ptr = (uint64_t)g_malloc (key->size);
-               if (param_ptr) {
-                       param = ep_event_filter_desc_alloc (param_ptr, key->size, key->type);
-                       if (param) {
-                               memcpy ((uint8_t*)(uintptr_t)param->ptr,(const uint8_t*)(uintptr_t)key->ptr, key->size);
-                               _ep_rt_mono_profiler_provider_params = g_slist_append (_ep_rt_mono_profiler_provider_params, param);
-                       } else {
-                               g_free ((void *)(uintptr_t)param_ptr);
-                       }
-               }
-       }
-       return param;
-}
+                                               g_free (diag_argv [i]);
+                                               diag_argv [i] = NULL;
+                                       }
+                               }
 
-static
-bool
-mono_profiler_remove_provider_param (const EventFilterDescriptor *key)
-{
-       ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock);
-
-       bool removed = false;
-       if (_ep_rt_mono_profiler_provider_params && key && key->ptr && key->size) {
-               GSList *list = _ep_rt_mono_profiler_provider_params;
-               EventFilterDescriptor *param = NULL;
-               while (list) {
-                       param = (EventFilterDescriptor *)(list->data);
-                       if (param && param->ptr && param->type == key->type && param->size == key->size &&
-                               memcmp ((const void *)(uintptr_t)param->ptr, (const void *)(uintptr_t)key->ptr, param->size) == 0) {
-                                       g_free ((void *)(uintptr_t)param->ptr);
-                                       ep_event_filter_desc_free (param);
-                                       _ep_rt_mono_profiler_provider_params = g_slist_delete_link (_ep_rt_mono_profiler_provider_params, list);
-                                       removed = true;
-                                       break;
+                               g_free (diag_argv);
+                       } else {
+                               mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed parsing MONO_DIAGNOSTICS environment variable");
                        }
-                       list = list->next;
                }
        }
+       g_free (diag_env);
 
-       return removed;
+       ep_rt_mono_runtime_provider_component_init ();
+       ep_rt_mono_profiler_provider_component_init ();
 }
 
-static
 void
-mono_profiler_free_provider_params (void)
-{
-       // Should only be called from ep_rt_mono_fini.
-       for (GSList *list = _ep_rt_mono_profiler_provider_params; list; list = list->next) {
-               EventFilterDescriptor *param = (EventFilterDescriptor *)(list->data);
-               if (param) {
-                       g_free ((void *)(uintptr_t)param->ptr);
-                       ep_event_filter_desc_free (param);
-               }
-       }
-       g_slist_free (_ep_rt_mono_profiler_provider_params);
-       _ep_rt_mono_profiler_provider_params = NULL;
-}
-
-static
-bool
-mono_profiler_provider_params_get_value (
-       const EventFilterDescriptor *param,
-       const ep_char8_t *key,
-       const ep_char8_t **value)
+ep_rt_mono_init (void)
 {
-       if (!param || !param->ptr || !param->size || !key)
-               return false;
-
-       const ep_char8_t *current = (ep_char8_t *)(uintptr_t)param->ptr;
-       const ep_char8_t *end = current + param->size;
-       bool found_key = false;
+       EP_ASSERT (_ep_rt_mono_default_profiler_provider != NULL);
 
-       if (value)
-               *value = "";
+       mono_native_tls_alloc (&_ep_rt_mono_thread_holder_tls_id, NULL);
+       mono_native_tls_alloc (&_thread_data_tls_id, NULL);
 
-       if (!current [param->size - 1]) {
-               while (current < end) {
-                       if (found_key) {
-                               if (value)
-                                       *value = current;
-                               break;
-                       }
+       mono_100ns_ticks ();
+       mono_rand_open ();
+       _rand_provider = mono_rand_init (NULL, 0);
 
-                       if (!ep_rt_utf8_string_compare_ignore_case (current, key)) {
-                               found_key = true;
-                       }
+       ep_rt_mono_runtime_provider_init ();
+       ep_rt_mono_profiler_provider_init ();
 
-                       current = current + strlen (current) + 1;
-               }
-       }
+       mono_profiler_set_runtime_initialized_callback (_ep_rt_mono_default_profiler_provider, runtime_initialized_callback);
+       mono_profiler_set_thread_started_callback (_ep_rt_mono_default_profiler_provider, thread_started_callback);
+       mono_profiler_set_thread_stopped_callback (_ep_rt_mono_default_profiler_provider, thread_stopped_callback);
 
-       return found_key;
+       _eventpipe_initialized = TRUE;
 }
 
-static
-bool
-mono_profiler_provider_param_contains_heap_collect_ondemand (const EventFilterDescriptor *param)
+void
+ep_rt_mono_init_finish (void)
 {
-       const ep_char8_t *value = NULL;
-       bool found_heap_collect_ondemand_value = false;
+       if (mono_runtime_get_no_exec ())
+               return;
 
-       if (mono_profiler_provider_params_get_value (param, "heapcollect", &value)) {
-               if (strstr (value, "ondemand"))
-                       found_heap_collect_ondemand_value = true;
+       // Managed init of diagnostics classes, like registration of RuntimeEventSource (if available).
+       ERROR_DECL (error);
+
+       MonoClass *runtime_event_source = mono_class_from_name_checked (mono_get_corlib (), "System.Diagnostics.Tracing", "RuntimeEventSource", error);
+       if (is_ok (error) && runtime_event_source) {
+               MonoMethod *init = mono_class_get_method_from_name_checked (runtime_event_source, "Initialize", -1, 0, error);
+               if (is_ok (error) && init) {
+                       mono_runtime_try_invoke_handle (init, NULL_HANDLE, NULL, error);
+               }
        }
 
-       return found_heap_collect_ondemand_value;
+       mono_error_cleanup (error);
 }
 
-static
 void
-mono_profiler_push_gc_heap_collect_param_request_value (const EventFilterDescriptor *param)
+ep_rt_mono_fini (void)
 {
-       ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock);
+       ep_rt_mono_runtime_provider_fini ();
+       ep_rt_mono_profiler_provider_fini ();
 
-       const ep_char8_t *value = NULL;
-       if (param)
-               mono_profiler_provider_params_get_value (param, "heapcollect", &value);
+       if (_eventpipe_initialized)
+               mono_rand_close (_rand_provider);
 
-       if (!_ep_rt_mono_profiler_gc_heap_collect_request_params)
-               _ep_rt_mono_profiler_gc_heap_collect_request_params = g_queue_new ();
-       if (_ep_rt_mono_profiler_gc_heap_collect_request_params)
-               g_queue_push_tail (_ep_rt_mono_profiler_gc_heap_collect_request_params, (gpointer)ep_rt_utf8_string_dup (value ? value : ""));
-}
+       _rand_provider = NULL;
+       _eventpipe_initialized = FALSE;
 
-static
-void
-mono_profiler_pop_gc_heap_collect_param_request_value (void)
-{
-       ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock);
+       _ep_rt_mono_runtime_initialized = FALSE;
 
-       ep_char8_t *value = NULL;
-       if (_ep_rt_mono_profiler_gc_heap_collect_request_params && !g_queue_is_empty (_ep_rt_mono_profiler_gc_heap_collect_request_params))
-               value = (ep_char8_t *)g_queue_pop_head (_ep_rt_mono_profiler_gc_heap_collect_request_params);
-       g_free (value);
-}
+       if (_ep_rt_mono_default_profiler_provider) {
+               mono_profiler_set_runtime_initialized_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_thread_started_callback (_ep_rt_mono_default_profiler_provider, NULL);
+               mono_profiler_set_thread_stopped_callback (_ep_rt_mono_default_profiler_provider, NULL);
+       }
+       _ep_rt_mono_default_profiler_provider = NULL;
 
-static
-const ep_char8_t *
-mono_profiler_get_gc_heap_collect_param_request_value (void)
-{
-       ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock);
+       if (_ep_rt_mono_thread_holder_tls_id)
+               mono_native_tls_free (_ep_rt_mono_thread_holder_tls_id);
+       _ep_rt_mono_thread_holder_tls_id = 0;
 
-       ep_char8_t *value = NULL;
-       if (_ep_rt_mono_profiler_gc_heap_collect_request_params && !g_queue_is_empty (_ep_rt_mono_profiler_gc_heap_collect_request_params)) {
-               value = (ep_char8_t *)g_queue_pop_head (_ep_rt_mono_profiler_gc_heap_collect_request_params);
-               g_queue_push_head (_ep_rt_mono_profiler_gc_heap_collect_request_params, (gpointer)value);
-       }
-       return value ? value : "";
+       if (_thread_data_tls_id)
+               mono_native_tls_free (_thread_data_tls_id);
+       _thread_data_tls_id = 0;
+
+       _ep_rt_mono_os_cmd_line_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
+       _ep_rt_mono_os_cmd_line = NULL;
+
+       _ep_rt_mono_managed_cmd_line_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
+       _ep_rt_mono_managed_cmd_line = NULL;
+
+       ep_rt_spin_lock_free (&_ep_rt_mono_config_lock);
 }
 
-static
 void
-mono_profiler_free_gc_heap_collect_param_requests (void)
+EventPipeEtwCallbackDotNETRuntimeRundown (
+       const uint8_t *source_id,
+       unsigned long is_enabled,
+       uint8_t level,
+       uint64_t match_any_keywords,
+       uint64_t match_all_keywords,
+       EventFilterDescriptor *filter_data,
+       void *callback_data)
 {
-       // Should only be called from ep_rt_mono_fini.
-       if (_ep_rt_mono_profiler_gc_heap_collect_request_params) {
-               while (!g_queue_is_empty (_ep_rt_mono_profiler_gc_heap_collect_request_params))
-                       g_free (g_queue_pop_head (_ep_rt_mono_profiler_gc_heap_collect_request_params));
-               g_queue_free (_ep_rt_mono_profiler_gc_heap_collect_request_params);
-               _ep_rt_mono_profiler_gc_heap_collect_request_params = NULL;
-       }
+       RUNTIME_RUNDOWN_PROVIDER_CONTEXT.Level = level;
+       RUNTIME_RUNDOWN_PROVIDER_CONTEXT.EnabledKeywordsBitmask = match_any_keywords;
+       RUNTIME_RUNDOWN_PROVIDER_CONTEXT.IsEnabled = (is_enabled == 1 ? true : false);
 }
 
-static
 void
-mono_profiler_ep_provider_callback (
+EventPipeEtwCallbackDotNETRuntimePrivate (
        const uint8_t *source_id,
        unsigned long is_enabled,
        uint8_t level,
@@ -7495,288 +905,13 @@ mono_profiler_ep_provider_callback (
        EventFilterDescriptor *filter_data,
        void *callback_data)
 {
-       ep_rt_config_requires_lock_not_held ();
-       ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock);
-
-       EP_ASSERT(is_enabled == 0 || is_enabled == 1) ;
-       EP_ASSERT (_ep_rt_dotnet_mono_profiler_provider != NULL);
-       EP_ASSERT (_ep_rt_dotnet_mono_profiler_heap_collect_provider != NULL);
-
-       match_any_keywords = (is_enabled == 1) ? match_any_keywords : 0;
-
-       EP_LOCK_ENTER (section1)
-               uint64_t enabled_keywords = MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask;
-
-               if (profiler_callback_is_enabled(match_any_keywords, LOADER_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, LOADER_KEYWORD)) {
-                               mono_profiler_set_domain_loading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_app_domain_loading);
-                               mono_profiler_set_domain_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_app_domain_loaded);
-                               mono_profiler_set_domain_unloading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_app_domain_unloading);
-                               mono_profiler_set_domain_unloaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_app_domain_unloaded);
-                               mono_profiler_set_domain_name_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_app_domain_name);
-                               mono_profiler_set_image_loading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_module_loading);
-                               mono_profiler_set_image_failed_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_module_failed);
-                               mono_profiler_set_image_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_module_loaded);
-                               mono_profiler_set_image_unloading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_module_unloading);
-                               mono_profiler_set_image_unloaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_module_unloaded);
-                               mono_profiler_set_assembly_loading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_assembly_loading);
-                               mono_profiler_set_assembly_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_assembly_loaded);
-                               mono_profiler_set_assembly_unloading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_assembly_unloading);
-                               mono_profiler_set_assembly_unloaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_assembly_unloaded);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, LOADER_KEYWORD)) {
-                               mono_profiler_set_domain_loading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_domain_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_domain_unloading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_domain_unloaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_domain_name_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_image_loading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_image_failed_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_image_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_image_unloading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_image_unloaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_assembly_loading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_assembly_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_assembly_unloading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_assembly_unloaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, JIT_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, JIT_KEYWORD)) {
-                               mono_profiler_set_jit_begin_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_jit_begin);
-                               mono_profiler_set_jit_failed_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_jit_failed);
-                               mono_profiler_set_jit_done_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_jit_done);
-                               mono_profiler_set_jit_chunk_created_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_jit_chunk_created);
-                               mono_profiler_set_jit_chunk_destroyed_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_jit_chunk_destroyed);
-                               mono_profiler_set_jit_code_buffer_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_jit_code_buffer);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, JIT_KEYWORD)) {
-                               mono_profiler_set_jit_begin_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_jit_failed_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_jit_done_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_jit_chunk_created_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_jit_chunk_destroyed_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_jit_code_buffer_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, TYPE_LOADING_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, TYPE_LOADING_KEYWORD)) {
-                               mono_profiler_set_class_loading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_class_loading);
-                               mono_profiler_set_class_failed_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_class_failed);
-                               mono_profiler_set_class_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_class_loaded);
-                               mono_profiler_set_vtable_loading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_vtable_loading);
-                               mono_profiler_set_vtable_failed_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_vtable_failed);
-                               mono_profiler_set_vtable_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_vtable_loaded);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, TYPE_LOADING_KEYWORD)) {
-                               mono_profiler_set_class_loading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_class_failed_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_class_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_vtable_loading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_vtable_failed_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_vtable_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, METHOD_TRACING_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, METHOD_TRACING_KEYWORD)) {
-                               mono_profiler_set_method_enter_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_enter);
-                               mono_profiler_set_method_leave_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_leave);
-                               mono_profiler_set_method_tail_call_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_tail_call);
-                               mono_profiler_set_method_exception_leave_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_exception_leave);
-                               mono_profiler_set_method_free_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_free);
-                               mono_profiler_set_method_begin_invoke_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_begin_invoke);
-                               mono_profiler_set_method_end_invoke_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_end_invoke);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, METHOD_TRACING_KEYWORD)) {
-                               mono_profiler_set_method_enter_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_method_leave_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_method_tail_call_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_method_exception_leave_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_method_free_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_method_begin_invoke_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_method_end_invoke_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, EXCEPTION_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, EXCEPTION_KEYWORD)) {
-                               mono_profiler_set_exception_throw_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_exception_throw);
-                               mono_profiler_set_exception_clause_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_exception_clause);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, EXCEPTION_KEYWORD)) {
-                               mono_profiler_set_exception_throw_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_exception_clause_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, GC_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD)) {
-                               mono_profiler_set_gc_event_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_event);
-                       }
-               } else {
-                       // NOTE, disabled in mono_profiler_gc_event, MONO_GC_EVENT_POST_START_WORLD to make sure all
-                       // callbacks during GC fires.
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, GC_ALLOCATION_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, GC_ALLOCATION_KEYWORD)) {
-                               mono_profiler_set_gc_allocation_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_allocation);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, GC_ALLOCATION_KEYWORD)) {
-                               mono_profiler_set_gc_allocation_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, GC_HANDLE_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, GC_HANDLE_KEYWORD)) {
-                               mono_profiler_set_gc_handle_created_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_handle_created);
-                               mono_profiler_set_gc_handle_deleted_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_handle_deleted);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, GC_HANDLE_KEYWORD)) {
-                               mono_profiler_set_gc_handle_created_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_gc_handle_deleted_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, GC_FINALIZATION_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, GC_FINALIZATION_KEYWORD)) {
-                               mono_profiler_set_gc_finalizing_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_finalizing);
-                               mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_finalized);
-                               mono_profiler_set_gc_finalizing_object_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_finalizing_object);
-                               mono_profiler_set_gc_finalized_object_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_finalized_object);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, GC_FINALIZATION_KEYWORD)) {
-                               mono_profiler_set_gc_finalizing_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_gc_finalizing_object_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_gc_finalized_object_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, GC_ROOT_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, GC_ROOT_KEYWORD)) {
-                               mono_profiler_set_gc_root_register_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_root_register);
-                               mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_root_unregister);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, GC_ROOT_KEYWORD)) {
-                               mono_profiler_set_gc_root_register_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, GC_HEAP_COLLECT_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, GC_HEAP_COLLECT_KEYWORD)) {
-                               mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, mono_profiler_trigger_heap_collect);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, GC_HEAP_COLLECT_KEYWORD)) {
-                               mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, MONITOR_KEYWORD) || profiler_callback_is_enabled(match_any_keywords, CONTENTION_KEYWORD)) {
-                       if (!(profiler_callback_is_enabled(enabled_keywords, MONITOR_KEYWORD) && profiler_callback_is_enabled(enabled_keywords, CONTENTION_KEYWORD))) {
-                               mono_profiler_set_monitor_contention_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_monitor_contention);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled(enabled_keywords, MONITOR_KEYWORD) || profiler_callback_is_enabled(enabled_keywords, CONTENTION_KEYWORD)) {
-                               mono_profiler_set_monitor_contention_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, MONITOR_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, MONITOR_KEYWORD)) {
-                               mono_profiler_set_monitor_failed_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_monitor_failed);
-                               mono_profiler_set_monitor_acquired_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_monitor_acquired);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, MONITOR_KEYWORD)) {
-                               mono_profiler_set_monitor_failed_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_monitor_acquired_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                       }
-               }
-
-               if (profiler_callback_is_enabled(match_any_keywords, THREADING_KEYWORD)) {
-                       if (!profiler_callback_is_enabled (enabled_keywords, THREADING_KEYWORD)) {
-                               mono_profiler_set_thread_started_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_thread_started);
-                               mono_profiler_set_thread_stopping_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_thread_stopping);
-                               mono_profiler_set_thread_stopped_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_thread_stopped);
-                               mono_profiler_set_thread_exited_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_thread_exited);
-                               mono_profiler_set_thread_name_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_thread_name);
-                       }
-               } else {
-                       if (profiler_callback_is_enabled (enabled_keywords, THREADING_KEYWORD)) {
-                               mono_profiler_set_thread_started_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_thread_stopping_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_thread_stopped_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_thread_exited_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               mono_profiler_set_thread_name_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                       }
-               }
-
-               if (!_ep_rt_dotnet_mono_profiler_provider_callspec.enabled) {
-                       if (profiler_callback_is_enabled(match_any_keywords, METHOD_INSTRUMENTATION_KEYWORD)) {
-                               if (!profiler_callback_is_enabled (enabled_keywords, METHOD_INSTRUMENTATION_KEYWORD)) {
-                                       mono_profiler_set_call_instrumentation_filter_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_instrumentation);
-                               }
-                       } else {
-                               if (profiler_callback_is_enabled (enabled_keywords, METHOD_INSTRUMENTATION_KEYWORD)) {
-                                       mono_profiler_set_call_instrumentation_filter_callback (_ep_rt_dotnet_mono_profiler_provider, NULL);
-                               }
-                       }
-               }
-
-               if (match_any_keywords) {
-                       bool request_heap_collect = false;
-                       if (profiler_callback_is_enabled (match_any_keywords, GC_HEAP_COLLECT_KEYWORD)) {
-                               if (mono_profiler_gc_can_collect_heap () && !profiler_callback_is_enabled (enabled_keywords, GC_HEAP_COLLECT_KEYWORD))
-                                       request_heap_collect = true;
-                       }
-
-                       if (filter_data) {
-                               if (mono_profiler_provider_param_contains_heap_collect_ondemand (filter_data) && !mono_profiler_remove_provider_param (filter_data)) {
-                                       mono_profiler_add_provider_param (filter_data);
-                                       if (mono_profiler_gc_can_collect_heap () && profiler_callback_is_enabled (match_any_keywords, GC_HEAP_COLLECT_KEYWORD))
-                                               request_heap_collect = true;
-                               }
-                       }
-
-                       if (request_heap_collect) {
-                               mono_profiler_push_gc_heap_collect_param_request_value (filter_data);
-                               mono_profiler_gc_heap_collect_requests_inc ();
-                               mono_gc_finalize_notify ();
-                       }
-               } else {
-                       mono_profiler_free_provider_params ();
-               }
-
-               MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.Level = level;
-               MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords;
-               MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false);
-       EP_LOCK_EXIT (section1)
-
-ep_on_exit:
-       ep_rt_config_requires_lock_not_held ();
-       return;
-
-ep_on_error:
-       ep_exit_error_handler ();
+       RUNTIME_PRIVATE_PROVIDER_CONTEXT.Level = level;
+       RUNTIME_PRIVATE_PROVIDER_CONTEXT.EnabledKeywordsBitmask = match_any_keywords;
+       RUNTIME_PRIVATE_PROVIDER_CONTEXT.IsEnabled = (is_enabled == 1 ? true : false);
 }
 
 void
-EventPipeEtwCallbackDotNETRuntimeMonoProfiler (
+EventPipeEtwCallbackDotNETRuntimeStress (
        const uint8_t *source_id,
        unsigned long is_enabled,
        uint8_t level,
@@ -7785,25 +920,9 @@ EventPipeEtwCallbackDotNETRuntimeMonoProfiler (
        EventFilterDescriptor *filter_data,
        void *callback_data)
 {
-       ep_rt_spin_lock_requires_lock_not_held (&_ep_rt_mono_profiler_gc_state_lock);
-
-       EP_SPIN_LOCK_ENTER (&_ep_rt_mono_profiler_gc_state_lock, section1);
-               mono_profiler_ep_provider_callback (
-                       source_id,
-                       is_enabled,
-                       level,
-                       match_any_keywords,
-                       match_all_keywords,
-                       filter_data,
-                       callback_data);
-       EP_SPIN_LOCK_EXIT (&_ep_rt_mono_profiler_gc_state_lock, section1);
-
-ep_on_exit:
-       ep_rt_spin_lock_requires_lock_not_held (&_ep_rt_mono_profiler_gc_state_lock);
-       return;
-
-ep_on_error:
-       ep_exit_error_handler ();
+       RUNTIME_STRESS_PROVIDER_CONTEXT.Level = level;
+       RUNTIME_STRESS_PROVIDER_CONTEXT.EnabledKeywordsBitmask = match_any_keywords;
+       RUNTIME_STRESS_PROVIDER_CONTEXT.IsEnabled = (is_enabled == 1 ? true : false);
 }
 
 #endif /* ENABLE_PERFTRACING */
index 7183393..c2e1088 100644 (file)
@@ -58,6 +58,7 @@ extern bool ep_rt_mono_file_write (ep_rt_file_handle_t handle, const uint8_t *bu
 extern void * ep_rt_mono_thread_attach (bool background_thread);
 extern void * ep_rt_mono_thread_attach_2 (bool background_thread, EventPipeThreadType thread_type);
 extern void ep_rt_mono_thread_detach (void);
+extern void ep_rt_mono_component_init (void);
 extern void ep_rt_mono_init (void);
 extern void ep_rt_mono_init_finish (void);
 extern void ep_rt_mono_fini (void);
@@ -382,8 +383,6 @@ void
 ep_rt_init (void)
 {
        ep_rt_mono_init ();
-
-       ep_rt_spin_lock_alloc (ep_rt_mono_config_lock_get ());
 }
 
 static
@@ -402,8 +401,6 @@ ep_rt_shutdown (void)
        mono_lazy_cleanup (managed_command_line_get_init (), managed_command_line_lazy_clean);
        mono_lazy_cleanup (os_command_line_get_init (), os_command_line_lazy_clean);
 
-       ep_rt_spin_lock_free (ep_rt_mono_config_lock_get ());
-
        ep_rt_mono_fini ();
 }
 
@@ -1818,90 +1815,7 @@ ep_rt_volatile_store_ptr_without_barrier (
  */
 
 bool
-ep_rt_mono_write_event_ee_startup_start (void);
-
-typedef struct _BulkTypeEventLogger BulkTypeEventLogger;
-
-void
-ep_rt_mono_fire_bulk_type_event (BulkTypeEventLogger *p_type_logger);
-
-int
-ep_rt_mono_log_single_type (
-       BulkTypeEventLogger *p_type_logger,
-       MonoType *mono_type);
-
-void
-ep_rt_mono_log_type_and_parameters (
-       BulkTypeEventLogger *p_type_logger,
-       MonoType *mono_type);
-
-void
-ep_rt_mono_log_type_and_parameters_if_necessary (
-       BulkTypeEventLogger *p_type_logger,
-       MonoType *mono_type);
-
-void
-ep_rt_mono_send_method_details_event (MonoMethod *method);
-
-bool
-ep_rt_mono_write_event_jit_start (MonoMethod *method);
-
-bool
-ep_rt_mono_write_event_method_il_to_native_map (
-       MonoMethod *method,
-       MonoJitInfo *ji);
-
-bool
-ep_rt_mono_write_event_method_load (
-       MonoMethod *method,
-       MonoJitInfo *ji);
-
-bool
-ep_rt_mono_write_event_module_load (MonoImage *image);
-
-bool
-ep_rt_mono_write_event_module_unload (MonoImage *image);
-
-bool
-ep_rt_mono_write_event_assembly_load (MonoAssembly *assembly);
-
-bool
-ep_rt_mono_write_event_assembly_unload (MonoAssembly *assembly);
-
-bool
-ep_rt_mono_write_event_thread_created (ep_rt_thread_id_t tid);
-
-bool
-ep_rt_mono_write_event_thread_terminated (ep_rt_thread_id_t tid);
-
-bool
-ep_rt_mono_write_event_type_load_start (MonoType *type);
-
-bool
-ep_rt_mono_write_event_type_load_stop (MonoType *type);
-
-bool
-ep_rt_mono_write_event_exception_thrown (MonoObject *object);
-
-bool
-ep_rt_mono_write_event_exception_clause (
-       MonoMethod *method,
-       uint32_t clause_num,
-       MonoExceptionEnum clause_type,
-       MonoObject *obj);
-
-bool
-ep_rt_mono_write_event_monitor_contention_start (MonoObject *obj);
-
-bool
-ep_rt_mono_write_event_monitor_contention_stop (MonoObject *obj);
-
-bool
-ep_rt_mono_write_event_method_jit_memory_allocated_for_code (
-       const uint8_t *buffer,
-       uint64_t size,
-       MonoProfilerCodeBufferType type,
-       const void *data);
+ep_rt_write_event_ee_startup_start (void);
 
 bool
 ep_rt_write_event_threadpool_worker_thread_start (
@@ -2053,6 +1967,64 @@ EventPipeEtwCallbackDotNETRuntimeMonoProfiler (
        EventFilterDescriptor *filter_data,
        void *callback_data);
 
+/*
+* Shared EventPipe provider defines/types/functions.
+*/
+
+#define GC_KEYWORD 0x1
+#define GC_HANDLE_KEYWORD 0x2
+#define LOADER_KEYWORD 0x8
+#define JIT_KEYWORD 0x10
+#define APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD 0x800
+#define CONTENTION_KEYWORD 0x4000
+#define EXCEPTION_KEYWORD 0x8000
+#define THREADING_KEYWORD 0x10000
+#define TYPE_KEYWORD 0x80000
+#define GC_HEAP_DUMP_KEYWORD 0x100000
+#define GC_ALLOCATION_KEYWORD 0x200000
+#define GC_MOVES_KEYWORD 0x400000
+#define GC_HEAP_COLLECT_KEYWORD 0x800000
+#define GC_HEAP_AND_TYPE_NAMES_KEYWORD 0x1000000
+#define GC_FINALIZATION_KEYWORD 0x1000000
+#define GC_RESIZE_KEYWORD 0x2000000
+#define GC_ROOT_KEYWORD 0x4000000
+#define GC_HEAP_DUMP_VTABLE_CLASS_REF_KEYWORD 0x8000000
+#define METHOD_TRACING_KEYWORD 0x20000000
+#define TYPE_DIAGNOSTIC_KEYWORD 0x8000000000
+#define TYPE_LOADING_KEYWORD 0x8000000000
+#define MONITOR_KEYWORD 0x10000000000
+#define METHOD_INSTRUMENTATION_KEYWORD 0x40000000000
+
+// Custom Mono EventPipe thread data.
+typedef struct _EventPipeMonoThreadData EventPipeMonoThreadData;
+struct _EventPipeMonoThreadData {
+       void *gc_heap_dump_context;
+       bool prevent_profiler_event_recursion;
+};
+
+static
+inline
+bool
+ep_rt_mono_is_runtime_initialized (void)
+{
+       extern gboolean _ep_rt_mono_runtime_initialized;
+       return !!_ep_rt_mono_runtime_initialized;
+}
+
+extern EventPipeMonoThreadData * ep_rt_mono_thread_data_get_or_create (void);
+extern uint64_t ep_rt_mono_session_calculate_and_count_all_keywords (const ep_char8_t *provider, uint64_t keywords[], uint64_t count[], size_t len);
+extern bool ep_rt_mono_sesion_has_all_started (void);
+
+extern void ep_rt_mono_runtime_provider_component_init (void);
+extern void ep_rt_mono_runtime_provider_init (void);
+extern void ep_rt_mono_runtime_provider_fini (void);
+extern void ep_rt_mono_runtime_provider_thread_started_callback (MonoProfiler *prof, uintptr_t tid);
+extern void ep_rt_mono_runtime_provider_thread_stopped_callback (MonoProfiler *prof, uintptr_t tid);
+
+extern void ep_rt_mono_profiler_provider_component_init (void);
+extern void ep_rt_mono_profiler_provider_init (void);
+extern void ep_rt_mono_profiler_provider_fini (void);
+extern bool ep_rt_mono_profiler_provider_parse_options (const char *options);
 
 #endif /* ENABLE_PERFTRACING */
 #endif /* __EVENTPIPE_RT_MONO_H__ */
index cd0d4a6..0fc46a0 100644 (file)
@@ -47,6 +47,8 @@ if(ENABLE_PERFTRACING)
 
     list(APPEND MONO_EVENTPIPE_SHIM_SOURCES
         ep-rt-mono.c
+        ep-rt-mono-runtime-provider.c
+        ep-rt-mono-profiler-provider.c
     )
 
     list(APPEND MONO_DIAGNOSTIC_SERVER_SHIM_SOURCES
index 4797935..8a9f572 100644 (file)
@@ -24,6 +24,13 @@ ExceptionFinallyStart
 ExceptionFinallyStop
 ExceptionThrown_V1
 ExceptionThrownStop
+GCBulkEdge
+GCBulkNode
+GCBulkRootConditionalWeakTableElementEdge
+GCBulkRootEdge
+GCBulkRootStaticVar
+GCEnd_V1
+GCStart_V2
 MethodDCEndILToNativeMap
 MethodDCEnd_V1
 MethodDCEndVerbose_V1
index 5b6e5e3..5024faa 100644 (file)
@@ -3897,7 +3897,7 @@ sgen_gc_init (void)
 
        sgen_card_table_init (&remset);
 
-       sgen_register_root (NULL, 0, sgen_make_user_root_descriptor (sgen_mark_normal_gc_handles), ROOT_TYPE_NORMAL, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "GC Handles (SGen, Normal)");
+       sgen_register_root (NULL, 0, sgen_make_user_root_descriptor (sgen_mark_normal_gc_handles), ROOT_TYPE_NORMAL, MONO_ROOT_SOURCE_GC_HANDLE, GINT_TO_POINTER (ROOT_TYPE_NORMAL), "GC Handles (SGen, Normal)");
 
        gc_initialized = 1;
 
index fa9742b..f869775 100644 (file)
@@ -105,7 +105,7 @@ static void
 bucket_alloc_callback (gpointer *bucket, guint32 new_bucket_size, gboolean alloc)
 {
        if (alloc)
-               sgen_register_root ((char *)bucket, new_bucket_size, SGEN_DESCRIPTOR_NULL, ROOT_TYPE_PINNED, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "GC Handle Bucket (SGen, Pinned)");
+               sgen_register_root ((char *)bucket, new_bucket_size, SGEN_DESCRIPTOR_NULL, ROOT_TYPE_PINNED, MONO_ROOT_SOURCE_GC_HANDLE, GINT_TO_POINTER (ROOT_TYPE_PINNED), "GC Handle Bucket (SGen, Pinned)");
        else
                sgen_deregister_root ((char *)bucket);
 }
@@ -114,7 +114,7 @@ static void
 bucket_alloc_report_root (gpointer *bucket, guint32 new_bucket_size, gboolean alloc)
 {
        if (alloc)
-               sgen_client_root_registered ((char *)bucket, new_bucket_size, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "GC Handle Bucket (SGen, Normal)");
+               sgen_client_root_registered ((char *)bucket, new_bucket_size, MONO_ROOT_SOURCE_GC_HANDLE, GINT_TO_POINTER (ROOT_TYPE_NORMAL), "GC Handle Bucket (SGen, Normal)");
        else
                sgen_client_root_deregistered ((char *)bucket);
 }
index 58ae8df..61eecd7 100644 (file)
@@ -50,6 +50,8 @@ EP_RT_DEFINE_THREAD_FUNC (streaming_thread)
        bool success = true;
        ep_rt_wait_event_handle_t *wait_event = ep_session_get_wait_event (session);
 
+       ep_rt_volatile_store_uint32_t (&session->started, 1);
+
        EP_GCX_PREEMP_ENTER
                while (ep_session_get_streaming_enabled (session)) {
                        bool events_written = false;
@@ -203,6 +205,7 @@ ep_session_alloc (
        instance->session_start_timestamp = ep_perf_timestamp_get ();
        instance->paused = false;
        instance->enable_stackwalk = ep_rt_config_value_get_enable_stackwalk ();
+       instance->started = 0;
 
 ep_on_exit:
        ep_requires_lock_held ();
@@ -393,6 +396,9 @@ ep_session_start_streaming (EventPipeSession *session)
                EP_ASSERT (!ep_session_get_streaming_enabled (session));
        }
 
+       if (session->session_type != EP_SESSION_TYPE_IPCSTREAM && session->session_type != EP_SESSION_TYPE_FILESTREAM)
+               ep_rt_volatile_store_uint32_t_without_barrier (&session->started, 1);
+
        ep_requires_lock_held ();
        return;
 }
@@ -581,6 +587,13 @@ ep_session_resume (EventPipeSession *session)
        session->paused = false;
 }
 
+bool
+ep_session_has_started (EventPipeSession *session)
+{
+       EP_ASSERT (session != NULL);
+       return ep_rt_volatile_load_uint32_t (&session->started) == 1 ? true : false;
+}
+
 #endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */
 #endif /* ENABLE_PERFTRACING */
 
index c7923cb..6b26dc0 100644 (file)
@@ -61,6 +61,8 @@ struct _EventPipeSession_Internal {
        bool paused;
        // Set via environment variable to enable or disable stack collection globally
        bool enable_stackwalk;
+       // Indicate that session is fully running (streaming thread started).
+       volatile uint32_t started;
 };
 
 #if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_SESSION_GETTER_SETTER)
@@ -199,5 +201,8 @@ ep_session_pause (EventPipeSession *session);
 void
 ep_session_resume (EventPipeSession *session);
 
+bool
+ep_session_has_started (EventPipeSession *session);
+
 #endif /* ENABLE_PERFTRACING */
 #endif /* __EVENTPIPE_SESSION_H__ */
index e711815..5073c52 100644 (file)
@@ -336,32 +336,20 @@ ep_write_buffer_uintptr_t (uint8_t **buffer, uintptr_t value)
 static
 inline
 uint32_t
-ep_write_buffer_string_utf8_to_utf16_t (uint8_t **buf, const ep_char8_t *str, uint32_t len)
+ep_write_buffer_string_utf16_t (uint8_t **buf, const ep_char16_t *str, uint32_t len)
 {
-       if (len == 0) {
-               (*buf)[0] = 0;
-               (*buf)[1] = 0;
-               *buf += sizeof (ep_char16_t);
-               return sizeof (ep_char16_t);
+       uint32_t num_bytes = 0;
+       if (str && len != 0) {
+               num_bytes = len * sizeof (ep_char16_t);
+               memcpy (*buf, str, num_bytes);
        }
-       ep_char16_t *str_utf16 = ep_rt_utf8_to_utf16le_string (str, len);
-       uint32_t num_bytes_utf16_str = 0;
-       while (str_utf16[num_bytes_utf16_str] != 0)
-               ++num_bytes_utf16_str;
-       num_bytes_utf16_str = (num_bytes_utf16_str + 1) * sizeof (ep_char16_t);
-       memcpy (*buf, str_utf16, num_bytes_utf16_str);
-       *buf += num_bytes_utf16_str;
-       ep_rt_utf16_string_free (str_utf16);
-       return num_bytes_utf16_str;
-}
 
-static
-inline
-uint32_t
-ep_write_buffer_string_utf16_t (uint8_t **buf, const ep_char16_t *str, uint32_t len)
-{
-       uint32_t num_bytes = (len + 1) * sizeof (ep_char16_t);
-       memcpy (*buf, str, num_bytes);
+       (*buf) [num_bytes] = 0;
+       num_bytes++;
+
+       (*buf) [num_bytes] = 0;
+       num_bytes++;
+
        *buf += num_bytes;
        return num_bytes;
 }