Merge pull request #1654 from alexanderkyte/xunit-fixes
authorRodrigo Kumpera <kumpera@gmail.com>
Fri, 15 May 2015 19:24:44 +0000 (15:24 -0400)
committerRodrigo Kumpera <kumpera@gmail.com>
Fri, 15 May 2015 19:24:44 +0000 (15:24 -0400)
Fix various bugs causing hangs on Xunit

mcs/class/corlib/System.Runtime.Remoting.Channels/CrossAppDomainChannel.cs
mcs/class/corlib/System.Runtime.Remoting.Messaging/CADMessages.cs
mcs/class/corlib/System.Runtime.Remoting/ObjRef.cs
mono/metadata/marshal.c

index 938805aa3a3a085184ad7c06bd07d86a17ae4c37..c9018521fd3d29f82530a98022f3ec8050d9d944 100644 (file)
@@ -318,6 +318,22 @@ namespace System.Runtime.Remoting.Channels
                        return mem;
                }
 
+               // This wrapper deserializes the objects on
+               // it's input byte array. It's safe for concurrent use
+               // while Deserialize will modify the cursor of the MemoryStream
+               //
+               // It is also the preferred way to deserialize CADMessage
+               // objects because their payload must be stored as byte arrays to avoid
+               // cross-domain references to MemoryStream objects
+               internal static object DeserializeObjectSafe(byte[] mem)
+               {
+                       byte [] outstream = new byte [mem.Length];
+                       Array.Copy (mem, outstream, mem.Length);
+                       MemoryStream objStream = new MemoryStream (outstream);
+                       var returnVal = DeserializeObject (objStream);
+                       return returnVal;
+               }
+
                internal static MemoryStream SerializeObject(object obj)
                {
                        MemoryStream mem = new MemoryStream ();
index 0f19f0249d1dec7d077f19057f1616b52cba56ad..0b267eed10646f58dc1e530c79fba21f2bb65464 100644 (file)
@@ -51,14 +51,16 @@ namespace System.Runtime.Remoting.Messaging {
        }
        
        internal class CADObjRef {
-               ObjRef objref;
-               public int SourceDomain;
+               internal ObjRef objref;
+               internal int SourceDomain;
+               internal byte[] TypeInfo;
 
                public CADObjRef (ObjRef o, int sourceDomain) {
                        objref = o;
+                       TypeInfo = o.SerializeType ();
                        SourceDomain = sourceDomain;
                }
-               
+
                public string TypeName {
                        get { return objref.TypeInfo.TypeName; }
                }
@@ -68,37 +70,53 @@ namespace System.Runtime.Remoting.Messaging {
                }
        }
 
+       [Serializable]
+       internal class CADMethodRef
+       {
+               internal string FullTypeName;
+               internal IntPtr MethodHandlePtr;
+
+               public RuntimeMethodHandle MethodHandle {
+                       get {
+                               return new RuntimeMethodHandle (MethodHandlePtr);
+                       }
+               }
+
+               public CADMethodRef (IMethodMessage msg)
+               {
+                       MethodHandlePtr = msg.MethodBase.MethodHandle.Value;
+                       FullTypeName = msg.MethodBase.DeclaringType.AssemblyQualifiedName;
+               }
+       }
+
        internal class CADMessageBase {
 
                protected object [] _args;
                protected byte [] _serializedArgs = null;
                protected int _propertyCount = 0;
                protected CADArgHolder _callContext;
-               internal RuntimeMethodHandle MethodHandle;
-               internal string FullTypeName;
-               internal MethodBase _method;
+               internal byte[] serializedMethod;
 
                public CADMessageBase (IMethodMessage msg) {
-                       MethodHandle = msg.MethodBase.MethodHandle;
-                       FullTypeName = msg.MethodBase.DeclaringType.AssemblyQualifiedName;
+                       CADMethodRef methodRef = new CADMethodRef (msg);
+                       serializedMethod = CADSerializer.SerializeObject (methodRef).GetBuffer ();
                }
 
                internal MethodBase method {
-                       get {
-                               if (_method == null) {
-                                       _method = GetMethod();
-                               }
-                               return _method;
-                       }
+                       get { return GetMethod (); }
                }
 
                internal MethodBase GetMethod ()
                {
-                       Type tt = Type.GetType (FullTypeName, true);
+                       CADMethodRef methRef = (CADMethodRef)CADSerializer.DeserializeObjectSafe (serializedMethod);
+
+                       MethodBase _method;
+
+                       Type tt = Type.GetType (methRef.FullTypeName, true);
                        if (tt.IsGenericType || tt.IsGenericTypeDefinition) {
-                               _method = MethodBase.GetMethodFromHandleNoGenericCheck (MethodHandle);
+                               _method = MethodBase.GetMethodFromHandleNoGenericCheck (methRef.MethodHandle);
                        } else {
-                               _method = MethodBase.GetMethodFromHandle (MethodHandle);
+                               _method = MethodBase.GetMethodFromHandle (methRef.MethodHandle);
                        }
 
                        if (tt != _method.DeclaringType) {
@@ -241,7 +259,7 @@ namespace System.Runtime.Remoting.Messaging {
                        return new CADArgHolder(args.Count - 1);
                }
 
-               protected object UnmarshalArgument (object arg, ArrayList args, Type argType) {
+               protected object UnmarshalArgument (object arg, ArrayList args) {
                        if (arg == null) return null;
                        
                        // Check if argument is an holder (then we know that it's a serialized argument)
@@ -252,19 +270,7 @@ namespace System.Runtime.Remoting.Messaging {
 
                        CADObjRef objref = arg as CADObjRef;
                        if (null != objref) {
-                               string typeName;
-
-                               if (argType != null) {
-                                       typeName = string.Copy (argType.AssemblyQualifiedName);
-                               } else {
-                                       typeName = string.Copy (objref.TypeName);
-                               }
-
-                               string uri = string.Copy (objref.URI);
-                               int domid = objref.SourceDomain;
-                               
-                               ChannelInfo cinfo = new ChannelInfo (new CrossAppDomainData (domid));
-                               ObjRef localRef = new ObjRef (typeName, uri, cinfo);
+                               ObjRef localRef = objref.objref.DeserializeInTheCurrentDomain (objref.SourceDomain, objref.TypeInfo);
                                return RemotingServices.Unmarshal (localRef);
                        }
                        
@@ -334,12 +340,12 @@ namespace System.Runtime.Remoting.Messaging {
                        return marshalledArgs;
                }
 
-               internal object [] UnmarshalArguments (object [] arguments, ArrayList args, Type [] sig) {
+               internal object [] UnmarshalArguments (object [] arguments, ArrayList args) {
                        object [] unmarshalledArgs = new object [arguments.Length];
 
                        int total = arguments.Length;
                        for (int i = 0; i < total; i++)
-                               unmarshalledArgs [i] = UnmarshalArgument (arguments [i], args, sig [i]);
+                               unmarshalledArgs [i] = UnmarshalArgument (arguments [i], args);
 
                        return unmarshalledArgs;
                }
@@ -416,8 +422,7 @@ namespace System.Runtime.Remoting.Messaging {
                }
 
                internal object [] GetArgs (ArrayList args) {
-                       Type [] sigs = GetSignature (method, true);
-                       return UnmarshalArguments (_args, args, sigs);
+                       return UnmarshalArguments (_args, args);
                }
 
                internal int PropertiesCount {
@@ -482,17 +487,11 @@ namespace System.Runtime.Remoting.Messaging {
                }
 
                internal object [] GetArgs (ArrayList args) {
-                       return UnmarshalArguments (_args, args, _sig);
+                       return UnmarshalArguments (_args, args);
                }
 
                internal object GetReturnValue (ArrayList args) {
-                       MethodInfo minfo = method as MethodInfo;
-
-                       Type returnType = null;
-                       if (minfo != null)
-                               returnType = minfo.ReturnType;
-
-                       return UnmarshalArgument (_returnValue, args, returnType);
+                       return UnmarshalArgument (_returnValue, args);
                }
 
                internal Exception GetException(ArrayList args) {
index 4337815c34ab3c62709d8519f935a416cb79fbf7..e73e956afac7db3334d38c6503153c878b588d00 100644 (file)
@@ -34,6 +34,7 @@
 //
 
 using System;
+using System.IO;
 using System.Runtime.Serialization;
 using System.Runtime.Remoting.Channels;
 using System.Runtime.Remoting.Messaging;
@@ -64,14 +65,34 @@ namespace System.Runtime.Remoting {
                        UpdateChannelInfo();
                }
 
-               internal ObjRef (string typeName, string uri, IChannelInfo cinfo) 
+               internal ObjRef (string uri, IChannelInfo cinfo)
                {
                        this.uri = uri;
-                       channel_info = cinfo;
-                       typeInfo = new TypeInfo (Type.GetType (typeName, true));
+                       this.channel_info = cinfo;
                }
 
-               internal ObjRef (ObjRef o, bool unmarshalAsProxy) {
+               internal ObjRef DeserializeInTheCurrentDomain (int domainId, byte[] tInfo)
+               {
+                               string local_uri = string.Copy (this.uri);
+                               ChannelInfo cinfo = new ChannelInfo (new CrossAppDomainData (domainId));
+                               ObjRef res = new ObjRef (local_uri, cinfo);
+                               IRemotingTypeInfo typeInfo = (IRemotingTypeInfo)CADSerializer.DeserializeObjectSafe (tInfo);
+                               res.typeInfo = typeInfo;
+                               return res;
+               }
+
+               internal byte[] SerializeType ()
+               {
+                       // FIXME: Assert self and typeinfo in same domain
+                       if (typeInfo == null)
+                               throw new Exception ("Attempt to serialize a null TypeInfo.");
+
+                       MemoryStream stm = CADSerializer.SerializeObject (typeInfo);
+                       return stm.GetBuffer ();
+               }
+
+               internal ObjRef (ObjRef o, bool unmarshalAsProxy)
+               {
                        channel_info = o.channel_info;
                        uri = o.uri;
        
index 3a5578eff2bf546b02985a1832968541393e24bd..72c93b8bd1b574bd8b0bd4d20cbe0593bf2a931a 100644 (file)
@@ -133,6 +133,9 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params);
 static void
 mono_marshal_set_last_error_windows (int error);
 
+static MonoObject *
+mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *cache);
+
 static void init_safe_handle (void);
 
 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
@@ -245,6 +248,7 @@ mono_marshal_init (void)
                register_icall (mono_context_set, "mono_context_set", "void object", FALSE);
                register_icall (mono_gc_wbarrier_generic_nostore, "wb_generic", "void ptr", FALSE);
                register_icall (mono_gchandle_get_target, "mono_gchandle_get_target", "object int32", TRUE);
+               register_icall (mono_marshal_isinst_with_cache, "mono_marshal_isinst_with_cache", "object object ptr ptr", FALSE);
 
                mono_cominterop_init ();
                mono_remoting_init ();
@@ -8104,6 +8108,66 @@ mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
 
        return mono_compile_method (method);
 }
+/*
+ * The code directly following this is the cache hit, value positive branch
+ *
+ * This function takes a new method builder with 0 locals and adds two locals
+ * to create multiple out-branches and the fall through state of having the object
+ * on the stack after a cache miss
+ */
+static void
+generate_check_cache (int obj_arg_position, int class_arg_position, int cache_arg_position, // In-parameters
+                                                                                       int *null_obj, int *cache_hit_neg, int *cache_hit_pos, // Out-parameters
+                                                                                       MonoMethodBuilder *mb)
+{
+       int cache_miss_pos;
+
+       /* allocate local 0 (pointer) obj_vtable */
+       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       /* allocate local 1 (pointer) cached_vtable */
+       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+       /*if (!obj)*/
+       mono_mb_emit_ldarg (mb, obj_arg_position);
+       *null_obj = mono_mb_emit_branch (mb, CEE_BRFALSE);
+
+       /*obj_vtable = obj->vtable;*/
+       mono_mb_emit_ldarg (mb, obj_arg_position);
+       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       mono_mb_emit_stloc (mb, 0);
+
+       /* cached_vtable = *cache*/
+       mono_mb_emit_ldarg (mb, cache_arg_position);
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       mono_mb_emit_stloc (mb, 1);
+
+       mono_mb_emit_ldloc (mb, 1);
+       mono_mb_emit_byte (mb, CEE_LDC_I4);
+       mono_mb_emit_i4 (mb, ~0x1);
+       mono_mb_emit_byte (mb, CEE_CONV_I);
+       mono_mb_emit_byte (mb, CEE_AND);
+       mono_mb_emit_ldloc (mb, 0);
+       /*if ((cached_vtable & ~0x1)== obj_vtable)*/
+       cache_miss_pos = mono_mb_emit_branch (mb, CEE_BNE_UN);
+
+       /*return (cached_vtable & 0x1) ? NULL : obj;*/
+       mono_mb_emit_ldloc (mb, 1);
+       mono_mb_emit_byte(mb, CEE_LDC_I4_1);
+       mono_mb_emit_byte (mb, CEE_CONV_U);
+       mono_mb_emit_byte (mb, CEE_AND);
+       *cache_hit_neg = mono_mb_emit_branch (mb, CEE_BRTRUE);
+       *cache_hit_pos = mono_mb_emit_branch (mb, CEE_BR);
+
+       // slow path
+       mono_mb_patch_branch (mb, cache_miss_pos);
+
+       // if isinst
+       mono_mb_emit_ldarg (mb, obj_arg_position);
+       mono_mb_emit_ldarg (mb, class_arg_position);
+       mono_mb_emit_ldarg (mb, cache_arg_position);
+       mono_mb_emit_icall (mb, mono_marshal_isinst_with_cache);
+}
 
 /*
  * This does the equivalent of mono_object_castclass_with_cache.
@@ -8116,63 +8180,36 @@ mono_marshal_get_castclass_with_cache (void)
        MonoMethod *res;
        MonoMethodBuilder *mb;
        MonoMethodSignature *sig;
-       int return_null_pos, cache_miss_pos, invalid_cast_pos;
+       int return_null_pos, positive_cache_hit_pos, negative_cache_hit_pos, invalid_cast_pos;
        WrapperInfo *info;
 
+       const int obj_arg_position = 0;
+       const int class_arg_position = 1;
+       const int cache_arg_position = 2;
+
        if (cached)
                return cached;
 
        mb = mono_mb_new (mono_defaults.object_class, "__castclass_with_cache", MONO_WRAPPER_CASTCLASS);
        sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
-       sig->params [0] = &mono_defaults.object_class->byval_arg;
-       sig->params [1] = &mono_defaults.int_class->byval_arg;
-       sig->params [2] = &mono_defaults.int_class->byval_arg;
+       sig->params [obj_arg_position] = &mono_defaults.object_class->byval_arg;
+       sig->params [class_arg_position] = &mono_defaults.int_class->byval_arg;
+       sig->params [cache_arg_position] = &mono_defaults.int_class->byval_arg;
        sig->ret = &mono_defaults.object_class->byval_arg;
        sig->pinvoke = 0;
 
 #ifndef DISABLE_JIT
-       /* allocate local 0 (pointer) obj_vtable */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-
-       /*if (!obj)*/
-       mono_mb_emit_ldarg (mb, 0);
-       return_null_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
-
-       /*obj_vtable = obj->vtable;*/
-       mono_mb_emit_ldarg (mb, 0);
-       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
-       mono_mb_emit_byte (mb, CEE_LDIND_I);
-       mono_mb_emit_stloc (mb, 0);
-
-       /* *cache */
-       mono_mb_emit_ldarg (mb, 2);
-       mono_mb_emit_byte (mb, CEE_LDIND_I);
-       mono_mb_emit_ldloc (mb, 0);
-
-       /*if (*cache == obj_vtable)*/
-       cache_miss_pos = mono_mb_emit_branch (mb, CEE_BNE_UN);
-
-       /*return obj;*/
-       mono_mb_emit_ldarg (mb, 0);
-       mono_mb_emit_byte (mb, CEE_RET);
-
-       mono_mb_patch_branch (mb, cache_miss_pos);
-       /*if (mono_object_isinst (obj, klass)) */
-       mono_mb_emit_ldarg (mb, 0);
-       mono_mb_emit_ldarg (mb, 1);
-       mono_mb_emit_icall (mb, mono_object_isinst);
+       generate_check_cache (obj_arg_position, class_arg_position, cache_arg_position, 
+                                                                                               &return_null_pos, &negative_cache_hit_pos, &positive_cache_hit_pos, mb);
        invalid_cast_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
 
-       /**cache = obj_vtable;*/
-       mono_mb_emit_ldarg (mb, 2);
-       mono_mb_emit_ldloc (mb, 0);
-       mono_mb_emit_byte (mb, CEE_STIND_I);
-
        /*return obj;*/
-       mono_mb_emit_ldarg (mb, 0);
+       mono_mb_patch_branch (mb, positive_cache_hit_pos);
+       mono_mb_emit_ldarg (mb, obj_arg_position);
        mono_mb_emit_byte (mb, CEE_RET);
 
        /*fails*/
+       mono_mb_patch_branch (mb, negative_cache_hit_pos);
        mono_mb_patch_branch (mb, invalid_cast_pos);
        mono_mb_emit_exception (mb, "InvalidCastException", NULL);
 
@@ -8195,6 +8232,23 @@ mono_marshal_get_castclass_with_cache (void)
        return cached;
 }
 
+static MonoObject *
+mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *cache)
+{
+       MonoObject *isinst = mono_object_isinst (obj, klass);
+
+       if (obj->vtable->klass == mono_defaults.transparent_proxy_class)
+               return isinst;
+
+       uintptr_t cache_update = (uintptr_t)obj->vtable;
+       if (!isinst)
+               cache_update = cache_update | 0x1;
+
+       *cache = cache_update;
+
+       return isinst;
+}
+
 /*
  * This does the equivalent of mono_object_isinst_with_cache.
  * The wrapper info for the wrapper is a WrapperInfo structure.
@@ -8206,100 +8260,43 @@ mono_marshal_get_isinst_with_cache (void)
        MonoMethod *res;
        MonoMethodBuilder *mb;
        MonoMethodSignature *sig;
-       int return_null_pos, cache_miss_pos, cache_hit_pos, not_an_instance_pos, negative_cache_hit_pos;
+       int return_null_pos, positive_cache_hit_pos, negative_cache_hit_pos;
        WrapperInfo *info;
 
+       const int obj_arg_position = 0;
+       const int class_arg_position = 1;
+       const int cache_arg_position = 2;
+
        if (cached)
                return cached;
 
        mb = mono_mb_new (mono_defaults.object_class, "__isinst_with_cache", MONO_WRAPPER_CASTCLASS);
        sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
-       sig->params [0] = &mono_defaults.object_class->byval_arg;
-       sig->params [1] = &mono_defaults.int_class->byval_arg;
-       sig->params [2] = &mono_defaults.int_class->byval_arg;
+       // The object
+       sig->params [obj_arg_position] = &mono_defaults.object_class->byval_arg;
+       // The class
+       sig->params [class_arg_position] = &mono_defaults.int_class->byval_arg;
+       // The cache
+       sig->params [cache_arg_position] = &mono_defaults.int_class->byval_arg;
        sig->ret = &mono_defaults.object_class->byval_arg;
        sig->pinvoke = 0;
 
 #ifndef DISABLE_JIT
-       /* allocate local 0 (pointer) obj_vtable */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-       /* allocate local 1 (pointer) cached_vtable */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 
-       /*if (!obj)*/
-       mono_mb_emit_ldarg (mb, 0);
-       return_null_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
-
-       /*obj_vtable = obj->vtable;*/
-       mono_mb_emit_ldarg (mb, 0);
-       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
-       mono_mb_emit_byte (mb, CEE_LDIND_I);
-       mono_mb_emit_stloc (mb, 0);
-
-       /* cached_vtable = *cache*/
-       mono_mb_emit_ldarg (mb, 2);
-       mono_mb_emit_byte (mb, CEE_LDIND_I);
-       mono_mb_emit_stloc (mb, 1);
-
-       mono_mb_emit_ldloc (mb, 1);
-       mono_mb_emit_byte (mb, CEE_LDC_I4);
-       mono_mb_emit_i4 (mb, ~0x1);
-       mono_mb_emit_byte (mb, CEE_CONV_I);
-       mono_mb_emit_byte (mb, CEE_AND);
-       mono_mb_emit_ldloc (mb, 0);
-       /*if ((cached_vtable & ~0x1)== obj_vtable)*/
-       cache_miss_pos = mono_mb_emit_branch (mb, CEE_BNE_UN);
-
-       /*return (cached_vtable & 0x1) ? NULL : obj;*/
-       mono_mb_emit_ldloc (mb, 1);
-       mono_mb_emit_byte(mb, CEE_LDC_I4_1);
-       mono_mb_emit_byte (mb, CEE_CONV_U);
-       mono_mb_emit_byte (mb, CEE_AND);
-       negative_cache_hit_pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
-
-       /*obj*/
-       mono_mb_emit_ldarg (mb, 0);
-       cache_hit_pos = mono_mb_emit_branch (mb, CEE_BR);
+       generate_check_cache (obj_arg_position, class_arg_position, cache_arg_position, 
+               &return_null_pos, &negative_cache_hit_pos, &positive_cache_hit_pos, mb);
+       // Return the object gotten via the slow path.
+       mono_mb_emit_byte (mb, CEE_RET);
 
-       /*NULL*/
+       // return NULL;
        mono_mb_patch_branch (mb, negative_cache_hit_pos);
+       mono_mb_patch_branch (mb, return_null_pos);
        mono_mb_emit_byte (mb, CEE_LDNULL);
-
-       mono_mb_patch_branch (mb, cache_hit_pos);
        mono_mb_emit_byte (mb, CEE_RET);
 
-       mono_mb_patch_branch (mb, cache_miss_pos);
-       /*if (mono_object_isinst (obj, klass)) */
+       // return obj
+       mono_mb_patch_branch (mb, positive_cache_hit_pos);
        mono_mb_emit_ldarg (mb, 0);
-       mono_mb_emit_ldarg (mb, 1);
-       mono_mb_emit_icall (mb, mono_object_isinst);
-       not_an_instance_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
-
-       /**cache = obj_vtable;*/
-       mono_mb_emit_ldarg (mb, 2);
-       mono_mb_emit_ldloc (mb, 0);
-       mono_mb_emit_byte (mb, CEE_STIND_I);
-
-       /*return obj;*/
-       mono_mb_emit_ldarg (mb, 0);
-       mono_mb_emit_byte (mb, CEE_RET);
-
-       /*not an instance*/
-       mono_mb_patch_branch (mb, not_an_instance_pos);
-       /* *cache = (gpointer)(obj_vtable | 0x1);*/
-       mono_mb_emit_ldarg (mb, 2);
-       /*obj_vtable | 0x1*/
-       mono_mb_emit_ldloc (mb, 0);
-       mono_mb_emit_byte(mb, CEE_LDC_I4_1);
-       mono_mb_emit_byte (mb, CEE_CONV_U);
-       mono_mb_emit_byte (mb, CEE_OR);
-
-       /* *cache = ... */
-       mono_mb_emit_byte (mb, CEE_STIND_I);
-
-       /*return null*/
-       mono_mb_patch_branch (mb, return_null_pos);
-       mono_mb_emit_byte (mb, CEE_LDNULL);
        mono_mb_emit_byte (mb, CEE_RET);
 #endif