[Mono-dev] TypeForwardedFrom

Neale Ferguson NealeFerguson at verizon.net
Fri Apr 12 21:11:39 UTC 2013


If I add the following to WriteTypeSpec it works fine and the serialization
exactly matches that of .NET.

@@ -994,7 +1064,12 @@ namespace
System.Runtime.Serialization.Formatters.Binary
 
     case TypeTag.GenericType:
          writer.Write (type.FullName);
+#if NET_4_0
+         string asmName = GetForwardedAttribute.GetAssemblyName(type);
+         writer.Write ((int) GetAssemblyNameId (asmName));
+#else
          writer.Write ((int)GetAssemblyId (type.Assembly));
+#endif
          break;
 
However, trying to add the same to CodeGenerator.cs requires some help:

@@ -292,8 +297,14 @@ namespace
System.Runtime.Serialization.Formatters.Binary
     // EMIT writer.Write ((int)ow.GetAssemblyId (type.Assembly));
     gen.Emit (OpCodes.Ldarg_2);
     gen.Emit (OpCodes.Ldarg_1);
+#if NET_4_0
+    EmitLoadType (gen, type);
+    gen.EmitCall (OpCodes.Callvirt,
typeof(ObjectWriter).GetMethod("GetForwardedAttribute.GetAssemblyName"),
null);
+    gen.EmitCall (OpCodes.Callvirt,
typeof(ObjectWriter).GetMethod("GetAssemblyNameId"), null);
+#else
     EmitLoadTypeAssembly (gen, type, member);
     gen.EmitCall (OpCodes.Callvirt,
typeof(ObjectWriter).GetMethod("GetAssemblyId"), null);
+#endif
     gen.Emit (OpCodes.Conv_I4);
     EmitWrite (gen, typeof(int));
     break;

GetForwardedAttribute is defined at the top of ObjectWriter.cs

