[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