+gpointer
+mono_create_rgctx_lazy_fetch_trampoline (guint32 offset)
+{
+ static gboolean inited = FALSE;
+ static int num_trampolines = 0;
+
+ gpointer tramp, ptr;
+
+ if (mono_aot_only)
+ return mono_aot_get_lazy_fetch_trampoline (offset);
+
+ mono_trampolines_lock ();
+ if (rgctx_lazy_fetch_trampoline_hash)
+ tramp = g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset));
+ else
+ tramp = NULL;
+ mono_trampolines_unlock ();
+ if (tramp)
+ return tramp;
+
+ tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset);
+ ptr = mono_create_ftnptr (mono_get_root_domain (), tramp);
+
+ mono_trampolines_lock ();
+ if (!rgctx_lazy_fetch_trampoline_hash) {
+ rgctx_lazy_fetch_trampoline_hash = g_hash_table_new (NULL, NULL);
+ rgctx_lazy_fetch_trampoline_hash_addr = g_hash_table_new (NULL, NULL);
+ }
+ g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset), ptr);
+ g_assert (offset != -1);
+ g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash_addr, ptr, GUINT_TO_POINTER (offset + 1));
+ mono_trampolines_unlock ();
+
+ if (!inited) {
+ mono_counters_register ("RGCTX num lazy fetch trampolines",
+ MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_trampolines);
+ inited = TRUE;
+ }
+ num_trampolines++;
+
+ return ptr;
+}
+
+gpointer
+mono_create_monitor_enter_trampoline (void)
+{
+ static gpointer code;
+
+ if (mono_aot_only) {
+ if (!code)
+ code = mono_aot_get_named_code ("monitor_enter_trampoline");
+ return code;
+ }
+
+#ifdef MONO_ARCH_MONITOR_OBJECT_REG
+ mono_trampolines_lock ();
+
+ if (!code)
+ code = mono_arch_create_monitor_enter_trampoline ();
+
+ mono_trampolines_unlock ();
+#else
+ code = NULL;
+ g_assert_not_reached ();
+#endif
+
+ return code;
+}
+
+gpointer
+mono_create_monitor_exit_trampoline (void)
+{
+ static gpointer code;
+
+ if (mono_aot_only) {
+ if (!code)
+ code = mono_aot_get_named_code ("monitor_exit_trampoline");
+ return code;
+ }
+
+#ifdef MONO_ARCH_MONITOR_OBJECT_REG
+ mono_trampolines_lock ();
+
+ if (!code)
+ code = mono_arch_create_monitor_exit_trampoline ();
+
+ mono_trampolines_unlock ();
+#else
+ code = NULL;
+ g_assert_not_reached ();
+#endif
+ return code;
+}
+
+#ifdef ENABLE_LLVM
+/*
+ * mono_create_llvm_vcall_trampoline:
+ *
+ * LLVM emits code for virtual calls which mono_get_vcall_slot is unable to
+ * decode, i.e. only the final branch address is available:
+ * mov <offset>(%rax), %rax
+ * <random code inserted by instruction scheduling>
+ * call *%rax
+ *
+ * To work around this problem, we don't use the common vtable trampoline when
+ * llvm is enabled. Instead, we use one trampoline per method.
+ */
+gpointer
+mono_create_llvm_vcall_trampoline (MonoMethod *method)
+{
+ MonoDomain *domain;
+ gpointer res;
+
+ domain = mono_domain_get ();
+
+ mono_domain_lock (domain);
+ res = g_hash_table_lookup (domain_jit_info (domain)->llvm_vcall_trampoline_hash, method);
+ mono_domain_unlock (domain);
+ if (res)
+ return res;
+
+ res = mono_create_specific_trampoline (method, MONO_TRAMPOLINE_LLVM_VCALL, domain, NULL);
+
+ mono_domain_lock (domain);
+ g_hash_table_insert (domain_jit_info (domain)->llvm_vcall_trampoline_hash, method, res);
+ mono_domain_unlock (domain);
+
+ return res;
+}
+#endif
+