Implement fast il wrapper for v4 Monitor.Enter.
authorRodrigo Kumpera <kumpera@gmail.com>
Mon, 23 May 2011 21:27:07 +0000 (18:27 -0300)
committerRodrigo Kumpera <kumpera@gmail.com>
Mon, 23 May 2011 21:27:07 +0000 (18:27 -0300)
* monitor.c (mono_monitor_get_fast_enter_method): Add support
for v4 Enter.

* monitor.c (mono_monitor_is_il_fastpath_wrapper): New function
that returns true for any of the monitor il wrappers.

* runtime.c (mono_runtime_is_critical_method): New function
that reports if a given method is critical and must not be interrupted.

* mono-threads.c (is_thread_in_critical_region): As the runtime if
the top method is critical in addition to the GC.

* method-to-ir.c (mini_emit_inst_for_method): Enable the IL fastpath
for v4 Monitor.Enter.

mono/metadata/monitor.c
mono/metadata/object-internals.h
mono/metadata/runtime.c
mono/metadata/runtime.h
mono/mini/method-to-ir.c
mono/utils/mono-threads.c

index f86ff5c0cd637264609614e96fdfdcd09a256dfd..84a20af60546c644ae5130a3e221944778d5f1cc 100644 (file)
@@ -774,7 +774,7 @@ mono_monitor_get_object_monitor_weak_link (MonoObject *object)
 }
 
 static void
