[jit] Add a fastpath to Monitor.Enter () which doesn't have a wrapper, and add a...
authorZoltan Varga <vargaz@gmail.com>
Thu, 11 Feb 2016 02:27:23 +0000 (21:27 -0500)
committerZoltan Varga <vargaz@gmail.com>
Thu, 11 Feb 2016 02:27:23 +0000 (21:27 -0500)
mono/metadata/monitor.c
mono/metadata/monitor.h
mono/mini/method-to-ir.c
mono/mini/mini-runtime.c

index 0c1d28130aff76741a2bc76e03d5cd84ea9dfdd8..b05a8416aac761b86579a210988f5627e168bc6d 100644 (file)
@@ -1009,6 +1009,12 @@ mono_monitor_enter (MonoObject *obj)
 }
 
 gboolean 
+mono_monitor_enter_fast (MonoObject *obj)
+{
+       return mono_monitor_try_enter_internal (obj, 0, FALSE) == 1;
+}
+
+gboolean
 mono_monitor_try_enter (MonoObject *obj, guint32 ms)
 {
        return mono_monitor_try_enter_internal (obj, ms, FALSE) == 1;
@@ -1100,7 +1106,6 @@ ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (MonoObject
 void
 mono_monitor_enter_v4 (MonoObject *obj, char *lock_taken)
 {
-
        if (*lock_taken == 1) {
                mono_set_pending_exception (mono_get_exception_argument ("lockTaken", "lockTaken is already true"));
                return;
@@ -1109,6 +1114,23 @@ mono_monitor_enter_v4 (MonoObject *obj, char *lock_taken)
        ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (obj, INFINITE, lock_taken);
 }
 
+/*
+ * mono_monitor_enter_v4_fast:
+ *
+ *   Same as mono_monitor_enter_v4, but return immediately if the
+ * monitor cannot be acquired.
+ * Returns TRUE if the lock was acquired, FALSE otherwise.
+ */
+gboolean
+mono_monitor_enter_v4_fast (MonoObject *obj, char *lock_taken)
+{
+       if (*lock_taken == 1)
+               return FALSE;
+       gint32 res = mono_monitor_try_enter_internal (obj, 0, TRUE);
+       *lock_taken = res == 1;
+       return res == 1;
+}
+
 gboolean 
 ves_icall_System_Threading_Monitor_Monitor_test_owner (MonoObject *obj)
 {
index bd796254034eac6f4fee232c63554231442536c3..f8e89936ba93067e658532d75e2e05e042321e0b 100644 (file)
@@ -106,6 +106,9 @@ MONO_API void mono_locks_dump (gboolean include_untaken);
 void mono_monitor_init (void);
 void mono_monitor_cleanup (void);
 
+gboolean mono_monitor_enter_fast (MonoObject *obj);
+gboolean mono_monitor_enter_v4_fast (MonoObject *obj, char *lock_taken);
+
 guint32 mono_monitor_get_object_monitor_gchandle (MonoObject *object);
 
 void mono_monitor_threads_sync_members_offset (int *status_offset, int *nest_offset);
index edece583b1c76defecd337447f51b568dc82060f..d804fa67259b8a4efade9e323c534a2e2f92c11c 100644 (file)
@@ -56,6 +56,7 @@
 #include <mono/metadata/security-core-clr.h>
 #include <mono/metadata/profiler-private.h>
 #include <mono/metadata/profiler.h>
+#include <mono/metadata/monitor.h>
 #include <mono/metadata/debug-mono-symfile.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-memory-model.h>
@@ -5981,7 +5982,6 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                } else 
                        return NULL;
        } else if (cmethod->klass == mono_defaults.object_class) {
-
                if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
                        int dreg = alloc_ireg_ref (cfg);
                        int vt_reg = alloc_preg (cfg);
@@ -6079,12 +6079,42 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                } else
                        return NULL;
        } else if (cmethod->klass == runtime_helpers_class) {
-
                if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
                        EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
                        return ins;
                } else
                        return NULL;
+       } else if (cmethod->klass == mono_defaults.monitor_class) {
+               gboolean is_enter = FALSE;
+               gboolean is_v4 = FALSE;
+
+               if (!strcmp (cmethod->name, "enter_with_atomic_var") && mono_method_signature (cmethod)->param_count == 2) {
+                       is_enter = TRUE;
+                       is_v4 = TRUE;
+               }
+               if (!strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1)
+                       is_enter = TRUE;
+
+               if (is_enter) {
+                       /*
+                        * To make async stack traces work, icalls which can block should have a wrapper.
+                        * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
+                        */
+                       MonoBasicBlock *end_bb, *slowpath_bb;
+
+                       NEW_BBLOCK (cfg, end_bb);
+                       NEW_BBLOCK (cfg, slowpath_bb);
+
+                       ins = mono_emit_jit_icall (cfg, is_v4 ? mono_monitor_enter_v4_fast : mono_monitor_enter_fast, args);
+                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->dreg, 0);
+                       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, slowpath_bb);
+                       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+                       MONO_START_BB (cfg, slowpath_bb);
+                       ins = mono_emit_jit_icall (cfg, is_v4 ? mono_monitor_enter_v4 : mono_monitor_enter, args);
+                       MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+                       MONO_START_BB (cfg, end_bb);
+                       return ins;
+               }
        } else if (cmethod->klass == mono_defaults.thread_class) {
                if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
                        MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
index 997f198c80bfedde195bbaefcae02441f87c40fb..52aaacbdd551f022f7159f1456e5e8ccd9523ba8 100644 (file)
@@ -48,6 +48,7 @@
 #include <mono/metadata/attach.h>
 #include <mono/metadata/runtime.h>
 #include <mono/metadata/reflection-internals.h>
+#include <mono/metadata/monitor.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-counters.h>
@@ -711,6 +712,19 @@ register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
        mono_register_jit_icall_full (func, name, sig, TRUE, FALSE, name);
 }
 
+static void
+register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
+{
+       MonoMethodSignature *sig;
+
+       if (sigstr)
+               sig = mono_create_icall_signature (sigstr);
+       else
+               sig = NULL;
+
+       mono_register_jit_icall_full (func, name, sig, FALSE, FALSE, NULL);
+}
+
 static void
 register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
 {
@@ -3948,6 +3962,11 @@ register_icalls (void)
        register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
        register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
 
+       register_icall_with_wrapper (mono_monitor_enter, "mono_monitor_enter", "void obj");
+       register_icall_with_wrapper (mono_monitor_enter_v4, "mono_monitor_enter_v4", "void obj ptr");
+       register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
+       register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
+
 #ifdef TARGET_IOS
        register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
 #endif