-#ifndef DISABLE_JIT
-
-static void
-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)
-{
- /*
- ldarg 0 obj
- brfalse.s obj_null
- */
-
- 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
- ldc.i4 MONO_STRUCT_OFFSET(MonoObject, synchronisation) objp off
- add &syncp
- ldind.i syncp
- stloc syncp
- ldloc syncp syncp
- brtrue/false.s syncp_true_false
- */
-
- mono_mb_emit_byte (mb, CEE_LDARG_0);
- mono_mb_emit_byte (mb, CEE_CONV_I);
- mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoObject, synchronisation));
- mono_mb_emit_byte (mb, CEE_ADD);
- mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_stloc (mb, syncp_loc);
-
-
- if (mono_gc_is_moving ()) {
- /*check for a thin hash*/
- mono_mb_emit_ldloc (mb, syncp_loc);
- mono_mb_emit_icon (mb, 0x01);
- mono_mb_emit_byte (mb, CEE_CONV_I);
- mono_mb_emit_byte (mb, CEE_AND);
- *thin_hash_branch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
-
- /*clear gc bits*/
- mono_mb_emit_ldloc (mb, syncp_loc);
- mono_mb_emit_icon (mb, ~0x3);
- mono_mb_emit_byte (mb, CEE_CONV_I);
- mono_mb_emit_byte (mb, CEE_AND);
- mono_mb_emit_stloc (mb, syncp_loc);
- } else {
- *thin_hash_branch = 0;
- }
-
- mono_mb_emit_ldloc (mb, syncp_loc);
- *syncp_true_false_branch = mono_mb_emit_short_branch (mb, branch_on_true ? CEE_BRTRUE_S : CEE_BRFALSE_S);
-}
-
-#endif
-
-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*
-register_fastpath (MonoMethod *method, int idx)
-{
- mono_memory_barrier ();
- monitor_il_fastpaths [idx] = method;
- return method;
-}
-
-static MonoMethod*
-mono_monitor_get_fast_enter_method (MonoMethod *monitor_enter_method)
-{
- MonoMethodBuilder *mb;
- MonoMethod *res;
- static MonoMethod *compare_exchange_method;
- int obj_null_branch, true_locktaken_branch = 0, syncp_null_branch, has_owner_branch, other_owner_branch, tid_branch, thin_hash_branch;
- int tid_loc, syncp_loc, owner_loc;
- gboolean is_v4 = mono_method_signature (monitor_enter_method)->param_count == 2;
- int fast_path_idx = is_v4 ? FASTPATH_ENTERV4 : FASTPATH_ENTER;
- WrapperInfo *info;
-
- /* The !is_v4 version is not used/tested */
- g_assert (is_v4);
-
- if (monitor_il_fastpaths [fast_path_idx])
- return monitor_il_fastpaths [fast_path_idx];
-
- if (!mono_get_runtime_callbacks ()->tls_key_supported (TLS_KEY_THREAD))
- return NULL;
-
- if (!compare_exchange_method) {
- MonoMethodDesc *desc;
- MonoClass *class;
-
- desc = mono_method_desc_new ("Interlocked:CompareExchange(intptr&,intptr,intptr)", FALSE);
- class = mono_class_from_name (mono_defaults.corlib, "System.Threading", "Interlocked");
- compare_exchange_method = mono_method_desc_search_in_class (desc, class);
- mono_method_desc_free (desc);
-
- if (!compare_exchange_method)
- return NULL;
- }
-
- 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 |
- METHOD_ATTRIBUTE_HIDE_BY_SIG | METHOD_ATTRIBUTE_FINAL;
-
-#ifndef DISABLE_JIT
- tid_loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
- 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, is_v4 ? &true_locktaken_branch : NULL, &syncp_null_branch, &thin_hash_branch, FALSE);
-
- /*
- mono. tls thread_tls_offset threadp
- ldc.i4 MONO_STRUCT_OFFSET(MonoThread, tid) threadp off
- add &tid
- ldind.i tid
- stloc tid
- ldloc syncp syncp
- ldc.i4 MONO_STRUCT_OFFSET(MonoThreadsSync, owner) syncp off
- add &owner
- ldind.i owner
- stloc owner
- ldloc owner owner
- brtrue.s tid
- */
-
- mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
- mono_mb_emit_byte (mb, CEE_MONO_TLS);
- mono_mb_emit_i4 (mb, TLS_KEY_THREAD);
- mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoInternalThread, tid));
- mono_mb_emit_byte (mb, CEE_ADD);
- mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_stloc (mb, tid_loc);
- mono_mb_emit_ldloc (mb, syncp_loc);
- mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoThreadsSync, owner));
- mono_mb_emit_byte (mb, CEE_ADD);
- mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_stloc (mb, owner_loc);
- mono_mb_emit_ldloc (mb, owner_loc);
- tid_branch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
-
- /*
- ldloc syncp syncp
- ldc.i4 MONO_STRUCT_OFFSET(MonoThreadsSync, owner) syncp off
- add &owner
- ldloc tid &owner tid
- ldc.i4 0 &owner tid 0
- call System.Threading.Interlocked.CompareExchange oldowner
- brtrue.s has_owner
- ret
- */
-
- mono_mb_emit_ldloc (mb, syncp_loc);
- mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoThreadsSync, owner));
- mono_mb_emit_byte (mb, CEE_ADD);
- mono_mb_emit_ldloc (mb, tid_loc);
- 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);
-
- /*
- tid:
- ldloc owner owner
- ldloc tid owner tid
- brne.s other_owner
- ldloc syncp syncp
- ldc.i4 MONO_STRUCT_OFFSET(MonoThreadsSync, nest) syncp off
- add &nest
- dup &nest &nest
- ldind.i4 &nest nest
- ldc.i4 1 &nest nest 1
- add &nest nest+
- stind.i4
- ret
- */
-
- mono_mb_patch_short_branch (mb, tid_branch);
- mono_mb_emit_ldloc (mb, owner_loc);
- mono_mb_emit_ldloc (mb, tid_loc);
- other_owner_branch = mono_mb_emit_short_branch (mb, CEE_BNE_UN_S);
- mono_mb_emit_ldloc (mb, syncp_loc);
- mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoThreadsSync, nest));
- mono_mb_emit_byte (mb, CEE_ADD);
- mono_mb_emit_byte (mb, CEE_DUP);
- mono_mb_emit_byte (mb, CEE_LDIND_I4);
- 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);
-
- /*
- obj_null, syncp_null, has_owner, other_owner:
- ldarg 0 obj
- call System.Threading.Monitor.Enter
- ret
- */
-
- if (thin_hash_branch)
- mono_mb_patch_short_branch (mb, thin_hash_branch);
- mono_mb_patch_short_branch (mb, obj_null_branch);
- mono_mb_patch_short_branch (mb, syncp_null_branch);
- mono_mb_patch_short_branch (mb, has_owner_branch);
- mono_mb_patch_short_branch (mb, other_owner_branch);
- if (true_locktaken_branch)
- mono_mb_patch_short_branch (mb, true_locktaken_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);
-#endif
-
- res = register_fastpath (mono_mb_create_method (mb, mono_signature_no_pinvoke (monitor_enter_method), 5), fast_path_idx);
-
- info = mono_image_alloc0 (mono_defaults.corlib, sizeof (WrapperInfo));
- info->subtype = is_v4 ? WRAPPER_SUBTYPE_FAST_MONITOR_ENTER_V4 : WRAPPER_SUBTYPE_FAST_MONITOR_ENTER;
- mono_marshal_set_wrapper_info (res, info);
-
- mono_mb_free (mb);
- return res;
-}
-
-static MonoMethod*
-mono_monitor_get_fast_exit_method (MonoMethod *monitor_exit_method)
-{
- MonoMethodBuilder *mb;
- MonoMethod *res;
- int obj_null_branch, has_waiting_branch, has_syncp_branch, owned_branch, nested_branch, thin_hash_branch;
- int syncp_loc;
- WrapperInfo *info;
-
- if (monitor_il_fastpaths [FASTPATH_EXIT])
- return monitor_il_fastpaths [FASTPATH_EXIT];
-
- if (!mono_get_runtime_callbacks ()->tls_key_supported (TLS_KEY_THREAD))
- return NULL;
-
- mb = mono_mb_new (mono_defaults.monitor_class, "FastMonitorExit", MONO_WRAPPER_UNKNOWN);
-
- mb->method->slot = -1;
- mb->method->flags = METHOD_ATTRIBUTE_PUBLIC | METHOD_ATTRIBUTE_STATIC |
- METHOD_ATTRIBUTE_HIDE_BY_SIG | METHOD_ATTRIBUTE_FINAL;
-
-#ifndef DISABLE_JIT
- syncp_loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-
- emit_obj_syncp_check (mb, syncp_loc, &obj_null_branch, NULL, &has_syncp_branch, &thin_hash_branch, TRUE);
-
- /*
- ret
- */
-
- mono_mb_emit_byte (mb, CEE_RET);
-
- /*
- has_syncp:
- ldloc syncp syncp
- ldc.i4 MONO_STRUCT_OFFSET(MonoThreadsSync, owner) syncp off
- add &owner
- ldind.i owner
- mono. tls thread_tls_offset owner threadp
- ldc.i4 MONO_STRUCT_OFFSET(MonoThread, tid) owner threadp off
- add owner &tid
- ldind.i owner tid
- beq.s owned
- */
-
- mono_mb_patch_short_branch (mb, has_syncp_branch);
- mono_mb_emit_ldloc (mb, syncp_loc);
- mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoThreadsSync, owner));
- mono_mb_emit_byte (mb, CEE_ADD);
- mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
- mono_mb_emit_byte (mb, CEE_MONO_TLS);
- mono_mb_emit_i4 (mb, TLS_KEY_THREAD);
- mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoInternalThread, tid));
- mono_mb_emit_byte (mb, CEE_ADD);
- mono_mb_emit_byte (mb, CEE_LDIND_I);
- owned_branch = mono_mb_emit_short_branch (mb, CEE_BEQ_S);
-
- /*
- ret
- */
-
- mono_mb_emit_byte (mb, CEE_RET);
-
- /*
- owned:
- ldloc syncp syncp
- ldc.i4 MONO_STRUCT_OFFSET(MonoThreadsSync, nest) syncp off
- add &nest
- dup &nest &nest
- ldind.i4 &nest nest
- dup &nest nest nest
- ldc.i4 1 &nest nest nest 1
- bgt.un.s nested &nest nest
- */
-
- mono_mb_patch_short_branch (mb, owned_branch);
- mono_mb_emit_ldloc (mb, syncp_loc);
- mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoThreadsSync, nest));
- mono_mb_emit_byte (mb, CEE_ADD);
- mono_mb_emit_byte (mb, CEE_DUP);
- mono_mb_emit_byte (mb, CEE_LDIND_I4);
- mono_mb_emit_byte (mb, CEE_DUP);
- mono_mb_emit_byte (mb, CEE_LDC_I4_1);
- nested_branch = mono_mb_emit_short_branch (mb, CEE_BGT_UN_S);
-
- /*
- pop &nest
- pop
- ldloc syncp syncp
- ldc.i4 MONO_STRUCT_OFFSET(MonoThreadsSync, entry_count) syncp off
- add &count
- ldind.i4 count
- brtrue.s has_waiting
- */
-
- mono_mb_emit_byte (mb, CEE_POP);
- mono_mb_emit_byte (mb, CEE_POP);
- mono_mb_emit_ldloc (mb, syncp_loc);
- mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoThreadsSync, entry_count));
- mono_mb_emit_byte (mb, CEE_ADD);
- mono_mb_emit_byte (mb, CEE_LDIND_I4);
- has_waiting_branch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
-
- /*
- ldloc syncp syncp
- ldc.i4 MONO_STRUCT_OFFSET(MonoThreadsSync, owner) syncp off
- add &owner
- ldnull &owner 0
- stind.i
- ret
- */
-
- mono_mb_emit_ldloc (mb, syncp_loc);
- mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoThreadsSync, owner));
- mono_mb_emit_byte (mb, CEE_ADD);
- mono_mb_emit_byte (mb, CEE_LDNULL);
- mono_mb_emit_byte (mb, CEE_STIND_I);
- mono_mb_emit_byte (mb, CEE_RET);
-
- /*
- nested:
- ldc.i4 1 &nest nest 1
- sub &nest nest-
- stind.i4
- ret
- */
-
- mono_mb_patch_short_branch (mb, nested_branch);
- mono_mb_emit_byte (mb, CEE_LDC_I4_1);
- mono_mb_emit_byte (mb, CEE_SUB);
- mono_mb_emit_byte (mb, CEE_STIND_I4);
- mono_mb_emit_byte (mb, CEE_RET);
-
- /*
- obj_null, has_waiting:
- ldarg 0 obj
- call System.Threading.Monitor.Exit
- ret
- */
-
- if (thin_hash_branch)
- mono_mb_patch_short_branch (mb, thin_hash_branch);
- mono_mb_patch_short_branch (mb, obj_null_branch);
- mono_mb_patch_short_branch (mb, has_waiting_branch);
- mono_mb_emit_byte (mb, CEE_LDARG_0);
- mono_mb_emit_managed_call (mb, monitor_exit_method, NULL);
- mono_mb_emit_byte (mb, CEE_RET);
-#endif
-
- res = register_fastpath (mono_mb_create_method (mb, mono_signature_no_pinvoke (monitor_exit_method), 5), FASTPATH_EXIT);
- mono_mb_free (mb);
-
- info = mono_image_alloc0 (mono_defaults.corlib, sizeof (WrapperInfo));
- info->subtype = WRAPPER_SUBTYPE_FAST_MONITOR_EXIT;
- mono_marshal_set_wrapper_info (res, info);
-
- return res;
-}
-
-MonoMethod*
-mono_monitor_get_fast_path (MonoMethod *enter_or_exit)
-{
- if (strcmp (enter_or_exit->name, "Enter") == 0)
- return mono_monitor_get_fast_enter_method (enter_or_exit);
- if (strcmp (enter_or_exit->name, "Exit") == 0)
- return mono_monitor_get_fast_exit_method (enter_or_exit);
- g_assert_not_reached ();
- return NULL;
-}
-