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 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); 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 }