1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
4 namespace System.Runtime.Serialization
7 using System.Collections.Generic;
8 using System.Reflection;
9 using System.Reflection.Emit;
10 using System.Runtime.Serialization.Diagnostics.Application;
11 using System.Security;
12 using System.Security.Permissions;
16 public delegate object XmlFormatClassReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString[] memberNames, XmlDictionaryString[] memberNamespaces);
17 public delegate object XmlFormatCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract);
18 public delegate void XmlFormatGetOnlyCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract);
20 public sealed class XmlFormatReaderGenerator
22 internal delegate object XmlFormatClassReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString[] memberNames, XmlDictionaryString[] memberNamespaces);
23 internal delegate object XmlFormatCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract);
24 internal delegate void XmlFormatGetOnlyCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract);
26 internal sealed class XmlFormatReaderGenerator
29 [Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that was produced within an assert.")]
31 CriticalHelper helper;
33 [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.")]
35 public XmlFormatReaderGenerator()
37 helper = new CriticalHelper();
40 [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.")]
42 public XmlFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract)
46 if (TD.DCGenReaderStartIsEnabled())
48 TD.DCGenReaderStart("Class", classContract.UnderlyingType.FullName);
51 return helper.GenerateClassReader(classContract);
55 if (TD.DCGenReaderStopIsEnabled())
62 [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.")]
64 public XmlFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract)
68 if (TD.DCGenReaderStartIsEnabled())
70 TD.DCGenReaderStart("Collection", collectionContract.UnderlyingType.FullName);
73 return helper.GenerateCollectionReader(collectionContract);
77 if (TD.DCGenReaderStopIsEnabled())
84 [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.")]
86 public XmlFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract)
90 if (TD.DCGenReaderStartIsEnabled())
92 TD.DCGenReaderStart("GetOnlyCollection", collectionContract.UnderlyingType.FullName);
95 return helper.GenerateGetOnlyCollectionReader(collectionContract);
99 if (TD.DCGenReaderStopIsEnabled())
101 TD.DCGenReaderStop();
106 [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Handles all aspects of IL generation including initializing the DynamicMethod."
107 + " Changes to how IL generated could affect how data is deserialized and what gets access to data,"
108 + " therefore we mark it for review so that changes to generation logic are reviewed.")]
112 LocalBuilder objectLocal;
114 ArgBuilder xmlReaderArg;
115 ArgBuilder contextArg;
116 ArgBuilder memberNamesArg;
117 ArgBuilder memberNamespacesArg;
118 ArgBuilder collectionContractArg;
120 public XmlFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract)
122 ilg = new CodeGenerator();
123 bool memberAccessFlag = classContract.RequiresMemberAccessForRead(null);
126 ilg.BeginMethod("Read" + classContract.StableName.Name + "FromXml", Globals.TypeOfXmlFormatClassReaderDelegate, memberAccessFlag);
128 catch (SecurityException securityException)
130 if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
132 classContract.RequiresMemberAccessForRead(securityException);
141 DemandSerializationFormatterPermission(classContract);
142 DemandMemberAccessPermission(memberAccessFlag);
143 CreateObject(classContract);
144 ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal);
145 InvokeOnDeserializing(classContract);
146 LocalBuilder objectId = null;
147 if (HasFactoryMethod(classContract))
149 objectId = ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");
150 ilg.Call(contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
153 if (classContract.IsISerializable)
154 ReadISerializable(classContract);
156 ReadClass(classContract);
157 bool isFactoryType = InvokeFactoryMethod(classContract, objectId);
158 if (Globals.TypeOfIDeserializationCallback.IsAssignableFrom(classContract.UnderlyingType))
159 ilg.Call(objectLocal, XmlFormatGeneratorStatics.OnDeserializationMethod, null);
160 InvokeOnDeserialized(classContract);
161 if (objectId == null || !isFactoryType)
163 ilg.Load(objectLocal);
165 // Do a conversion back from DateTimeOffsetAdapter to DateTimeOffset after deserialization.
166 // DateTimeOffsetAdapter is used here for deserialization purposes to bypass the ISerializable implementation
167 // on DateTimeOffset; which does not work in partial trust.
169 if (classContract.UnderlyingType == Globals.TypeOfDateTimeOffsetAdapter)
171 ilg.ConvertValue(objectLocal.LocalType, Globals.TypeOfDateTimeOffsetAdapter);
172 ilg.Call(XmlFormatGeneratorStatics.GetDateTimeOffsetMethod);
173 ilg.ConvertValue(Globals.TypeOfDateTimeOffset, ilg.CurrentMethod.ReturnType);
177 ilg.ConvertValue(objectLocal.LocalType, ilg.CurrentMethod.ReturnType);
180 return (XmlFormatClassReaderDelegate)ilg.EndMethod();
183 public XmlFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract)
185 ilg = GenerateCollectionReaderHelper(collectionContract, false /*isGetOnlyCollection*/);
186 ReadCollection(collectionContract);
187 ilg.Load(objectLocal);
188 ilg.ConvertValue(objectLocal.LocalType, ilg.CurrentMethod.ReturnType);
189 return (XmlFormatCollectionReaderDelegate)ilg.EndMethod();
192 public XmlFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract)
194 ilg = GenerateCollectionReaderHelper(collectionContract, true /*isGetOnlyCollection*/);
195 ReadGetOnlyCollection(collectionContract);
196 return (XmlFormatGetOnlyCollectionReaderDelegate)ilg.EndMethod();
199 CodeGenerator GenerateCollectionReaderHelper(CollectionDataContract collectionContract, bool isGetOnlyCollection)
201 ilg = new CodeGenerator();
202 bool memberAccessFlag = collectionContract.RequiresMemberAccessForRead(null);
205 if (isGetOnlyCollection)
207 ilg.BeginMethod("Read" + collectionContract.StableName.Name + "FromXml" + "IsGetOnly", Globals.TypeOfXmlFormatGetOnlyCollectionReaderDelegate, memberAccessFlag);
211 ilg.BeginMethod("Read" + collectionContract.StableName.Name + "FromXml" + string.Empty, Globals.TypeOfXmlFormatCollectionReaderDelegate, memberAccessFlag);
214 catch (SecurityException securityException)
216 if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
218 collectionContract.RequiresMemberAccessForRead(securityException);
226 DemandMemberAccessPermission(memberAccessFlag);
227 collectionContractArg = ilg.GetArg(4);
233 xmlReaderArg = ilg.GetArg(0);
234 contextArg = ilg.GetArg(1);
235 memberNamesArg = ilg.GetArg(2);
236 memberNamespacesArg = ilg.GetArg(3);
239 void DemandMemberAccessPermission(bool memberAccessFlag)
241 if (memberAccessFlag)
243 ilg.Call(contextArg, XmlFormatGeneratorStatics.DemandMemberAccessPermissionMethod);
247 void DemandSerializationFormatterPermission(ClassDataContract classContract)
249 if (!classContract.HasDataContract && !classContract.IsNonAttributedType)
251 ilg.Call(contextArg, XmlFormatGeneratorStatics.DemandSerializationFormatterPermissionMethod);
255 void CreateObject(ClassDataContract classContract)
257 Type type = objectType = classContract.UnderlyingType;
258 if (type.IsValueType && !classContract.IsNonAttributedType)
259 type = Globals.TypeOfValueType;
261 objectLocal = ilg.DeclareLocal(type, "objectDeserialized");
263 if (classContract.UnderlyingType == Globals.TypeOfDBNull)
265 ilg.LoadMember(Globals.TypeOfDBNull.GetField("Value"));
266 ilg.Stloc(objectLocal);
268 else if (classContract.IsNonAttributedType)
270 if (type.IsValueType)
272 ilg.Ldloca(objectLocal);
277 ilg.New(classContract.GetNonAttributedTypeConstructor());
278 ilg.Stloc(objectLocal);
283 ilg.Call(null, XmlFormatGeneratorStatics.GetUninitializedObjectMethod, DataContract.GetIdForInitialization(classContract));
284 ilg.ConvertValue(Globals.TypeOfObject, type);
285 ilg.Stloc(objectLocal);
289 void InvokeOnDeserializing(ClassDataContract classContract)
291 if (classContract.BaseContract != null)
292 InvokeOnDeserializing(classContract.BaseContract);
293 if (classContract.OnDeserializing != null)
295 ilg.LoadAddress(objectLocal);
296 ilg.ConvertAddress(objectLocal.LocalType, objectType);
297 ilg.Load(contextArg);
298 ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod);
299 ilg.Call(classContract.OnDeserializing);
303 void InvokeOnDeserialized(ClassDataContract classContract)
305 if (classContract.BaseContract != null)
306 InvokeOnDeserialized(classContract.BaseContract);
307 if (classContract.OnDeserialized != null)
309 ilg.LoadAddress(objectLocal);
310 ilg.ConvertAddress(objectLocal.LocalType, objectType);
311 ilg.Load(contextArg);
312 ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod);
313 ilg.Call(classContract.OnDeserialized);
317 bool HasFactoryMethod(ClassDataContract classContract)
319 return Globals.TypeOfIObjectReference.IsAssignableFrom(classContract.UnderlyingType);
322 bool InvokeFactoryMethod(ClassDataContract classContract, LocalBuilder objectId)
324 if (HasFactoryMethod(classContract))
326 ilg.Load(contextArg);
327 ilg.LoadAddress(objectLocal);
328 ilg.ConvertAddress(objectLocal.LocalType, Globals.TypeOfIObjectReference);
330 ilg.Call(XmlFormatGeneratorStatics.GetRealObjectMethod);
331 ilg.ConvertValue(Globals.TypeOfObject, ilg.CurrentMethod.ReturnType);
337 void ReadClass(ClassDataContract classContract)
339 if (classContract.HasExtensionData)
341 LocalBuilder extensionDataLocal = ilg.DeclareLocal(Globals.TypeOfExtensionDataObject, "extensionData");
342 ilg.New(XmlFormatGeneratorStatics.ExtensionDataObjectCtor);
343 ilg.Store(extensionDataLocal);
344 ReadMembers(classContract, extensionDataLocal);
346 ClassDataContract currentContract = classContract;
347 while (currentContract != null)
349 MethodInfo extensionDataSetMethod = currentContract.ExtensionDataSetMethod;
350 if (extensionDataSetMethod != null)
351 ilg.Call(objectLocal, extensionDataSetMethod, extensionDataLocal);
352 currentContract = currentContract.BaseContract;
356 ReadMembers(classContract, null /*extensionDataLocal*/);
359 void ReadMembers(ClassDataContract classContract, LocalBuilder extensionDataLocal)
361 int memberCount = classContract.MemberNames.Length;
362 ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, memberCount);
364 LocalBuilder memberIndexLocal = ilg.DeclareLocal(Globals.TypeOfInt, "memberIndex", -1);
366 int firstRequiredMember;
367 bool[] requiredMembers = GetRequiredMembers(classContract, out firstRequiredMember);
368 bool hasRequiredMembers = (firstRequiredMember < memberCount);
369 LocalBuilder requiredIndexLocal = hasRequiredMembers ? ilg.DeclareLocal(Globals.TypeOfInt, "requiredIndex", firstRequiredMember) : null;
371 object forReadElements = ilg.For(null, null, null);
372 ilg.Call(null, XmlFormatGeneratorStatics.MoveToNextElementMethod, xmlReaderArg);
373 ilg.IfFalseBreak(forReadElements);
374 if (hasRequiredMembers)
375 ilg.Call(contextArg, XmlFormatGeneratorStatics.GetMemberIndexWithRequiredMembersMethod, xmlReaderArg, memberNamesArg, memberNamespacesArg, memberIndexLocal, requiredIndexLocal, extensionDataLocal);
377 ilg.Call(contextArg, XmlFormatGeneratorStatics.GetMemberIndexMethod, xmlReaderArg, memberNamesArg, memberNamespacesArg, memberIndexLocal, extensionDataLocal);
380 Label[] memberLabels = ilg.Switch(memberCount);
381 ReadMembers(classContract, requiredMembers, memberLabels, memberIndexLocal, requiredIndexLocal);
389 if (hasRequiredMembers)
391 ilg.If(requiredIndexLocal, Cmp.LessThan, memberCount);
392 ilg.Call(null, XmlFormatGeneratorStatics.ThrowRequiredMemberMissingExceptionMethod, xmlReaderArg, memberIndexLocal, requiredIndexLocal, memberNamesArg);
397 int ReadMembers(ClassDataContract classContract, bool[] requiredMembers, Label[] memberLabels, LocalBuilder memberIndexLocal, LocalBuilder requiredIndexLocal)
399 int memberCount = (classContract.BaseContract == null) ? 0 : ReadMembers(classContract.BaseContract, requiredMembers,
400 memberLabels, memberIndexLocal, requiredIndexLocal);
402 for (int i = 0; i < classContract.Members.Count; i++, memberCount++)
404 DataMember dataMember = classContract.Members[i];
405 Type memberType = dataMember.MemberType;
406 ilg.Case(memberLabels[memberCount], dataMember.Name);
407 if (dataMember.IsRequired)
409 int nextRequiredIndex = memberCount + 1;
410 for (; nextRequiredIndex < requiredMembers.Length; nextRequiredIndex++)
411 if (requiredMembers[nextRequiredIndex])
413 ilg.Set(requiredIndexLocal, nextRequiredIndex);
416 LocalBuilder value = null;
418 if (dataMember.IsGetOnlyCollection)
420 ilg.LoadAddress(objectLocal);
421 ilg.LoadMember(dataMember.MemberInfo);
422 value = ilg.DeclareLocal(memberType, dataMember.Name + "Value");
424 ilg.Call(contextArg, XmlFormatGeneratorStatics.StoreCollectionMemberInfoMethod, value);
425 ReadValue(memberType, dataMember.Name, classContract.StableName.Namespace);
429 value = ReadValue(memberType, dataMember.Name, classContract.StableName.Namespace);
430 ilg.LoadAddress(objectLocal);
431 ilg.ConvertAddress(objectLocal.LocalType, objectType);
433 ilg.StoreMember(dataMember.MemberInfo);
435 ilg.Set(memberIndexLocal, memberCount);
441 bool[] GetRequiredMembers(ClassDataContract contract, out int firstRequiredMember)
443 int memberCount = contract.MemberNames.Length;
444 bool[] requiredMembers = new bool[memberCount];
445 GetRequiredMembers(contract, requiredMembers);
446 for (firstRequiredMember = 0; firstRequiredMember < memberCount; firstRequiredMember++)
447 if (requiredMembers[firstRequiredMember])
449 return requiredMembers;
452 int GetRequiredMembers(ClassDataContract contract, bool[] requiredMembers)
454 int memberCount = (contract.BaseContract == null) ? 0 : GetRequiredMembers(contract.BaseContract, requiredMembers);
455 List<DataMember> members = contract.Members;
456 for (int i = 0; i < members.Count; i++, memberCount++)
458 requiredMembers[memberCount] = members[i].IsRequired;
463 void ReadISerializable(ClassDataContract classContract)
465 ConstructorInfo ctor = classContract.GetISerializableConstructor();
466 ilg.LoadAddress(objectLocal);
467 ilg.ConvertAddress(objectLocal.LocalType, objectType);
468 ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadSerializationInfoMethod, xmlReaderArg, classContract.UnderlyingType);
469 ilg.Load(contextArg);
470 ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod);
474 LocalBuilder ReadValue(Type type, string name, string ns)
476 LocalBuilder value = ilg.DeclareLocal(type, "valueRead");
477 LocalBuilder nullableValue = null;
479 while (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfNullable)
482 type = type.GetGenericArguments()[0];
485 PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type);
486 if ((primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) || nullables != 0 || type.IsValueType)
488 LocalBuilder objectId = ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");
489 ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadAttributesMethod, xmlReaderArg);
490 ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadIfNullOrRefMethod, xmlReaderArg, type, DataContract.IsTypeSerializable(type));
493 ilg.If(objectId, Cmp.EqualTo, Globals.NullObjectId);
496 ilg.LoadAddress(value);
497 ilg.InitObj(value.LocalType);
499 else if (type.IsValueType)
500 ThrowValidationException(SR.GetString(SR.ValueTypeCannotBeNull, DataContract.GetClrTypeFullName(type)));
509 // Compare against Globals.NewObjectId, which is set to string.Empty
510 ilg.ElseIfIsEmptyString(objectId);
511 ilg.Call(contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
513 if (type.IsValueType)
515 ilg.IfNotIsEmptyString(objectId);
516 ThrowValidationException(SR.GetString(SR.ValueTypeCannotHaveId, DataContract.GetClrTypeFullName(type)));
521 nullableValue = value;
522 value = ilg.DeclareLocal(type, "innerValueRead");
525 if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject)
527 ilg.Call(xmlReaderArg, primitiveContract.XmlFormatReaderMethod);
529 if (!type.IsValueType)
530 ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, value);
534 InternalDeserialize(value, type, name, ns);
538 if (type.IsValueType)
539 ThrowValidationException(SR.GetString(SR.ValueTypeCannotHaveRef, DataContract.GetClrTypeFullName(type)));
542 ilg.Call(contextArg, XmlFormatGeneratorStatics.GetExistingObjectMethod, objectId, type, name, ns);
543 ilg.ConvertValue(Globals.TypeOfObject, type);
548 if (nullableValue != null)
550 ilg.If(objectId, Cmp.NotEqualTo, Globals.NullObjectId);
551 WrapNullableObject(value, nullableValue, nullables);
553 value = nullableValue;
558 InternalDeserialize(value, type, name, ns);
564 void InternalDeserialize(LocalBuilder value, Type type, string name, string ns)
566 ilg.Load(contextArg);
567 ilg.Load(xmlReaderArg);
568 Type declaredType = type.IsPointer ? Globals.TypeOfReflectionPointer : type;
569 ilg.Load(DataContract.GetId(declaredType.TypeHandle));
570 ilg.Ldtoken(declaredType);
573 ilg.Call(XmlFormatGeneratorStatics.InternalDeserializeMethod);
576 ilg.Call(XmlFormatGeneratorStatics.UnboxPointer);
578 ilg.ConvertValue(Globals.TypeOfObject, type);
582 void WrapNullableObject(LocalBuilder innerValue, LocalBuilder outerValue, int nullables)
584 Type innerType = innerValue.LocalType, outerType = outerValue.LocalType;
585 ilg.LoadAddress(outerValue);
586 ilg.Load(innerValue);
587 for (int i = 1; i < nullables; i++)
589 Type type = Globals.TypeOfNullable.MakeGenericType(innerType);
590 ilg.New(type.GetConstructor(new Type[] { innerType }));
593 ilg.Call(outerType.GetConstructor(new Type[] { innerType }));
596 void ReadCollection(CollectionDataContract collectionContract)
598 Type type = collectionContract.UnderlyingType;
599 Type itemType = collectionContract.ItemType;
600 bool isArray = (collectionContract.Kind == CollectionKind.Array);
602 ConstructorInfo constructor = collectionContract.Constructor;
604 if (type.IsInterface)
606 switch (collectionContract.Kind)
608 case CollectionKind.GenericDictionary:
609 type = Globals.TypeOfDictionaryGeneric.MakeGenericType(itemType.GetGenericArguments());
610 constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
612 case CollectionKind.Dictionary:
613 type = Globals.TypeOfHashtable;
614 constructor = XmlFormatGeneratorStatics.HashtableCtor;
616 case CollectionKind.Collection:
617 case CollectionKind.GenericCollection:
618 case CollectionKind.Enumerable:
619 case CollectionKind.GenericEnumerable:
620 case CollectionKind.List:
621 case CollectionKind.GenericList:
622 type = itemType.MakeArrayType();
627 string itemName = collectionContract.ItemName;
628 string itemNs = collectionContract.StableName.Namespace;
630 objectLocal = ilg.DeclareLocal(type, "objectDeserialized");
633 if (type.IsValueType)
635 ilg.Ldloca(objectLocal);
640 ilg.New(constructor);
641 ilg.Stloc(objectLocal);
642 ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal);
646 LocalBuilder size = ilg.DeclareLocal(Globals.TypeOfInt, "arraySize");
647 ilg.Call(contextArg, XmlFormatGeneratorStatics.GetArraySizeMethod);
650 LocalBuilder objectId = ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");
651 ilg.Call(contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
654 bool canReadPrimitiveArray = false;
655 if (isArray && TryReadPrimitiveArray(type, itemType, size))
657 canReadPrimitiveArray = true;
661 ilg.If(size, Cmp.EqualTo, -1);
663 LocalBuilder growingCollection = null;
666 growingCollection = ilg.DeclareLocal(type, "growingCollection");
667 ilg.NewArray(itemType, 32);
668 ilg.Stloc(growingCollection);
670 LocalBuilder i = ilg.DeclareLocal(Globals.TypeOfInt, "i");
671 object forLoop = ilg.For(i, 0, Int32.MaxValue);
672 IsStartElement(memberNamesArg, memberNamespacesArg);
674 ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
675 LocalBuilder value = ReadCollectionItem(collectionContract, itemType, itemName, itemNs);
678 MethodInfo ensureArraySizeMethod = XmlFormatGeneratorStatics.EnsureArraySizeMethod.MakeGenericMethod(itemType);
679 ilg.Call(null, ensureArraySizeMethod, growingCollection, i);
680 ilg.Stloc(growingCollection);
681 ilg.StoreArrayElement(growingCollection, i, value);
684 StoreCollectionValue(objectLocal, value, collectionContract);
690 HandleUnexpectedItemInCollection(i);
697 MethodInfo trimArraySizeMethod = XmlFormatGeneratorStatics.TrimArraySizeMethod.MakeGenericMethod(itemType);
698 ilg.Call(null, trimArraySizeMethod, growingCollection, i);
699 ilg.Stloc(objectLocal);
700 ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, objectLocal);
704 ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, size);
707 ilg.NewArray(itemType, size);
708 ilg.Stloc(objectLocal);
709 ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal);
711 LocalBuilder j = ilg.DeclareLocal(Globals.TypeOfInt, "j");
713 IsStartElement(memberNamesArg, memberNamespacesArg);
715 LocalBuilder itemValue = ReadCollectionItem(collectionContract, itemType, itemName, itemNs);
717 ilg.StoreArrayElement(objectLocal, j, itemValue);
719 StoreCollectionValue(objectLocal, itemValue, collectionContract);
721 HandleUnexpectedItemInCollection(j);
724 ilg.Call(contextArg, XmlFormatGeneratorStatics.CheckEndOfArrayMethod, xmlReaderArg, size, memberNamesArg, memberNamespacesArg);
727 if (canReadPrimitiveArray)
730 ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, objectLocal);
735 void ReadGetOnlyCollection(CollectionDataContract collectionContract)
737 Type type = collectionContract.UnderlyingType;
738 Type itemType = collectionContract.ItemType;
739 bool isArray = (collectionContract.Kind == CollectionKind.Array);
740 string itemName = collectionContract.ItemName;
741 string itemNs = collectionContract.StableName.Namespace;
743 objectLocal = ilg.DeclareLocal(type, "objectDeserialized");
744 ilg.Load(contextArg);
745 ilg.LoadMember(XmlFormatGeneratorStatics.GetCollectionMemberMethod);
746 ilg.ConvertValue(Globals.TypeOfObject, type);
747 ilg.Stloc(objectLocal);
749 //check that items are actually going to be deserialized into the collection
750 IsStartElement(memberNamesArg, memberNamespacesArg);
752 ilg.If(objectLocal, Cmp.EqualTo, null);
753 ilg.Call(null, XmlFormatGeneratorStatics.ThrowNullValueReturnedForGetOnlyCollectionExceptionMethod, type);
756 LocalBuilder size = ilg.DeclareLocal(Globals.TypeOfInt, "arraySize");
759 ilg.Load(objectLocal);
760 ilg.Call(XmlFormatGeneratorStatics.GetArrayLengthMethod);
764 ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal);
766 LocalBuilder i = ilg.DeclareLocal(Globals.TypeOfInt, "i");
767 object forLoop = ilg.For(i, 0, Int32.MaxValue);
768 IsStartElement(memberNamesArg, memberNamespacesArg);
770 ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
771 LocalBuilder value = ReadCollectionItem(collectionContract, itemType, itemName, itemNs);
774 ilg.If(size, Cmp.EqualTo, i);
775 ilg.Call(null, XmlFormatGeneratorStatics.ThrowArrayExceededSizeExceptionMethod, size, type);
777 ilg.StoreArrayElement(objectLocal, i, value);
781 StoreCollectionValue(objectLocal, value, collectionContract);
787 HandleUnexpectedItemInCollection(i);
791 ilg.Call(contextArg, XmlFormatGeneratorStatics.CheckEndOfArrayMethod, xmlReaderArg, size, memberNamesArg, memberNamespacesArg);
797 bool TryReadPrimitiveArray(Type type, Type itemType, LocalBuilder size)
799 PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType);
800 if (primitiveContract == null)
803 string readArrayMethod = null;
804 switch (Type.GetTypeCode(itemType))
806 case TypeCode.Boolean:
807 readArrayMethod = "TryReadBooleanArray";
809 case TypeCode.DateTime:
810 readArrayMethod = "TryReadDateTimeArray";
812 case TypeCode.Decimal:
813 readArrayMethod = "TryReadDecimalArray";
816 readArrayMethod = "TryReadInt32Array";
819 readArrayMethod = "TryReadInt64Array";
821 case TypeCode.Single:
822 readArrayMethod = "TryReadSingleArray";
824 case TypeCode.Double:
825 readArrayMethod = "TryReadDoubleArray";
830 if (readArrayMethod != null)
832 ilg.Load(xmlReaderArg);
833 ilg.Load(contextArg);
834 ilg.Load(memberNamesArg);
835 ilg.Load(memberNamespacesArg);
837 ilg.Ldloca(objectLocal);
838 ilg.Call(typeof(XmlReaderDelegator).GetMethod(readArrayMethod, Globals.ScanAllMembers));
844 LocalBuilder ReadCollectionItem(CollectionDataContract collectionContract, Type itemType, string itemName, string itemNs)
846 if (collectionContract.Kind == CollectionKind.Dictionary || collectionContract.Kind == CollectionKind.GenericDictionary)
848 ilg.Call(contextArg, XmlFormatGeneratorStatics.ResetAttributesMethod);
849 LocalBuilder value = ilg.DeclareLocal(itemType, "valueRead");
850 ilg.Load(collectionContractArg);
851 ilg.Call(XmlFormatGeneratorStatics.GetItemContractMethod);
852 ilg.Load(xmlReaderArg);
853 ilg.Load(contextArg);
854 ilg.Call(XmlFormatGeneratorStatics.ReadXmlValueMethod);
855 ilg.ConvertValue(Globals.TypeOfObject, itemType);
861 return ReadValue(itemType, itemName, itemNs);
865 void StoreCollectionValue(LocalBuilder collection, LocalBuilder value, CollectionDataContract collectionContract)
867 if (collectionContract.Kind == CollectionKind.GenericDictionary || collectionContract.Kind == CollectionKind.Dictionary)
869 ClassDataContract keyValuePairContract = DataContract.GetDataContract(value.LocalType) as ClassDataContract;
870 if (keyValuePairContract == null)
872 Fx.Assert("Failed to create contract for KeyValuePair type");
874 DataMember keyMember = keyValuePairContract.Members[0];
875 DataMember valueMember = keyValuePairContract.Members[1];
876 LocalBuilder pairKey = ilg.DeclareLocal(keyMember.MemberType, keyMember.Name);
877 LocalBuilder pairValue = ilg.DeclareLocal(valueMember.MemberType, valueMember.Name);
878 ilg.LoadAddress(value);
879 ilg.LoadMember(keyMember.MemberInfo);
881 ilg.LoadAddress(value);
882 ilg.LoadMember(valueMember.MemberInfo);
883 ilg.Stloc(pairValue);
885 ilg.Call(collection, collectionContract.AddMethod, pairKey, pairValue);
886 if (collectionContract.AddMethod.ReturnType != Globals.TypeOfVoid)
891 ilg.Call(collection, collectionContract.AddMethod, value);
892 if (collectionContract.AddMethod.ReturnType != Globals.TypeOfVoid)
897 void HandleUnexpectedItemInCollection(LocalBuilder iterator)
901 ilg.Call(contextArg, XmlFormatGeneratorStatics.SkipUnknownElementMethod, xmlReaderArg);
904 ThrowUnexpectedStateException(XmlNodeType.Element);
908 void IsStartElement(ArgBuilder nameArg, ArgBuilder nsArg)
910 ilg.Call(xmlReaderArg, XmlFormatGeneratorStatics.IsStartElementMethod2, nameArg, nsArg);
913 void IsStartElement()
915 ilg.Call(xmlReaderArg, XmlFormatGeneratorStatics.IsStartElementMethod0);
920 ilg.Load(xmlReaderArg);
921 ilg.LoadMember(XmlFormatGeneratorStatics.NodeTypeProperty);
922 ilg.Load(XmlNodeType.EndElement);
926 void ThrowUnexpectedStateException(XmlNodeType expectedState)
928 ilg.Call(null, XmlFormatGeneratorStatics.CreateUnexpectedStateExceptionMethod, expectedState, xmlReaderArg);
932 void ThrowValidationException(string msg, params object[] values)
934 if (values != null && values.Length > 0)
935 ilg.CallStringFormat(msg, values);
938 ThrowValidationException();
941 void ThrowValidationException()
943 ilg.New(XmlFormatGeneratorStatics.SerializationExceptionCtor);
949 [Fx.Tag.SecurityNote(Critical = "Elevates by calling GetUninitializedObject which has a LinkDemand.",
950 Safe = "Marked as such so that it's callable from transparent generated IL. Takes id as parameter which "
951 + " is guaranteed to be in internal serialization cache.")]
952 [SecuritySafeCritical]
954 public static object UnsafeGetUninitializedObject(int id)
956 static internal object UnsafeGetUninitializedObject(int id)
959 return FormatterServices.GetUninitializedObject(DataContract.GetDataContractForInitialization(id).TypeForInitialization);