-emit_obj_syncp_check (MonoMethodBuilder *mb, int syncp_loc, int *obj_null_branch, int *syncp_true_false_branch,
+emit_obj_syncp_check (MonoMethodBuilder *mb, int syncp_loc, int *obj_null_branch, int *true_locktaken_branch, int *syncp_true_false_branch,
        int *thin_hash_branch, gboolean branch_on_true)
 {
        /*
@@ -785,6 +785,17 @@ emit_obj_syncp_check (MonoMethodBuilder *mb, int syncp_loc, int *obj_null_branch
        mono_mb_emit_byte (mb, CEE_LDARG_0);
        *obj_null_branch = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
 
+       /*
+         ldarg.1
+         ldind.i1
+         brtrue.s true_locktaken
+       */
+       if (true_locktaken_branch) {
+               mono_mb_emit_byte (mb, CEE_LDARG_1);
+               mono_mb_emit_byte (mb, CEE_LDIND_I1);
+               *true_locktaken_branch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
+       }
+
        /*
          ldarg         0                                                       obj
          conv.i                                                                objp
@@ -826,23 +837,52 @@ emit_obj_syncp_check (MonoMethodBuilder *mb, int syncp_loc, int *obj_null_branch
        *syncp_true_false_branch = mono_mb_emit_short_branch (mb, branch_on_true ? CEE_BRTRUE_S : CEE_BRFALSE_S);
 }
 
+static MonoMethod* monitor_il_fastpaths[3];
+
+gboolean
+mono_monitor_is_il_fastpath_wrapper (MonoMethod *method)
+{
+       int i;
+       for (i = 0; i < 3; ++i) {
+               if (monitor_il_fastpaths [i] == method)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+enum {
+       FASTPATH_ENTER,
+       FASTPATH_ENTERV4,
+       FASTPATH_EXIT
+};
+
+
 static MonoMethod*
-mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method)
+register_fastpath (MonoMethod *method, int idx)
 {
-       static MonoMethod *fast_monitor_enter;
-       static MonoMethod *compare_exchange_method;
+       mono_memory_barrier ();
+       monitor_il_fastpaths [idx] = method;
+       return method;
+}
 
+static MonoMethod*
+mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method)
+{
        MonoMethodBuilder *mb;
-       int obj_null_branch, syncp_null_branch, has_owner_branch, other_owner_branch, tid_branch, thin_hash_branch;
+       MonoMethod *res;
+       static MonoMethod *compare_exchange_method;
+       int obj_null_branch, true_locktaken_branch, syncp_null_branch, has_owner_branch, other_owner_branch, tid_branch, thin_hash_branch;
        int tid_loc, syncp_loc, owner_loc;
        int thread_tls_offset;
+       gboolean is_v4 = mono_method_signature (monitor_enter_method)->param_count == 2;
+       int fast_path_idx = is_v4 ? FASTPATH_ENTERV4 : FASTPATH_ENTER;
 
        thread_tls_offset = mono_thread_get_tls_offset ();
        if (thread_tls_offset == -1)
                return NULL;
 
-       if (fast_monitor_enter)
-               return fast_monitor_enter;
+       if (monitor_il_fastpaths [fast_path_idx])
+               return monitor_il_fastpaths [fast_path_idx];
 
        if (!compare_exchange_method) {
                MonoMethodDesc *desc;
@@ -857,7 +897,7 @@ mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method)
                        return NULL;
        }
 
-       mb = mono_mb_new (mono_defaults.monitor_class, "FastMonitorEnter", MONO_WRAPPER_UNKNOWN);
+       mb = mono_mb_new (mono_defaults.monitor_class, is_v4 ? "FastMonitorEnterV4" : "FastMonitorEnter", MONO_WRAPPER_UNKNOWN);
 
        mb->method->slot = -1;
        mb->method->flags = METHOD_ATTRIBUTE_PUBLIC | METHOD_ATTRIBUTE_STATIC |
@@ -867,7 +907,7 @@ mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method)
        syncp_loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
        owner_loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 
-       emit_obj_syncp_check (mb, syncp_loc, &obj_null_branch, &syncp_null_branch, &thin_hash_branch, FALSE);
+       emit_obj_syncp_check (mb, syncp_loc, &obj_null_branch, &true_locktaken_branch, &syncp_null_branch, &thin_hash_branch, FALSE);
 
        /*
          mono. tls     thread_tls_offset                                       threadp
@@ -917,6 +957,12 @@ mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method)
        mono_mb_emit_byte (mb, CEE_LDC_I4_0);
        mono_mb_emit_managed_call (mb, compare_exchange_method, NULL);
        has_owner_branch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
+
+       if (is_v4) {
+               mono_mb_emit_byte (mb, CEE_LDARG_1);
+               mono_mb_emit_byte (mb, CEE_LDC_I4_1);
+               mono_mb_emit_byte (mb, CEE_STIND_I1);
+       }
        mono_mb_emit_byte (mb, CEE_RET);
 
        /*
@@ -947,6 +993,13 @@ mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method)
        mono_mb_emit_byte (mb, CEE_LDC_I4_1);
        mono_mb_emit_byte (mb, CEE_ADD);
        mono_mb_emit_byte (mb, CEE_STIND_I4);
+
+       if (is_v4) {
+               mono_mb_emit_byte (mb, CEE_LDARG_1);
+               mono_mb_emit_byte (mb, CEE_LDC_I4_1);
+               mono_mb_emit_byte (mb, CEE_STIND_I1);
+       }
+
        mono_mb_emit_byte (mb, CEE_RET);
 
        /*
@@ -963,21 +1016,21 @@ mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method)
        mono_mb_patch_short_branch (mb, has_owner_branch);
        mono_mb_patch_short_branch (mb, other_owner_branch);
        mono_mb_emit_byte (mb, CEE_LDARG_0);
+       if (is_v4)
+               mono_mb_emit_byte (mb, CEE_LDARG_1);
        mono_mb_emit_managed_call (mb, monitor_enter_method, NULL);
        mono_mb_emit_byte (mb, CEE_RET);
 
-       fast_monitor_enter = mono_mb_create_method (mb, mono_signature_no_pinvoke (monitor_enter_method), 5);
+       res = register_fastpath (mono_mb_create_method (mb, mono_signature_no_pinvoke (monitor_enter_method), 5), fast_path_idx);
        mono_mb_free (mb);
-
-       return fast_monitor_enter;
+       return res;
 }
 
 static MonoMethod*
 mono_monitor_get_fast_exit_method (MonoMethod *monitor_exit_method)
 {
-       static MonoMethod *fast_monitor_exit;
-
        MonoMethodBuilder *mb;
+       MonoMethod *res;
        int obj_null_branch, has_waiting_branch, has_syncp_branch, owned_branch, nested_branch, thin_hash_branch;
        int thread_tls_offset;
        int syncp_loc;
@@ -986,8 +1039,8 @@ mono_monitor_get_fast_exit_method (MonoMethod *monitor_exit_method)
        if (thread_tls_offset == -1)
                return NULL;
 
-       if (fast_monitor_exit)
-               return fast_monitor_exit;
+       if (monitor_il_fastpaths [FASTPATH_EXIT])
+               return monitor_il_fastpaths [FASTPATH_EXIT];
 
        mb = mono_mb_new (mono_defaults.monitor_class, "FastMonitorExit", MONO_WRAPPER_UNKNOWN);
 
@@ -997,7 +1050,7 @@ mono_monitor_get_fast_exit_method (MonoMethod *monitor_exit_method)
 
        syncp_loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 
-       emit_obj_syncp_check (mb, syncp_loc, &obj_null_branch, &has_syncp_branch, &thin_hash_branch, TRUE);
+       emit_obj_syncp_check (mb, syncp_loc, &obj_null_branch, NULL, &has_syncp_branch, &thin_hash_branch, TRUE);
 
        /*
          ret
@@ -1122,10 +1175,10 @@ mono_monitor_get_fast_exit_method (MonoMethod *monitor_exit_method)
        mono_mb_emit_managed_call (mb, monitor_exit_method, NULL);
        mono_mb_emit_byte (mb, CEE_RET);
 
-       fast_monitor_exit = mono_mb_create_method (mb, mono_signature_no_pinvoke (monitor_exit_method), 5);
+       res = register_fastpath (mono_mb_create_method (mb, mono_signature_no_pinvoke (monitor_exit_method), 5), FASTPATH_EXIT);
        mono_mb_free (mb);
 
-       return fast_monitor_exit;
+       return res;
 }
 
 MonoMethod*
index 07e0618163b4dd92d89b43f8042d69cfb6a8f32f..7baaf485a865490a8cb75ed034852627636c9cb2 100644 (file)
@@ -1567,6 +1567,9 @@ mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s) MONO_INTERNAL
 char *
 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s) MONO_INTERNAL;
 
+gboolean
+mono_monitor_is_il_fastpath_wrapper (MonoMethod *method) MONO_INTERNAL;
+
 #endif /* __MONO_OBJECT_INTERNALS_H__ */
 
 
index e4a4c32b3a374c054be6769d6662089e96c81587..364e08d7710f6573dbaf2a3b6ae866574ecac396 100644 (file)
@@ -41,3 +41,11 @@ mono_runtime_shutdown (void)
        mono_domain_foreach (fire_process_exit_event, NULL);
 }
 
+
+gboolean
+mono_runtime_is_critical_method (MonoMethod *method)
+{
+       if (mono_monitor_is_il_fastpath_wrapper (method))
+               return TRUE;
+       return FALSE;
+}
index 95dac47d0051635599cdd93c40bc636e340aabf8..1e408f8b98355d98f6b425dbe60967a6a2c61952 100644 (file)
@@ -16,6 +16,8 @@ MONO_BEGIN_DECLS
 
 void mono_runtime_shutdown (void) MONO_INTERNAL;
 
+gboolean mono_runtime_is_critical_method (MonoMethod *method) MONO_INTERNAL;
+
 MONO_END_DECLS
 
 #endif /* _MONO_METADATA_RUNTIME_H_ */
index d52656894943988707b64513f4096117e90db681..195c749117f2ddfa10183aafd66ba7ebc91cf263 100644 (file)
@@ -4447,6 +4447,24 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        return ins;
                }
        } else if (cmethod->klass == mono_defaults.monitor_class) {
+
+               /* FIXME this should be integrated to the check below once we support the trampoline version */
+#if defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
+               if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
+                       MonoMethod *fast_method = NULL;
+
+                       /* Avoid infinite recursion */
+                       if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN && !strcmp (cfg->method->name, "FastMonitorEnterV4"))
+                               return NULL;
+                               
+                       fast_method = mono_monitor_get_fast_path (cmethod);
+                       if (!fast_method)
+                               return NULL;
+
+                       return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);                 
+               }
+#endif
+
 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
                if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
                        MonoCallInst *call;
index dc16ae00911c1f065971d80ffec871ec4bc5ecdc..157d506888a847b1fcf82a05d2b5a8ff7bf65b84 100644 (file)
@@ -14,6 +14,7 @@
 #include <mono/utils/hazard-pointer.h>
 #include <mono/metadata/gc-internal.h>
 #include <mono/metadata/appdomain.h>
+#include <mono/metadata/runtime.h>
 
 #include <errno.h>
 
@@ -381,7 +382,7 @@ is_thread_in_critical_region (MonoThreadInfo *info)
 
        method = ji->method;
 
-       return mono_gc_is_critical_method (method);
+       return mono_runtime_is_critical_method (method) || mono_gc_is_critical_method (method);
 }
 
 /*