+ 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 G_STRUCT_OFFSET(MonoThread, tid) threadp off
+ add &tid
+ ldind.i tid
+ stloc tid
+ ldloc syncp syncp
+ ldc.i4 G_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, thread_tls_offset);
+ mono_mb_emit_icon (mb, G_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, G_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 G_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, G_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 G_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, G_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;