namespace System.Runtime.Serialization.Formatters.Binary
{
#if NET_4_0
        public class GetForwardedAttribute
        {
                public static string GetAssemblyName (Type self)
                {
                        var attrs = self.GetCustomAttributes(
                                        typeof (TypeForwardedFromAttribute),
false);
                        if (attrs.Length == 0)
                                return self.Assembly.FullName;
                        else
                                return ((TypeForwardedFromAttribute)attrs
[0]).AssemblyFullName;
                }
        }
#endif

So I'm not sure how to code the EmitCall for that method. At the moment I
get:

Error when trying to serialize with ObservableCollection: Argument cannot be
null.

Neale


On 4/12/13 1:37 PM, "Robert Jordan" <robertj at gmx.net> wrote:

> It looks like there are more places where we need the same
> Assembly -> Type "promotion".
> 
> GetAssemblyId should also take a Type argument where the
> forwarded assembly is determined, similar to the first change.
> 
> Robert
> 
> On 12.04.2013 16:46, Neale Ferguson wrote:
>> In both the MONO_REFLECTION_SERIALIZER=yes & no cases we die in
>> GetAssemblyId when called from WriteTypeSpec:
>> 
>> case TypeTag.GenericType:
>>        writer.Write (type.FullName);
>>        writer.Write ((int)GetAssemblyId (type.Assembly));
>>        break;
>> 
>> I put a couple of WriteLines in the ObjectWriter version before each call
>> and prior to the break and saw:
>> 
>> type.FullName = TypeTag.GenericType:
>> System.Collections.ObjectModel.ObservableCollection`1[[System.String,
>> mscorlib, Version=4.0.0.0, Culture=neutral,
>> PublicKeyToken=b77a5c561934e089]]
>> 
>> Type.Assembly = Getting assembly id System, Version=4.0.0.0,
>> Culture=neutral, PublicKeyToken=b77a5c561934e089
>> 
>> I'm not sure why commenting out the EmitLoadType/EmitCall to
>> WriteTypeAssembly and using the previous EmitLoadAssemblyType/EmitCall to
>> WriteAssembly causes things not to fail.
>> 
>> 
>> On 4/11/13 6:40 PM, "Robert Jordan" <robertj at gmx.net> wrote:
>> 
>>> This looks good. Maybe the error is somewhere else, so try to
>>> disable the IL serializer with
>>> 
>>> MONO_REFLECTION_SERIALIZER=yes mono yourtest.exe
>>> 
>>> If it still breaks, the bug is in WriteTypeAssembly.
>>> 
>>> Robert
>>> 
>>> On 11.04.2013 20:58, Neale Ferguson wrote:
>>>> This, in my naivety, looks like what I want. However, it's not and leads to
>>>> a NULL reference exception. What I am attempting to do is change the
>>>> generated code from calling ow.WriteAssembly(writer, memberType.Assembly)
>>>> to
>>>> ow.WriteTypeAssembly(writer, memberType)
>>>> 
>>>> ---
>>>> 
a/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/CodeGener>>>>
a
>>>> tor.cs
>>>> +++
>>>> 
b/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/CodeGener>>>>
a
>>>> tor.cs
>>>> @@ -115,8 +115,10 @@ namespace
>>>> System.Runtime.Serialization.Formatters.Binary
>>>> -                                       // EMIT ow.WriteAssembly (writer,
>>>> memberType.Assembly);
>>>> +                                       // EMIT ow.WriteTypeAssembly
>>>> (writer, memberType);
>>>> 
>>>>                                           gen.Emit (OpCodes.Ldarg_1);
>>>>                                           gen.Emit (OpCodes.Ldarg_2);
>>>> -                                       EmitLoadTypeAssembly (gen,
>>>> memberType, field.Name);
>>>> -                                       gen.EmitCall (OpCodes.Callvirt,
>>>> typeof(ObjectWriter).GetMethod("WriteAssembly"), null);
>>>> +//                                     EmitLoadTypeAssembly (gen,
>>>> memberType, field.Name);
>>>> +//                                     gen.EmitCall (OpCodes.Callvirt,
>>>> typeof(ObjectWriter).GetMethod("WriteAssembly"), null);
>>>> +                                       EmitLoadType (gen, memberType);
>>>> +                                       gen.EmitCall (OpCodes.Callvirt,
>>>> typeof(ObjectWriter).GetMethod("WriteTypeAssembly"), null);
>>>>                                           gen.Emit (OpCodes.Pop);
>>>>                                   }
>>>>                           }
>>>> @@ -318,6 +320,12 @@ namespace
>>>> System.Runtime.Serialization.Formatters.Binary
>>>>                           gen.EmitCall (OpCodes.Callvirt,
>>>> typeof(Type).GetProperty("Assembly").GetGetMethod(), null);
>>>>                   }
>>>> 
>>>> +               static void EmitLoadType (ILGenerator gen, Type type)
>>>> +               {
>>>> +                       gen.Emit (OpCodes.Ldtoken, type);
>>>> +                       gen.EmitCall (OpCodes.Call,
>>>> typeof(Type).GetMethod("GetTypeFromHandle"), null);
>>>> +               }
>>>> +
>>>>                   static void EmitWrite (ILGenerator gen, Type type)
>>>>                   {
>>>>                           gen.EmitCall (OpCodes.Callvirt,
>>>> typeof(BinaryWriter).GetMethod("Write", new Type[] { type }), null);
>>>> 
>>>> 
>>>> 
>>>> On 4/11/13 1:21 PM, "Robert Jordan" <robertj at gmx.net> wrote:
>>>> 
>>>>> Neale,
>>>>> 
>>>>> Rename & Modify WriteAssembly to take a Type argument:
>>>>> 
>>>>> public int WriteTypeAssembly (BinaryWriter writer, Type type)
>>>>> {
>>>>> return WriteAssemblyName (writer, type.GetAssemblyName ());
>>>>> }
>>>>> 
>>>>> (GetAssemblyName () is the extension from my first post)
>>>>> 
>>>>> Then change all call sites such that they pass the type directly
>>>>> instead type.Assembly to WriteTypeAssembly. Don't forget
>>>>> CodeGenerator.cs, where things get nastier due to IL code
>>>>> generation ;)
>>>>> 
>>>>> Robert
>>>>> 
>>>>> 
>>>>> On 11.04.2013 17:48, Neale Ferguson wrote:
>>>>>> Thanks again and apologies for peppering you with questions. In
>>>>>> WriteAssemblyName() it retrieves the AssemblyFullName so I'm not sure how
>>>>>> I
>>>>>> can get the forwarded name without the associated Type value.
>>>>>> 
>>>>>> Neale
>>>>>> 
>>>>>> On 4/11/13 10:04 AM, "Robert Jordan" <robertj at gmx.net> wrote:
>>>>>> 
>>>>>>> Neale,
>>>>>>> 
>>>>>>> The icall's declaration:
>>>>>>> 
>>>>>>> mono/metadata/icall-def.h:ICALL(ASSEM_23, "get_fullname",
>>>>>>> ves_icall_System_Reflection_Assembly_get_fullName)
>>>>>>> 
>>>>>>> The function:
>>>>>>> 
>>>>>>> mono/metadata/icall.c:ves_icall_System_Reflection_Assembly_get_fullName
>>>>>>> (MonoReflectionAssembly *assembly)
>>>>>>> 
>>>>>>> 
>>>>>>> I won't add this overhead to the Assembly class because it's a Type
>>>>>>> feature after all. You can handle this locally in ObjectWriter,
>>>>>>> as this is the only place where TypeForwardedFrom is used at all.
>>>>>> 
>>>>>> 
>>>>> 
>>>> 
>>>> 
>>> 
>> 
>> 
> 




More information about the Mono-devel-list mailing list