/// <summary> /// Transform open generic types to closed instantiation using context information. /// As an example, if B{T} inherits from A{T}, running it with B{C} as context and A{B.T} as type, ti will return A{C}. /// </summary> public static TypeReference Process(TypeReference context, TypeReference type) { if (type == null) return null; var genericInstanceTypeContext = context as GenericInstanceType; if (genericInstanceTypeContext == null) return type; if (genericInstanceTypeContext.ContainsGenericParameter()) return type; // Build dictionary that will map generic type to their real implementation type var resolvedType = context.Resolve(); var genericTypeMapping = new Dictionary<TypeReference, TypeReference>(); for (int i = 0; i < resolvedType.GenericParameters.Count; ++i) { var genericParameter = context.GetElementType().Resolve().GenericParameters[i]; genericTypeMapping.Add(genericParameter, genericInstanceTypeContext.GenericArguments[i]); } var visitor = new ResolveGenericsVisitor(genericTypeMapping); var result = visitor.VisitDynamic(type); // Make sure type is closed now if (result.ContainsGenericParameter()) throw new InvalidOperationException("Unsupported generic resolution."); return result; }
public static void InflateGenericType(TypeDefinition genericType, TypeDefinition inflatedType, params TypeReference[] genericTypes) { // Base type var genericMapping = new Dictionary <TypeReference, TypeReference>(); for (int i = 0; i < genericTypes.Length; ++i) { genericMapping.Add(genericType.GenericParameters[i], genericTypes[i]); } var resolveGenericsVisitor = new ResolveGenericsVisitor(genericMapping); inflatedType.BaseType = inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(genericType.BaseType)); // Some stuff are not handled yet if (genericType.HasNestedTypes) { throw new NotImplementedException(); } foreach (var field in genericType.Fields) { var clonedField = new FieldDefinition(field.Name, field.Attributes, inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(field.FieldType))); inflatedType.Fields.Add(clonedField); } foreach (var property in genericType.Properties) { if (property.HasParameters) { throw new NotImplementedException(); } var clonedProperty = new PropertyDefinition(property.Name, property.Attributes, inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(property.PropertyType))) { HasThis = property.HasThis, GetMethod = property.GetMethod != null?InflateMethod(inflatedType, property.GetMethod, resolveGenericsVisitor) : null, SetMethod = property.SetMethod != null?InflateMethod(inflatedType, property.GetMethod, resolveGenericsVisitor) : null, }; inflatedType.Properties.Add(clonedProperty); } // Clone methods foreach (var method in genericType.Methods) { var clonedMethod = InflateMethod(inflatedType, method, resolveGenericsVisitor); inflatedType.Methods.Add(clonedMethod); } }
public static IEnumerable <SerializableItem> GetSerializableItems(TypeReference type, bool serializeFields, ComplexTypeSerializerFlags?flagsOverride = null) { foreach (var serializableItemOriginal in GetSerializableItems(type.Resolve(), serializeFields, flagsOverride)) { var serializableItem = serializableItemOriginal; // Try to resolve open generic types with context to have closed types. if (serializableItem.Type.ContainsGenericParameter()) { serializableItem.Type = ResolveGenericsVisitor.Process(type, serializableItem.Type); } yield return(serializableItem); } }
/// <summary> /// Transform open generic types to closed instantiation using context information. /// As an example, if B{T} inherits from A{T}, running it with B{C} as context and A{B.T} as type, ti will return A{C}. /// </summary> public static TypeReference Process(TypeReference context, TypeReference type) { if (type == null) { return(null); } var genericInstanceTypeContext = context as GenericInstanceType; if (genericInstanceTypeContext == null) { return(type); } if (genericInstanceTypeContext.ContainsGenericParameter()) { return(type); } // Build dictionary that will map generic type to their real implementation type var resolvedType = context.Resolve(); var genericTypeMapping = new Dictionary <TypeReference, TypeReference>(); for (int i = 0; i < resolvedType.GenericParameters.Count; ++i) { var genericParameter = context.GetElementType().Resolve().GenericParameters[i]; genericTypeMapping.Add(genericParameter, genericInstanceTypeContext.GenericArguments[i]); } var visitor = new ResolveGenericsVisitor(genericTypeMapping); var result = visitor.VisitDynamic(type); // Make sure type is closed now if (result.ContainsGenericParameter()) { throw new InvalidOperationException("Unsupported generic resolution."); } return(result); }
/// <summary> /// Create the template output /// </summary> public virtual string TransformText() { this.Write("\r\n"); #line 7 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" var className = SerializerTypeName(type, true, true); var parentType = hasParentSerializer ? ResolveGenericsVisitor.Process(type, type.BaseType) : null; #line default #line hidden this.Write("\r\nnamespace SiliconStudio.DataSerializers\r\n{\r\n\t"); #line 14 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" if (type.HasGenericParameters) { #line default #line hidden this.Write("public "); #line 14 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" } #line default #line hidden this.Write("sealed class "); #line 14 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(className)); #line default #line hidden this.Write(" : "); #line 14 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(type.IsClass && !type.IsValueType && !type.IsAbstract && HasEmptyConstructor(type) ? "Class" : string.Empty)); #line default #line hidden this.Write("DataSerializer<"); #line 14 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(type.ConvertCSharp())); #line default #line hidden this.Write(">, IDataSerializerInitializer"); #line 14 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(GenerateGenericConstraints(type))); #line default #line hidden this.Write("\r\n\t{\r\n"); #line 16 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" if (hasParentSerializer) { #line default #line hidden this.Write("\t\tprivate DataSerializer<"); #line 17 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parentType.ConvertCSharp())); #line default #line hidden this.Write("> parentSerializer;\r\n"); #line 18 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" } var serializableItems = GetSerializableItems(type, true).ToArray(); #line default #line hidden #line 21 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" foreach (var serializableItem in serializableItems) { #line default #line hidden this.Write("\t\tprivate DataSerializer<"); #line 22 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(serializableItem.Type.ConvertCSharp())); #line default #line hidden this.Write("> "); #line 22 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(serializableItem.MemberInfo.Name)); #line default #line hidden this.Write("Serializer;\r\n"); #line 23 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" } #line default #line hidden this.Write("\r\n\t\tpublic void Initialize(SerializerSelector serializerSelector)\r\n\t\t{\r\n"); #line 27 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" if (hasParentSerializer) { #line default #line hidden this.Write("\t\t\t// Get parent serializer\r\n\t\t\tparentSerializer = serializerSelector.GetSerializ" + "er<"); #line 29 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parentType.ConvertCSharp())); #line default #line hidden this.Write(">();\r\n\t\t\tif (parentSerializer == null)\r\n\t\t\t\tthrow new InvalidOperationException(s" + "tring.Format(\"Could not find parent serializer for type {0}\", @\""); #line 31 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parentType.ConvertCSharp())); #line default #line hidden this.Write("\"));\r\n"); #line 32 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" } #line default #line hidden this.Write("\t\t\t// Cache member serializers\r\n"); #line 34 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" foreach (var serializableItem in serializableItems) { #line default #line hidden this.Write("\t\t\t"); #line 35 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(serializableItem.MemberInfo.Name)); #line default #line hidden this.Write("Serializer = MemberSerializer<"); #line 35 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(serializableItem.Type.ConvertCSharp())); #line default #line hidden this.Write(">.Create(serializerSelector);\r\n"); #line 36 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" } #line default #line hidden this.Write("\t\t}\r\n\r\n\t\tpublic override void Serialize(ref "); #line 39 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(type.ConvertCSharp())); #line default #line hidden this.Write(" obj, ArchiveMode mode, SerializationStream stream)\r\n\t\t{\r\n"); #line 41 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" if (hasParentSerializer) { #line default #line hidden this.Write("\t\t\t// Serialize parent (for now we don\'t copy reference back because it shouldn\'t" + " change)\r\n\t\t\t"); #line 43 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(parentType.ConvertCSharp())); #line default #line hidden this.Write(" parentObj = obj;\r\n\t\t\tparentSerializer.Serialize(ref parentObj, mode, stream);\r\n\t" + "\t\tobj = ("); #line 45 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(type.ConvertCSharp())); #line default #line hidden this.Write(")parentObj;\r\n\r\n"); #line 47 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" } foreach (var serializableItem in serializableItems) { var memberType = serializableItem.Type; var memberTypeName = serializableItem.Type.ConvertCSharp(); var memberName = serializableItem.MemberInfo.Name; var memberAssignBack = serializableItem.AssignBack; var memberVariableName = (serializableItem.MemberInfo is PropertyDefinition || !memberAssignBack) ? CreateMemberVariableName(serializableItem.MemberInfo) : null; var memberAccessName = memberVariableName != null ? memberVariableName : "obj." + memberName; if (serializableItem.HasFixedAttribute) { #line default #line hidden this.Write("\t\tthrow new NotImplementedException(\"FixedBuffer attribute is not supported.\");\r\n" + ""); #line 59 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" } else { if (memberVariableName != null) { #line default #line hidden this.Write(" "); #line 64 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(memberTypeName)); #line default #line hidden this.Write(" "); #line 64 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(memberVariableName)); #line default #line hidden this.Write(" = "); #line 64 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" if (memberAssignBack) { #line default #line hidden this.Write("mode == ArchiveMode.Serialize ? obj."); #line 64 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(memberName)); #line default #line hidden this.Write(" : default("); #line 64 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(memberTypeName)); #line default #line hidden this.Write(")"); #line 64 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" } else { #line default #line hidden this.Write("obj."); #line 64 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(memberName)); #line default #line hidden #line 64 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" } #line default #line hidden this.Write(";\r\n"); #line 65 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" } #line default #line hidden this.Write(" "); #line 66 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(serializableItem.MemberInfo.Name)); #line default #line hidden this.Write("Serializer.Serialize(ref "); #line 66 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(memberAccessName)); #line default #line hidden this.Write(", mode, stream);\r\n"); #line 67 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" if (memberVariableName != null && memberAssignBack) { #line default #line hidden this.Write(" obj."); #line 69 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(memberName)); #line default #line hidden this.Write(" = "); #line 69 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(memberVariableName)); #line default #line hidden this.Write(";\r\n"); #line 70 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" } } } #line default #line hidden this.Write("\t\t}\r\n\r\n\t\tinternal static void ForceGenericInstantiation()\r\n\t\t{\r\n"); #line 77 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" foreach (var memberSerializerType in EnumerateSerializerTypes(serializableItems.Select(x => x.Type))) { #line default #line hidden this.Write("\t\t\ttypeof("); #line 79 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" this.Write(this.ToStringHelper.ToStringWithCulture(memberSerializerType.ConvertCSharp())); #line default #line hidden this.Write(").ToString();\r\n"); #line 80 "C:\DEV\paradox\sources\common\core\SiliconStudio.AssemblyProcessor.Common\ComplexClassSerializerGenerator.tt" } #line default #line hidden this.Write("\t\t}\r\n\t}\r\n}"); return(this.GenerationEnvironment.ToString()); }
public void ProcessSerializers(CecilSerializerContext context) { var references = new HashSet <AssemblyDefinition>(); EnumerateReferences(references, context.Assembly); var coreAssembly = CecilExtensions.FindCorlibAssembly(context.Assembly); // Only process assemblies depending on Xenko.Engine if (!references.Any(x => x.Name.Name == "SiliconStudio.Xenko.Engine")) { // Make sure Xenko.Engine.Serializers can access everything internally var internalsVisibleToAttribute = coreAssembly.MainModule.GetTypeResolved(typeof(InternalsVisibleToAttribute).FullName); var serializationAssemblyName = "SiliconStudio.Xenko.Engine.Serializers"; // Add [InteralsVisibleTo] attribute var internalsVisibleToAttributeCtor = context.Assembly.MainModule.ImportReference(internalsVisibleToAttribute.GetConstructors().Single()); var internalsVisibleAttribute = new CustomAttribute(internalsVisibleToAttributeCtor) { ConstructorArguments = { new CustomAttributeArgument(context.Assembly.MainModule.ImportReference(context.Assembly.MainModule.TypeSystem.String), serializationAssemblyName) } }; context.Assembly.CustomAttributes.Add(internalsVisibleAttribute); return; } // Get or create method var updateEngineType = GetOrCreateUpdateType(context.Assembly, true); var mainPrepareMethod = new MethodDefinition("UpdateMain", MethodAttributes.HideBySig | MethodAttributes.Assembly | MethodAttributes.Static, context.Assembly.MainModule.TypeSystem.Void); updateEngineType.Methods.Add(mainPrepareMethod); // Get some useful Cecil objects from SiliconStudio.Core var siliconStudioCoreAssembly = context.Assembly.Name.Name == "SiliconStudio.Core" ? context.Assembly : context.Assembly.MainModule.AssemblyResolver.Resolve("SiliconStudio.Core"); var siliconStudioCoreModule = siliconStudioCoreAssembly.MainModule; var siliconStudioXenkoEngineAssembly = context.Assembly.Name.Name == "SiliconStudio.Xenko.Engine" ? context.Assembly : context.Assembly.MainModule.AssemblyResolver.Resolve("SiliconStudio.Xenko.Engine"); var siliconStudioXenkoEngineModule = siliconStudioXenkoEngineAssembly.MainModule; // Generate IL for SiliconStudio.Core if (context.Assembly.Name.Name == "SiliconStudio.Xenko.Engine") { ProcessXenkoEngineAssembly(context); } else { #if true || SILICONSTUDIO_XENKO_XAMARIN_CALLI_BUG // We still process UpdatableProperty<T> since we had to revert it back when writing back Xenko.Engine (otherwise it crashes at AOT on iOS) new UpdatablePropertyCodeGenerator(siliconStudioXenkoEngineAssembly).GenerateUpdatablePropertyCode(); #endif } animationDataType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Animations.AnimationData`1"); var updatableFieldGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdatableField`1"); updatableFieldGenericCtor = updatableFieldGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); updatablePropertyGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdatableProperty`1"); updatablePropertyGenericCtor = updatablePropertyGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var updatablePropertyObjectGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdatablePropertyObject`1"); updatablePropertyObjectGenericCtor = updatablePropertyObjectGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var updatableListUpdateResolverGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.ListUpdateResolver`1"); updatableListUpdateResolverGenericCtor = updatableListUpdateResolverGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var updatableArrayUpdateResolverGenericType = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.ArrayUpdateResolver`1"); updatableArrayUpdateResolverGenericCtor = updatableArrayUpdateResolverGenericType.Methods.First(x => x.IsConstructor && !x.IsStatic); var registerMemberMethod = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdateEngine").Methods.First(x => x.Name == "RegisterMember"); var pclVisitor = new PclFixupTypeVisitor(coreAssembly); pclVisitor.VisitMethod(registerMemberMethod); updateEngineRegisterMemberMethod = context.Assembly.MainModule.ImportReference(registerMemberMethod); var registerMemberResolverMethod = siliconStudioXenkoEngineModule.GetType("SiliconStudio.Xenko.Updater.UpdateEngine").Methods.First(x => x.Name == "RegisterMemberResolver"); pclVisitor.VisitMethod(registerMemberResolverMethod); updateEngineRegisterMemberResolverMethod = context.Assembly.MainModule.ImportReference(registerMemberResolverMethod); var typeType = coreAssembly.MainModule.GetTypeResolved(typeof(Type).FullName); getTypeFromHandleMethod = context.Assembly.MainModule.ImportReference(typeType.Methods.First(x => x.Name == "GetTypeFromHandle")); // Make sure it is called at module startup var moduleInitializerAttribute = siliconStudioCoreModule.GetType("SiliconStudio.Core.ModuleInitializerAttribute"); var ctorMethod = moduleInitializerAttribute.GetConstructors().Single(x => !x.IsStatic && !x.HasParameters); pclVisitor.VisitMethod(ctorMethod); mainPrepareMethod.CustomAttributes.Add(new CustomAttribute(context.Assembly.MainModule.ImportReference(ctorMethod))); // Emit serialization code for all the types we care about var processedTypes = new HashSet <TypeDefinition>(TypeReferenceEqualityComparer.Default); foreach (var serializableType in context.SerializableTypesProfiles.SelectMany(x => x.Value.SerializableTypes)) { // Special case: when processing Xenko.Engine assembly, we automatically add dependent assemblies types too if (!serializableType.Value.Local && siliconStudioXenkoEngineAssembly != context.Assembly) { continue; } var typeDefinition = serializableType.Key as TypeDefinition; if (typeDefinition == null) { continue; } // Ignore already processed types if (!processedTypes.Add(typeDefinition)) { continue; } try { ProcessType(context, typeDefinition, mainPrepareMethod); } catch (Exception e) { throw new InvalidOperationException(string.Format("Error when generating update engine code for {0}", typeDefinition), e); } } // Force generic instantiations var il = mainPrepareMethod.Body.GetILProcessor(); foreach (var serializableType in context.SerializableTypesProfiles.SelectMany(x => x.Value.SerializableTypes).ToArray()) { // Special case: when processing Xenko.Engine assembly, we automatically add dependent assemblies types too if (!serializableType.Value.Local && siliconStudioXenkoEngineAssembly != context.Assembly) { continue; } // Make sure AnimationData<T> is serializable //if (serializableType.Value.Mode == DataSerializerGenericMode.None) // context.GenerateSerializer(context.Assembly.MainModule.ImportReference(animationDataType).MakeGenericType(context.Assembly.MainModule.ImportReference(serializableType.Key))); // Try to find if original method definition was generated var typeDefinition = serializableType.Key.Resolve(); // If using List<T>, register this type in UpdateEngine var listInterfaceType = typeDefinition.Interfaces.OfType <GenericInstanceType>().FirstOrDefault(x => x.ElementType.FullName == typeof(IList <>).FullName); if (listInterfaceType != null) { //call Updater.UpdateEngine.RegisterMemberResolver(new Updater.ListUpdateResolver<T>()); var elementType = ResolveGenericsVisitor.Process(serializableType.Key, listInterfaceType.GenericArguments[0]); il.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(updatableListUpdateResolverGenericCtor).MakeGeneric(context.Assembly.MainModule.ImportReference(elementType).FixupValueType())); il.Emit(OpCodes.Call, updateEngineRegisterMemberResolverMethod); } // Same for arrays var arrayType = serializableType.Key as ArrayType; if (arrayType != null) { //call Updater.UpdateEngine.RegisterMemberResolver(new Updater.ArrayUpdateResolver<T>()); var elementType = ResolveGenericsVisitor.Process(serializableType.Key, arrayType.ElementType); il.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(updatableArrayUpdateResolverGenericCtor).MakeGeneric(context.Assembly.MainModule.ImportReference(elementType).FixupValueType())); il.Emit(OpCodes.Call, updateEngineRegisterMemberResolverMethod); } var genericInstanceType = serializableType.Key as GenericInstanceType; if (genericInstanceType != null) { var expectedUpdateMethodName = ComputeUpdateMethodName(typeDefinition); var updateMethod = GetOrCreateUpdateType(typeDefinition.Module.Assembly, false)?.Methods.FirstOrDefault(x => x.Name == expectedUpdateMethodName && x.HasGenericParameters && x.GenericParameters.Count == genericInstanceType.GenericParameters.Count); // If nothing was found in main assembly, also look in SiliconStudio.Xenko.Engine assembly, just in case (it might defines some shared/corlib types -- currently not the case) if (updateMethod == null) { updateMethod = GetOrCreateUpdateType(siliconStudioXenkoEngineAssembly, false)?.Methods.FirstOrDefault(x => x.Name == expectedUpdateMethodName && x.HasGenericParameters && x.GenericParameters.Count == genericInstanceType.GenericParameters.Count); } if (updateMethod != null) { // Emit call to update engine setup method with generic arguments of current type il.Emit(OpCodes.Call, context.Assembly.MainModule.ImportReference(updateMethod) .MakeGenericMethod(genericInstanceType.GenericArguments .Select(context.Assembly.MainModule.ImportReference) .Select(CecilExtensions.FixupValueType).ToArray())); } } } il.Emit(OpCodes.Ret); #if true || SILICONSTUDIO_XENKO_XAMARIN_CALLI_BUG // Due to Xamarin iOS AOT limitation, we can't keep this type around because it fails compilation if (context.Assembly.Name.Name == "SiliconStudio.Xenko.Engine") { NotImplementedBody(updatablePropertyGenericType.Methods.First(x => x.Name == "GetStructAndUnbox")); NotImplementedBody(updatablePropertyGenericType.Methods.First(x => x.Name == "GetBlittable")); NotImplementedBody(updatablePropertyGenericType.Methods.First(x => x.Name == "SetStruct")); NotImplementedBody(updatablePropertyGenericType.Methods.First(x => x.Name == "SetBlittable")); } #endif }
public void ProcessType(CecilSerializerContext context, TypeReference type, MethodDefinition updateMainMethod) { var typeDefinition = type.Resolve(); // No need to process enum if (typeDefinition.IsEnum) { return; } var updateCurrentMethod = updateMainMethod; ResolveGenericsVisitor replaceGenericsVisitor = null; if (typeDefinition.HasGenericParameters) { // Make a prepare method for just this object since it might need multiple instantiation updateCurrentMethod = new MethodDefinition(ComputeUpdateMethodName(typeDefinition), MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static, context.Assembly.MainModule.TypeSystem.Void); var genericsMapping = new Dictionary <TypeReference, TypeReference>(); foreach (var genericParameter in typeDefinition.GenericParameters) { var genericParameterCopy = new GenericParameter(genericParameter.Name, updateCurrentMethod) { Attributes = genericParameter.Attributes, }; foreach (var constraint in genericParameter.Constraints) { genericParameterCopy.Constraints.Add(context.Assembly.MainModule.ImportReference(constraint)); } updateCurrentMethod.GenericParameters.Add(genericParameterCopy); genericsMapping[genericParameter] = genericParameterCopy; } replaceGenericsVisitor = new ResolveGenericsVisitor(genericsMapping); updateMainMethod.DeclaringType.Methods.Add(updateCurrentMethod); } var il = updateCurrentMethod.Body.GetILProcessor(); var emptyObjectField = updateMainMethod.DeclaringType.Fields.FirstOrDefault(x => x.Name == "emptyObject"); // Note: forcing fields and properties to be processed in all cases foreach (var serializableItem in ComplexClassSerializerGenerator.GetSerializableItems(type, true, ComplexTypeSerializerFlags.SerializePublicFields | ComplexTypeSerializerFlags.SerializePublicProperties | ComplexTypeSerializerFlags.Updatable)) { var fieldReference = serializableItem.MemberInfo as FieldReference; if (fieldReference != null) { var field = fieldReference.Resolve(); // First time it is needed, let's create empty object: var emptyObject = new object(); if (emptyObjectField == null) { emptyObjectField = new FieldDefinition("emptyObject", FieldAttributes.Static | FieldAttributes.Private, context.Assembly.MainModule.TypeSystem.Object); // Create static ctor that will initialize this object var staticConstructor = new MethodDefinition(".cctor", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, context.Assembly.MainModule.TypeSystem.Void); var staticConstructorIL = staticConstructor.Body.GetILProcessor(); staticConstructorIL.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(emptyObjectField.FieldType.Resolve().GetConstructors().Single(x => !x.IsStatic && !x.HasParameters))); staticConstructorIL.Emit(OpCodes.Stsfld, emptyObjectField); staticConstructorIL.Emit(OpCodes.Ret); updateMainMethod.DeclaringType.Fields.Add(emptyObjectField); updateMainMethod.DeclaringType.Methods.Add(staticConstructor); } il.Emit(OpCodes.Ldtoken, type); il.Emit(OpCodes.Call, getTypeFromHandleMethod); il.Emit(OpCodes.Ldstr, field.Name); il.Emit(OpCodes.Ldsfld, emptyObjectField); il.Emit(OpCodes.Ldflda, context.Assembly.MainModule.ImportReference(fieldReference)); il.Emit(OpCodes.Conv_I); il.Emit(OpCodes.Ldsfld, emptyObjectField); il.Emit(OpCodes.Conv_I); il.Emit(OpCodes.Sub); il.Emit(OpCodes.Conv_I4); var fieldType = context.Assembly.MainModule.ImportReference(replaceGenericsVisitor != null ? replaceGenericsVisitor.VisitDynamic(field.FieldType) : field.FieldType).FixupValueType(); il.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(updatableFieldGenericCtor).MakeGeneric(fieldType)); il.Emit(OpCodes.Call, updateEngineRegisterMemberMethod); } var propertyReference = serializableItem.MemberInfo as PropertyReference; if (propertyReference != null) { var property = propertyReference.Resolve(); var propertyGetMethod = context.Assembly.MainModule.ImportReference(property.GetMethod).MakeGeneric(updateCurrentMethod.GenericParameters.ToArray()); il.Emit(OpCodes.Ldtoken, type); il.Emit(OpCodes.Call, getTypeFromHandleMethod); il.Emit(OpCodes.Ldstr, property.Name); il.Emit(OpCodes.Ldftn, propertyGetMethod); // Only get setter if it exists and it's public if (property.SetMethod != null && property.SetMethod.IsPublic) { var propertySetMethod = context.Assembly.MainModule.ImportReference(property.SetMethod).MakeGeneric(updateCurrentMethod.GenericParameters.ToArray()); il.Emit(OpCodes.Ldftn, propertySetMethod); } else { // 0 (native int) il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Conv_I); } var propertyType = context.Assembly.MainModule.ImportReference(replaceGenericsVisitor != null ? replaceGenericsVisitor.VisitDynamic(property.PropertyType) : property.PropertyType).FixupValueType(); var updatablePropertyInflatedCtor = GetOrCreateUpdatablePropertyCtor(context.Assembly, propertyType); il.Emit(OpCodes.Newobj, updatablePropertyInflatedCtor); il.Emit(OpCodes.Call, updateEngineRegisterMemberMethod); } } if (updateCurrentMethod != updateMainMethod) { // If we have a local method, close it il.Emit(OpCodes.Ret); // Also call it from main method if it was a closed generic instantiation if (type is GenericInstanceType) { il = updateMainMethod.Body.GetILProcessor(); il.Emit(OpCodes.Call, updateCurrentMethod.MakeGeneric(((GenericInstanceType)type).GenericArguments.Select(context.Assembly.MainModule.ImportReference).Select(CecilExtensions.FixupValueType).ToArray())); } } }
public void ProcessType(CecilSerializerContext context, TypeReference type, MethodDefinition updateMainMethod) { var typeDefinition = type.Resolve(); // No need to process enum if (typeDefinition.IsEnum) return; var updateCurrentMethod = updateMainMethod; ResolveGenericsVisitor replaceGenericsVisitor = null; if (typeDefinition.HasGenericParameters) { // Make a prepare method for just this object since it might need multiple instantiation updateCurrentMethod = new MethodDefinition(ComputeUpdateMethodName(typeDefinition), MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static, context.Assembly.MainModule.TypeSystem.Void); var genericsMapping = new Dictionary<TypeReference, TypeReference>(); foreach (var genericParameter in typeDefinition.GenericParameters) { var genericParameterCopy = new GenericParameter(genericParameter.Name, updateCurrentMethod) { Attributes = genericParameter.Attributes, }; foreach (var constraint in genericParameter.Constraints) genericParameterCopy.Constraints.Add(context.Assembly.MainModule.ImportReference(constraint)); updateCurrentMethod.GenericParameters.Add(genericParameterCopy); genericsMapping[genericParameter] = genericParameterCopy; } replaceGenericsVisitor = new ResolveGenericsVisitor(genericsMapping); updateMainMethod.DeclaringType.Methods.Add(updateCurrentMethod); } var il = updateCurrentMethod.Body.GetILProcessor(); var emptyObjectField = updateMainMethod.DeclaringType.Fields.FirstOrDefault(x => x.Name == "emptyObject"); // Note: forcing fields and properties to be processed in all cases foreach (var serializableItem in ComplexClassSerializerGenerator.GetSerializableItems(type, true, ComplexTypeSerializerFlags.SerializePublicFields | ComplexTypeSerializerFlags.SerializePublicProperties | ComplexTypeSerializerFlags.Updatable)) { var fieldReference = serializableItem.MemberInfo as FieldReference; if (fieldReference != null) { var field = fieldReference.Resolve(); // First time it is needed, let's create empty object: var emptyObject = new object(); if (emptyObjectField == null) { emptyObjectField = new FieldDefinition("emptyObject", FieldAttributes.Static | FieldAttributes.Private, context.Assembly.MainModule.TypeSystem.Object); // Create static ctor that will initialize this object var staticConstructor = new MethodDefinition(".cctor", MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, context.Assembly.MainModule.TypeSystem.Void); var staticConstructorIL = staticConstructor.Body.GetILProcessor(); staticConstructorIL.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(emptyObjectField.FieldType.Resolve().GetConstructors().Single(x => !x.IsStatic && !x.HasParameters))); staticConstructorIL.Emit(OpCodes.Stsfld, emptyObjectField); staticConstructorIL.Emit(OpCodes.Ret); updateMainMethod.DeclaringType.Fields.Add(emptyObjectField); updateMainMethod.DeclaringType.Methods.Add(staticConstructor); } il.Emit(OpCodes.Ldtoken, type); il.Emit(OpCodes.Call, getTypeFromHandleMethod); il.Emit(OpCodes.Ldstr, field.Name); il.Emit(OpCodes.Ldsfld, emptyObjectField); il.Emit(OpCodes.Ldflda, context.Assembly.MainModule.ImportReference(fieldReference)); il.Emit(OpCodes.Ldsfld, emptyObjectField); il.Emit(OpCodes.Conv_I); il.Emit(OpCodes.Sub); il.Emit(OpCodes.Conv_I4); var fieldType = context.Assembly.MainModule.ImportReference(replaceGenericsVisitor != null ? replaceGenericsVisitor.VisitDynamic(field.FieldType) : field.FieldType).FixupValueType(); il.Emit(OpCodes.Newobj, context.Assembly.MainModule.ImportReference(updatableFieldGenericCtor).MakeGeneric(fieldType)); il.Emit(OpCodes.Call, updateEngineRegisterMemberMethod); } var propertyReference = serializableItem.MemberInfo as PropertyReference; if (propertyReference != null) { var property = propertyReference.Resolve(); var propertyGetMethod = context.Assembly.MainModule.ImportReference(property.GetMethod).MakeGeneric(updateCurrentMethod.GenericParameters.ToArray()); il.Emit(OpCodes.Ldtoken, type); il.Emit(OpCodes.Call, getTypeFromHandleMethod); il.Emit(OpCodes.Ldstr, property.Name); il.Emit(OpCodes.Ldftn, propertyGetMethod); // Only get setter if it exists and it's public if (property.SetMethod != null && property.SetMethod.IsPublic) { var propertySetMethod = context.Assembly.MainModule.ImportReference(property.SetMethod).MakeGeneric(updateCurrentMethod.GenericParameters.ToArray()); il.Emit(OpCodes.Ldftn, propertySetMethod); } else { // 0 (native int) il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Conv_I); } var propertyType = context.Assembly.MainModule.ImportReference(replaceGenericsVisitor != null ? replaceGenericsVisitor.VisitDynamic(property.PropertyType) : property.PropertyType).FixupValueType(); var updatablePropertyInflatedCtor = GetOrCreateUpdatablePropertyCtor(context.Assembly, propertyType); il.Emit(OpCodes.Newobj, updatablePropertyInflatedCtor); il.Emit(OpCodes.Call, updateEngineRegisterMemberMethod); } } if (updateCurrentMethod != updateMainMethod) { // If we have a local method, close it il.Emit(OpCodes.Ret); // Also call it from main method if it was a closed generic instantiation if (type is GenericInstanceType) { il = updateMainMethod.Body.GetILProcessor(); il.Emit(OpCodes.Call, updateCurrentMethod.MakeGeneric(((GenericInstanceType)type).GenericArguments.Select(context.Assembly.MainModule.ImportReference).Select(CecilExtensions.FixupValueType).ToArray())); } } }
private static MethodDefinition InflateMethod(TypeDefinition inflatedType, MethodDefinition method, ResolveGenericsVisitor resolveGenericsVisitor) { var clonedMethod = new MethodDefinition(method.Name, method.Attributes, inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(method.ReturnType))); clonedMethod.Parameters.AddRange( method.Parameters.Select(x => new ParameterDefinition(x.Name, x.Attributes, inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(x.ParameterType))))); if (method.Body != null) { clonedMethod.Body.Variables.AddRange( method.Body.Variables.Select(x => new VariableDefinition(inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(x.VariableType))))); clonedMethod.Body.InitLocals = method.Body.InitLocals; var mappedInstructions = new Dictionary <Instruction, Instruction>(); foreach (var instruction in method.Body.Instructions) { // Create nop instructions to start with (if we use actual opcode, it would do an operand check) var mappedInstruction = Instruction.Create(OpCodes.Nop); mappedInstruction.OpCode = instruction.OpCode; mappedInstruction.Operand = instruction.Operand; mappedInstructions[instruction] = mappedInstruction; } foreach (var instruction in method.Body.Instructions) { // Fix operand var mappedInstruction = mappedInstructions[instruction]; if (mappedInstruction.Operand is Instruction) { mappedInstruction.Operand = mappedInstructions[(Instruction)instruction.Operand]; } else if (mappedInstruction.Operand is ParameterDefinition) { var parameterIndex = method.Parameters.IndexOf((ParameterDefinition)instruction.Operand); mappedInstruction.Operand = clonedMethod.Parameters[parameterIndex]; } else if (mappedInstruction.Operand is VariableDefinition) { var variableIndex = method.Body.Variables.IndexOf((VariableDefinition)instruction.Operand); mappedInstruction.Operand = clonedMethod.Body.Variables[variableIndex]; } else if (mappedInstruction.Operand is TypeReference) { var newTypeReference = resolveGenericsVisitor.VisitDynamic((TypeReference)mappedInstruction.Operand); newTypeReference = inflatedType.Module.ImportReference(newTypeReference); mappedInstruction.Operand = newTypeReference; } else if (mappedInstruction.Operand is FieldReference) { var fieldReference = (FieldReference)mappedInstruction.Operand; var newFieldReference = new FieldReference(fieldReference.Name, inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(fieldReference.FieldType)), inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(fieldReference.DeclaringType))); mappedInstruction.Operand = newFieldReference; } else if (mappedInstruction.Operand is MethodReference) { var methodReference = (MethodReference)mappedInstruction.Operand; var genericInstanceMethod = methodReference as GenericInstanceMethod; if (genericInstanceMethod != null) { methodReference = genericInstanceMethod.ElementMethod; } methodReference = methodReference.GetElementMethod(); var newMethodReference = new MethodReference(methodReference.Name, inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(methodReference.ReturnType)), inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(methodReference.DeclaringType))) { HasThis = methodReference.HasThis, ExplicitThis = methodReference.ExplicitThis, CallingConvention = methodReference.CallingConvention, }; foreach (var parameter in methodReference.Parameters) { newMethodReference.Parameters.Add(new ParameterDefinition(inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(parameter.ParameterType)))); } if (methodReference.HasGenericParameters) { CopyGenericParameters(methodReference, newMethodReference); } if (genericInstanceMethod != null) { newMethodReference = newMethodReference.MakeGenericMethod(genericInstanceMethod.GenericArguments.Select(x => inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(x))).ToArray()); } mappedInstruction.Operand = newMethodReference; } else if (mappedInstruction.Operand is Mono.Cecil.CallSite) { var callSite = (Mono.Cecil.CallSite)mappedInstruction.Operand; var newCallSite = new Mono.Cecil.CallSite(inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(callSite.ReturnType))) { HasThis = callSite.HasThis, ExplicitThis = callSite.ExplicitThis, CallingConvention = callSite.CallingConvention, }; foreach (var parameter in callSite.Parameters) { newCallSite.Parameters.Add(new ParameterDefinition(inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(parameter.ParameterType)))); } mappedInstruction.Operand = newCallSite; } else if (mappedInstruction.Operand is Instruction[]) { // Not used in UpdatableProperty<T> throw new NotImplementedException(); } } clonedMethod.Body.Instructions.AddRange(method.Body.Instructions.Select(x => mappedInstructions[x])); } return(clonedMethod); }