public static MethodDefinition OpenModuleConstructor(AssemblyDefinition assembly, out Instruction returnInstruction)
        {
            var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);

            if (mscorlibAssembly == null)
            {
                throw new InvalidOperationException("Missing mscorlib.dll from assembly");
            }

            // Get or create module static constructor
            var voidType          = assembly.MainModule.TypeSystem.Void;
            var moduleClass       = assembly.MainModule.Types.First(t => t.Name == "<Module>");
            var staticConstructor = moduleClass.GetStaticConstructor();

            if (staticConstructor == null)
            {
                staticConstructor = new MethodDefinition(".cctor",
                                                         MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                                                         voidType);
                staticConstructor.Body.GetILProcessor().Append(Instruction.Create(OpCodes.Ret));

                moduleClass.Methods.Add(staticConstructor);
            }
            returnInstruction = staticConstructor.Body.Instructions.Last();

            return(staticConstructor);
        }
Exemple #2
0
        public MethodReference GetOrCreateUpdatablePropertyCtor(AssemblyDefinition assembly, TypeReference propertyType)
        {
            if (propertyType.Resolve().IsValueType)
            {
#if true || SILICONSTUDIO_XENKO_XAMARIN_CALLI_BUG
                // Temporary code until Xamarin fixes bugs with generics calli
                // For now, we simply create one class per type T instead of using UpdatableProperty<T>
                // Later, we should only use UpdatableProperty<T> for everything
                var updateEngineType = GetOrCreateUpdateType(assembly, true);
                var updatablePropertyInflatedTypeName = $"UpdatableProperty_{propertyType.ConvertCSharp().Replace('.', '_').Replace("[]", "Array")}";
                var updatablePropertyInflatedType     = updateEngineType.NestedTypes.FirstOrDefault(x => x.Name == updatablePropertyInflatedTypeName);
                if (updatablePropertyInflatedType == null)
                {
                    var genericMapping = new Dictionary <TypeReference, TypeReference>();
                    genericMapping.Add(updatablePropertyGenericType.GenericParameters[0], propertyType);

                    updatablePropertyInflatedType = new TypeDefinition(string.Empty, updatablePropertyInflatedTypeName, TypeAttributes.NestedPrivate | TypeAttributes.AutoClass | TypeAttributes.AnsiClass);
                    updateEngineType.NestedTypes.Add(updatablePropertyInflatedType);

                    CecilExtensions.InflateGenericType(updatablePropertyGenericType, updatablePropertyInflatedType, propertyType);
                }

                var updatablePropertyCtor = updatablePropertyInflatedType.Methods.First(x => x.IsConstructor && !x.IsStatic);

                return(assembly.MainModule.ImportReference(updatablePropertyCtor));
#else
                return(assembly.MainModule.ImportReference(updatablePropertyGenericCtor).MakeGeneric(propertyType));
#endif
            }
            else
            {
                return(assembly.MainModule.ImportReference(updatablePropertyObjectGenericCtor).MakeGeneric(propertyType));
            }
        }
        private static ILProcessor NotImplementedBody(MethodDefinition method)
        {
            var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(method.Module.Assembly);
            var notImplementedExceptionType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(NotImplementedException).FullName);

            method.Body = new MethodBody(method);
            var il = method.Body.GetILProcessor();
            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Newobj, method.Module.ImportReference(notImplementedExceptionType.GetConstructors().Single(x => !x.IsStatic && !x.HasParameters)));
            il.Emit(OpCodes.Throw);

            return il;
        }
        public bool Process(AssemblyProcessorContext context)
        {
            var assembly         = context.Assembly;
            var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);

            if (mscorlibAssembly == null)
            {
                throw new InvalidOperationException("Missing mscorlib.dll from assembly");
            }


            // Resolve mscorlib types
            var assemblyFileVersionAttributeType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(AssemblyFileVersionAttribute).FullName);
            var assemblyMethodConstructor        = assembly.MainModule.ImportReference(assemblyFileVersionAttributeType.Methods.FirstOrDefault(method => method.IsConstructor && method.Parameters.Count == 1));
            var stringType = assembly.MainModule.TypeSystem.String;

            // TODO: Git Commit SHA
            var gitCommitShortId = "0";

            // Use epoch time to get a "unique" build number (different each time)
            var build = (long)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds;

            // Get current AssemblyVersion and clone it
            var version     = assembly.Name.Version;
            var fileVersion = string.Format("{0}.{1}.{2}.{3}", version.Major, version.Minor, build, gitCommitShortId);

            // Copy build/revision to the AssemblyFileVersion
            bool fileVersionUpdated = false;

            for (int i = 0; i < assembly.CustomAttributes.Count; i++)
            {
                var customAttribute = assembly.CustomAttributes[i];
                if (customAttribute.AttributeType.FullName == typeof(AssemblyFileVersionAttribute).FullName)
                {
                    customAttribute.ConstructorArguments.Clear();
                    customAttribute.ConstructorArguments.Add(new CustomAttributeArgument(stringType, fileVersion));
                    fileVersionUpdated = true;
                    break;
                }
            }

            if (!fileVersionUpdated)
            {
                var assemblyFileVersion = new CustomAttribute(assemblyMethodConstructor);
                assemblyFileVersion.ConstructorArguments.Add(new CustomAttributeArgument(stringType, fileVersion));
                assembly.CustomAttributes.Add(assemblyFileVersion);
            }

            return(true);
        }
            public UpdatableListCodeGenerator(AssemblyDefinition assembly) : base(assembly)
            {
                declaringType = assembly.MainModule.GetType("SiliconStudio.Xenko.Updater.UpdatableListAccessor`1");
                indexField    = assembly.MainModule.GetType("SiliconStudio.Xenko.Updater.UpdatableListAccessor").Fields.First(x => x.Name == "Index");

                // TODO: Update to new method to resolve collection assembly
                var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);
                var ilistType        = mscorlibAssembly.MainModule.GetTypeResolved(typeof(IList <>).FullName);

                var ilistItem = ilistType.Properties.First(x => x.Name == "Item");

                ilistGetItem = assembly.MainModule.ImportReference(ilistItem.GetMethod).MakeGeneric(declaringType.GenericParameters[0]);
                ilistSetItem = assembly.MainModule.ImportReference(ilistItem.SetMethod).MakeGeneric(declaringType.GenericParameters[0]);
            }
        private void EnsureInitialized(AssemblyProcessorContext context)
        {
            if (isInitialized)
            {
                return;
            }

            var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(context.Assembly);

            siliconStudioCoreAssembly = context.Assembly.Name.Name == "SiliconStudio.Core" ? context.Assembly :
                                        context.AssemblyResolver.Resolve(new AssemblyNameReference("SiliconStudio.Core", null));

            pooledClosureType = context.Assembly.MainModule.ImportReference(siliconStudioCoreAssembly.MainModule.GetType("SiliconStudio.Core.Threading.IPooledClosure"));

            // Func type and it's contructor
            var funcType = mscorlibAssembly.MainModule.GetTypeResolved("System.Func`1");

            funcConstructor = context.Assembly.MainModule.ImportReference(funcType.Methods.FirstOrDefault(x => x.Name == ".ctor"));

            // Pool type and it's constructor
            var poolTypeDefinition = siliconStudioCoreAssembly.MainModule.GetType("SiliconStudio.Core.Threading.ConcurrentPool`1");

            poolType          = context.Assembly.MainModule.ImportReference(poolTypeDefinition);
            poolConstructor   = context.Assembly.MainModule.ImportReference(poolTypeDefinition.Methods.FirstOrDefault(x => x.Name == ".ctor"));
            poolAcquireMethod = context.Assembly.MainModule.ImportReference(poolTypeDefinition.Methods.FirstOrDefault(x => x.Name == "Acquire"));
            poolReleaseMethod = context.Assembly.MainModule.ImportReference(poolTypeDefinition.Methods.FirstOrDefault(x => x.Name == "Release"));

            // Interlocked (either from mscorlib.dll or System.Threading.dll)
            var interlockedTypeDefinition = mscorlibAssembly.MainModule.GetTypeResolved("System.Threading.Interlocked");

            if (interlockedTypeDefinition == null)
            {
                var threadingAssembly = context.AssemblyResolver.Resolve(new AssemblyNameReference("System.Threading", null));
                interlockedTypeDefinition = threadingAssembly.MainModule.GetTypeResolved("System.Threading.Interlocked");
            }
            var interlockedType = context.Assembly.MainModule.ImportReference(interlockedTypeDefinition);

            // NOTE: We create method references manually, because ImportReference imports a different version of the runtime, causing
            interlockedIncrementMethod = new MethodReference("Increment", context.Assembly.MainModule.TypeSystem.Int32, interlockedType);
            interlockedIncrementMethod.Parameters.Add(new ParameterDefinition("", ParameterAttributes.None, context.Assembly.MainModule.TypeSystem.Int32.MakeByReferenceType()));
            //interlockedIncrementMethod = context.Assembly.MainModule.ImportReference(interlockedType.Methods.FirstOrDefault(x => x.Name == "Increment" && x.ReturnType.MetadataType == MetadataType.Int32));

            interlockedDecrementMethod = new MethodReference("Decrement", context.Assembly.MainModule.TypeSystem.Int32, interlockedType);
            interlockedDecrementMethod.Parameters.Add(new ParameterDefinition("", ParameterAttributes.None, context.Assembly.MainModule.TypeSystem.Int32.MakeByReferenceType()));
            //interlockedDecrementMethod = context.Assembly.MainModule.ImportReference(interlockedType.Methods.FirstOrDefault(x => x.Name == "Decrement" && x.ReturnType.MetadataType == MetadataType.Int32));

            isInitialized = true;
        }
        public bool Process(AssemblyProcessorContext context)
        {
            this.assembly    = context.Assembly;
            mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);

            if (mscorlibAssembly == null)
            {
                LogError("Missing mscorlib.dll from assembly {0}", assembly.FullName);
                throw new InvalidOperationException("Missing mscorlib.dll from assembly");
            }

            // Import void* and int32 from assembly using mscorlib specific version (2.0 or 4.0 depending on assembly)
            voidType        = mscorlibAssembly.MainModule.GetTypeResolved("System.Void");
            voidPointerType = new PointerType(assembly.MainModule.Import(voidType));
            intType         = assembly.MainModule.Import(mscorlibAssembly.MainModule.GetTypeResolved("System.Int32"));

            // Remove CompilationRelaxationsAttribute
            if (context.Platform == PlatformType.WindowsStore || context.Platform == PlatformType.WindowsPhone)
            {
                for (int i = 0; i < assembly.CustomAttributes.Count; i++)
                {
                    var customAttribute = assembly.CustomAttributes[i];
                    if (customAttribute.AttributeType.FullName == typeof(CompilationRelaxationsAttribute).FullName)
                    {
                        assembly.CustomAttributes.RemoveAt(i);
                        i--;
                    }
                }
            }

            Log("Patch for assembly [{0}]", assembly.FullName);
            foreach (var type in assembly.MainModule.Types)
            {
                PatchType(type);
            }

            // Remove All Interop classes
            foreach (var type in classToRemoveList)
            {
                assembly.MainModule.Types.Remove(type);
            }

            return(true);
        }
        private static void RegisterDefaultSerializationProfile(IAssemblyResolver assemblyResolver, AssemblyDefinition assembly, ComplexSerializerCodeGenerator generator, TextWriter log)
        {
            var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);

            if (mscorlibAssembly == null)
            {
                log.WriteLine("Missing mscorlib.dll from assembly {0}", assembly.FullName);
                throw new InvalidOperationException("Missing mscorlib.dll from assembly");
            }

            var coreSerializationAssembly = assemblyResolver.Resolve("SiliconStudio.Core");

            // Register serializer factories (determine which type requires which serializer)
            generator.SerializerFactories.Add(new CecilGenericSerializerFactory(typeof(IList <>), coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.ListInterfaceSerializer`1")));
            generator.SerializerFactories.Add(new CecilGenericSerializerFactory(typeof(List <>), coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.ListSerializer`1")));
            generator.SerializerFactories.Add(new CecilGenericSerializerFactory(typeof(KeyValuePair <,>), coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.KeyValuePairSerializer`2")));
            generator.SerializerFactories.Add(new CecilGenericSerializerFactory(typeof(IDictionary <,>), coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.DictionaryInterfaceSerializer`2")));
            generator.SerializerFactories.Add(new CecilGenericSerializerFactory(typeof(Dictionary <,>), coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.DictionarySerializer`2")));
            generator.SerializerFactories.Add(new CecilGenericSerializerFactory(typeof(Nullable <>), coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.NullableSerializer`1")));
            generator.SerializerFactories.Add(new CecilEnumSerializerFactory(coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.EnumSerializer`1")));
            generator.SerializerFactories.Add(new CecilArraySerializerFactory(coreSerializationAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.ArraySerializer`1")));

            // Iterate over tuple size
            for (int i = 1; i <= 4; ++i)
            {
                generator.SerializerDependencies.Add(new CecilSerializerDependency(
                                                         string.Format("System.Tuple`{0}", i),
                                                         coreSerializationAssembly.MainModule.GetTypeResolved(string.Format("SiliconStudio.Core.Serialization.Serializers.TupleSerializer`{0}", i))));

                generator.SerializerDependencies.Add(new CecilSerializerDependency(string.Format("SiliconStudio.Core.Serialization.Serializers.TupleSerializer`{0}", i)));
            }

            // Register serializer dependencies (determine which serializer serializes which sub-type)
            generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.ArraySerializer`1"));
            generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.KeyValuePairSerializer`2"));
            generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.ListSerializer`1"));
            generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.ListInterfaceSerializer`1"));
            generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.NullableSerializer`1"));
            generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.DictionarySerializer`2",
                                                                               mscorlibAssembly.MainModule.GetTypeResolved(typeof(KeyValuePair <,>).FullName)));
            generator.SerializerDependencies.Add(new CecilSerializerDependency("SiliconStudio.Core.Serialization.Serializers.DictionaryInterfaceSerializer`2",
                                                                               mscorlibAssembly.MainModule.GetTypeResolved(typeof(KeyValuePair <,>).FullName)));
        }
Exemple #9
0
        public static AssemblyDefinition GenerateSerializationAssembly(PlatformType platformType, BaseAssemblyResolver assemblyResolver, AssemblyDefinition assembly, string serializationAssemblyLocation, string signKeyFile = null)
        {
            // Create the serializer code generator
            var serializerGenerator = new ComplexSerializerCodeGenerator(assemblyResolver, assembly);

            // Register default serialization profile (to help AOT generic instantiation of serializers)
            RegisterDefaultSerializationProfile(assemblyResolver, assembly, serializerGenerator);

            // Generate serializer code
            var serializerGeneratedCode = serializerGenerator.TransformText();

            var compilerParameters = new CompilerParameters();

            compilerParameters.IncludeDebugInformation = false;
            compilerParameters.GenerateInMemory        = false;
            compilerParameters.CompilerOptions         = "/nostdlib";
            compilerParameters.TreatWarningsAsErrors   = false;
            compilerParameters.TempFiles.KeepFiles     = false;
            //Console.WriteLine("Generating {0}", serializationAssemblyLocation);

            // Add reference from source assembly
            // Use a hash set because it seems including twice mscorlib (2.0 and 4.0) seems to be a problem.
            var skipWindows = "Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null";

            // Sign the serialization assembly the same way the source was signed
            // TODO: Transmit over command line
            if (assembly.Name.HasPublicKey)
            {
                // TODO: If delay signed, we could actually extract the public key and apply it ourself maybe?
                if (signKeyFile == null)
                {
                    throw new InvalidOperationException("Generating serialization code for signed assembly, but no key was specified.");
                }

                var assemblyPath = Path.GetDirectoryName(assembly.MainModule.FullyQualifiedName);
                if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) == ModuleAttributes.StrongNameSigned)
                {
                    // Strongly signed
                    compilerParameters.CompilerOptions += string.Format(" /keyfile:\"{0}\"", signKeyFile);
                }
                else
                {
                    // Delay signed
                    compilerParameters.CompilerOptions += string.Format(" /delaysign+ /keyfile:\"{0}\"", signKeyFile);
                }
            }

            var assemblyLocations = new HashSet <string>();

            foreach (var referencedAssemblyName in assembly.MainModule.AssemblyReferences)
            {
                if (referencedAssemblyName.FullName != skipWindows)
                {
                    if (assemblyLocations.Add(referencedAssemblyName.Name))
                    {
                        //Console.WriteLine("Resolve Assembly for serialization [{0}]", referencedAssemblyName.FullName);
                        compilerParameters.ReferencedAssemblies.Add(assemblyResolver.Resolve(referencedAssemblyName).MainModule.FullyQualifiedName);
                    }
                }
            }

            // typeof(Dictionary<,>)
            // Special case for 4.5: Because Dictionary<,> is forwarded, we need to add a reference to the actual assembly
            var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);

            compilerParameters.ReferencedAssemblies.Add(mscorlibAssembly.MainModule.FullyQualifiedName);
            var collectionType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Dictionary <,>).FullName);

            compilerParameters.ReferencedAssemblies.Add(collectionType.Module.FullyQualifiedName);

            // Make sure System and System.Reflection are added
            // TODO: Maybe we should do that for .NETCore and PCL too? (instead of WinRT only)
            if (platformType == PlatformType.WindowsStore || platformType == PlatformType.WindowsPhone)
            {
                if (assemblyLocations.Add("System"))
                {
                    compilerParameters.ReferencedAssemblies.Add(assemblyResolver.Resolve("System").MainModule.FullyQualifiedName);
                }
                if (assemblyLocations.Add("System.Reflection"))
                {
                    compilerParameters.ReferencedAssemblies.Add(assemblyResolver.Resolve("System.Reflection").MainModule.FullyQualifiedName);
                }
            }

            compilerParameters.ReferencedAssemblies.Add(assembly.MainModule.FullyQualifiedName);
            assemblyLocations.Add(assembly.Name.Name);

            // In case Paradox.Framework.Serialization was not referenced, let's add it.
            if (!assemblyLocations.Contains("SiliconStudio.Core"))
            {
                compilerParameters.ReferencedAssemblies.Add(assemblyResolver.Resolve("SiliconStudio.Core").MainModule.FullyQualifiedName);
            }

            compilerParameters.OutputAssembly = serializationAssemblyLocation;
            var compilerResults = codeDomProvider.CompileAssemblyFromSource(compilerParameters, serializerGeneratedCode);

            if (compilerResults.Errors.HasErrors)
            {
                var errors = new StringBuilder();
                errors.AppendLine(string.Format("Serialization assembly compilation: {0} error(s)", compilerResults.Errors.Count));
                foreach (var error in compilerResults.Errors)
                {
                    errors.AppendLine(error.ToString());
                }
                throw new InvalidOperationException(errors.ToString());
            }

            // Run ILMerge
            var merge = new ILRepacking.ILRepack()
            {
                OutputFile     = assembly.MainModule.FullyQualifiedName,
                DebugInfo      = true,
                CopyAttributes = true,
                AllowMultipleAssemblyLevelAttributes = true,
                XmlDocumentation          = false,
                NoRepackRes               = true,
                PrimaryAssemblyDefinition = assembly,
                WriteToDisk               = false,
                //KeepFirstOfMultipleAssemblyLevelAttributes = true,
                //Log = true,
                //LogFile = "ilmerge.log",
            };

            merge.SetInputAssemblies(new string[] { serializationAssemblyLocation });

            // Force to use the correct framework
            //merge.SetTargetPlatform("v4", frameworkFolder);
            merge.SetSearchDirectories(assemblyResolver.GetSearchDirectories());
            merge.Merge();

            // Add assembly signing info
            if (assembly.Name.HasPublicKey)
            {
                merge.TargetAssemblyDefinition.Name.PublicKey      = assembly.Name.PublicKey;
                merge.TargetAssemblyDefinition.Name.PublicKeyToken = assembly.Name.PublicKeyToken;
                merge.TargetAssemblyDefinition.Name.Attributes    |= AssemblyAttributes.PublicKey;
                if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) == ModuleAttributes.StrongNameSigned)
                {
                    merge.TargetAssemblyMainModule.Attributes |= ModuleAttributes.StrongNameSigned;
                }
            }

            try
            {
                // Delete serializer dll
                File.Delete(serializationAssemblyLocation);

                var serializationAssemblyPdbFilePath = Path.ChangeExtension(serializationAssemblyLocation, "pdb");
                if (File.Exists(serializationAssemblyPdbFilePath))
                {
                    File.Delete(serializationAssemblyPdbFilePath);
                }
            }
            catch (IOException)
            {
                // Mute IOException
            }

            return(merge.TargetAssemblyDefinition);
        }
Exemple #10
0
        public bool Run(ref AssemblyDefinition assemblyDefinition, ref bool readWriteSymbols, out bool modified)
        {
            modified = false;

            try
            {
                var assemblyResolver = (CustomAssemblyResolver)assemblyDefinition.MainModule.AssemblyResolver;

                // Register self
                assemblyResolver.Register(assemblyDefinition);

                var processors = new List <IAssemblyDefinitionProcessor>();

                // We are no longer using it so we are deactivating it for now to avoid processing
                //if (AutoNotifyProperty)
                //{
                //    processors.Add(new NotifyPropertyProcessor());
                //}

                processors.Add(new AddReferenceProcessor(ReferencesToAdd));

                if (ParameterKey)
                {
                    processors.Add(new ParameterKeyProcessor());
                }

                if (NewAssemblyName != null)
                {
                    processors.Add(new RenameAssemblyProcessor(NewAssemblyName));
                }

                //processors.Add(new AsyncBridgeProcessor());

                // Always applies the interop processor
                processors.Add(new InteropProcessor());

                processors.Add(new AssemblyVersionProcessor());

                if (DocumentationFile != null)
                {
                    processors.Add(new GenerateUserDocumentationProcessor(DocumentationFile));
                }

                var roslynExtraCodeProcessor = new RoslynExtraCodeProcessor(SignKeyFile, References, MemoryReferences, log);

                if (SerializationAssembly)
                {
                    processors.Add(new SerializationProcessor(roslynExtraCodeProcessor.SourceCodes.Add));
                }

                processors.Add(roslynExtraCodeProcessor);

                if (ModuleInitializer)
                {
                    processors.Add(new ModuleInitializerProcessor());
                }

                processors.Add(new InitLocalsProcessor());
                processors.Add(new OpenSourceSignProcessor());

                // Check if pdb was actually read
                readWriteSymbols = assemblyDefinition.MainModule.HasDebugHeader;

                // Check if there is already a AssemblyProcessedAttribute (in which case we can skip processing, it has already been done).
                // Note that we should probably also match the command line as well so that we throw an error if processing is different (need to rebuild).
                if (assemblyDefinition.CustomAttributes.Any(x => x.AttributeType.FullName == "SiliconStudio.Core.AssemblyProcessedAttribute"))
                {
                    OnInfoAction($"Assembly [{assemblyDefinition.Name}] has already been processed, skip it.");
                    return(true);
                }

                // Register references so that our assembly resolver can use them
                foreach (var reference in References)
                {
                    assemblyResolver.RegisterReference(reference);
                }

                if (SerializationAssembly)
                {
                    // Resave a first version of assembly with [InteralsVisibleTo] for future serialization assembly.
                    // It will be used by serialization assembly compilation.
                    // It's recommended to do it in the original code to avoid this extra step.

                    var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assemblyDefinition);
                    if (mscorlibAssembly == null)
                    {
                        OnErrorAction("Missing reference to mscorlib.dll or System.Runtime.dll in assembly!");
                        return(false);
                    }

                    var  internalsVisibleToAttribute    = mscorlibAssembly.MainModule.GetTypeResolved(typeof(InternalsVisibleToAttribute).FullName);
                    var  serializationAssemblyName      = assemblyDefinition.Name.Name + ".Serializers";
                    bool internalsVisibleAlreadyApplied = false;

                    // Check if already applied
                    foreach (var customAttribute in assemblyDefinition.CustomAttributes.Where(x => x.AttributeType.FullName == internalsVisibleToAttribute.FullName))
                    {
                        var assemblyName = (string)customAttribute.ConstructorArguments[0].Value;

                        int publicKeyIndex;
                        if ((publicKeyIndex = assemblyName.IndexOf(", PublicKey=", StringComparison.InvariantCulture)) != -1 || (publicKeyIndex = assemblyName.IndexOf(",PublicKey=", StringComparison.InvariantCulture)) != -1)
                        {
                            assemblyName = assemblyName.Substring(0, publicKeyIndex);
                        }

                        if (assemblyName == serializationAssemblyName)
                        {
                            internalsVisibleAlreadyApplied = true;
                            break;
                        }
                    }

                    if (!internalsVisibleAlreadyApplied)
                    {
                        // Apply public key
                        if (assemblyDefinition.Name.HasPublicKey)
                        {
                            serializationAssemblyName += ", PublicKey=" + ByteArrayToString(assemblyDefinition.Name.PublicKey);
                        }

                        // Add [InteralsVisibleTo] attribute
                        var internalsVisibleToAttributeCtor = assemblyDefinition.MainModule.ImportReference(internalsVisibleToAttribute.GetConstructors().Single());
                        var internalsVisibleAttribute       = new CustomAttribute(internalsVisibleToAttributeCtor)
                        {
                            ConstructorArguments =
                            {
                                new CustomAttributeArgument(assemblyDefinition.MainModule.TypeSystem.String, serializationAssemblyName)
                            }
                        };
                        assemblyDefinition.CustomAttributes.Add(internalsVisibleAttribute);

                        var assemblyFilePath = assemblyDefinition.MainModule.FullyQualifiedName;
                        if (string.IsNullOrEmpty(assemblyFilePath))
                        {
                            assemblyFilePath = Path.ChangeExtension(Path.GetTempFileName(), ".dll");
                        }

                        // Save updated file
                        assemblyDefinition.Write(assemblyFilePath, new WriterParameters()
                        {
                            WriteSymbols = readWriteSymbols
                        });

                        // Reread file (otherwise it seems Mono Cecil is buggy and generate invalid PDB)
                        assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyFilePath, new ReaderParameters {
                            AssemblyResolver = assemblyResolver, ReadSymbols = readWriteSymbols
                        });

                        // Check if pdb was actually read
                        readWriteSymbols = assemblyDefinition.MainModule.HasDebugHeader;
                    }
                }

                var assemblyProcessorContext = new AssemblyProcessorContext(assemblyResolver, assemblyDefinition, Platform, log);

                foreach (var processor in processors)
                {
                    modified = processor.Process(assemblyProcessorContext) || modified;
                }

                // Assembly might have been recreated (i.e. il-repack), so let's use it from now on
                assemblyDefinition = assemblyProcessorContext.Assembly;

                if (modified)
                {
                    // In case assembly has been modified,
                    // add AssemblyProcessedAttribute to assembly so that it doesn't get processed again
                    var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assemblyDefinition);
                    if (mscorlibAssembly == null)
                    {
                        OnErrorAction("Missing reference to mscorlib.dll or System.Runtime.dll in assembly!");
                        return(false);
                    }

                    var attributeType    = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Attribute).FullName);
                    var attributeTypeRef = assemblyDefinition.MainModule.ImportReference(attributeType);
                    var attributeCtorRef = assemblyDefinition.MainModule.ImportReference(attributeType.GetConstructors().Single(x => x.Parameters.Count == 0));
                    var voidType         = assemblyDefinition.MainModule.TypeSystem.Void;

                    // Create custom attribute
                    var assemblyProcessedAttributeType = new TypeDefinition("SiliconStudio.Core", "AssemblyProcessedAttribute", TypeAttributes.BeforeFieldInit | TypeAttributes.AnsiClass | TypeAttributes.AutoClass | TypeAttributes.Public, attributeTypeRef);

                    // Add constructor (call parent constructor)
                    var assemblyProcessedAttributeConstructor = new MethodDefinition(".ctor", MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Public, voidType);
                    assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
                    assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Call, attributeCtorRef));
                    assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
                    assemblyProcessedAttributeType.Methods.Add(assemblyProcessedAttributeConstructor);

                    // Add AssemblyProcessedAttribute to assembly
                    assemblyDefinition.MainModule.Types.Add(assemblyProcessedAttributeType);
                    assemblyDefinition.CustomAttributes.Add(new CustomAttribute(assemblyProcessedAttributeConstructor));
                }
            }
            catch (Exception e)
            {
                OnErrorAction(null, e);
                return(false);
            }

            return(true);
        }
Exemple #11
0
        public bool Process(AssemblyProcessorContext context)
        {
            var assembly = context.Assembly;
            var fields   = new List <FieldDefinition>();

            var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);

            if (mscorlibAssembly == null)
            {
                throw new InvalidOperationException("Missing mscorlib.dll from assembly");
            }

            MethodDefinition parameterKeysMergeMethod        = null;
            TypeDefinition   assemblyEffectKeysAttributeType = null;
            var getTypeFromHandleMethod = new Lazy <MethodReference>(() =>
            {
                // Find Type.GetTypeFromHandle
                var typeType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Type).FullName);
                return(assembly.MainModule.Import(typeType.Methods.First(x => x.Name == "GetTypeFromHandle")));
            });

            var effectKeysStaticConstructors = new List <MethodReference>();

            foreach (var type in assembly.MainModule.GetTypes())
            {
                fields.Clear();

                foreach (var field in type.Fields.Where(x => x.IsStatic))
                {
                    var fieldBaseType = field.FieldType;
                    while (fieldBaseType != null)
                    {
                        if (fieldBaseType.FullName == "SiliconStudio.Paradox.Effects.ParameterKey")
                        {
                            break;
                        }

                        var resolvedFieldBaseType = fieldBaseType.Resolve();
                        if (resolvedFieldBaseType == null)
                        {
                            fieldBaseType = null;
                            break;
                        }

                        fieldBaseType = resolvedFieldBaseType.BaseType;
                    }

                    if (fieldBaseType == null)
                    {
                        continue;
                    }

                    fields.Add(field);
                }

                if (fields.Count == 0)
                {
                    continue;
                }

                // ParameterKey present means we should have a static cctor.
                var cctor = type.GetStaticConstructor();
                if (cctor == null)
                {
                    continue;
                }

                // Load necessary SiliconStudio.Paradox methods/attributes
                if (parameterKeysMergeMethod == null)
                {
                    AssemblyDefinition paradoxEngineAssembly;
                    try
                    {
                        paradoxEngineAssembly = assembly.Name.Name == "SiliconStudio.Paradox"
                            ? assembly
                            : context.AssemblyResolver.Resolve("SiliconStudio.Paradox");
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("Error, cannot find [SiliconStudio.Paradox] assembly for processing ParameterKeyProcessor");
                        // We can't generate an exception, so we are just returning. It means that SiliconStudio.Paradox has not been generated so far.
                        return(true);
                    }

                    var parameterKeysType = paradoxEngineAssembly.MainModule.GetTypes().First(x => x.Name == "ParameterKeys");
                    parameterKeysMergeMethod        = parameterKeysType.Methods.First(x => x.Name == "Merge");
                    assemblyEffectKeysAttributeType = paradoxEngineAssembly.MainModule.GetTypes().First(x => x.Name == "AssemblyEffectKeysAttribute");
                }

                var cctorIL           = cctor.Body.GetILProcessor();
                var cctorInstructions = cctor.Body.Instructions;

                var keyClassName = type.Name;
                if (keyClassName.EndsWith("Keys"))
                {
                    keyClassName = keyClassName.Substring(0, keyClassName.Length - 4);
                }

                keyClassName += '.';

                bool cctorModified = false;

                // Find field store instruction
                for (int i = 0; i < cctorInstructions.Count; ++i)
                {
                    var fieldInstruction = cctorInstructions[i];

                    if (fieldInstruction.OpCode == OpCodes.Stsfld &&
                        fields.Contains(fieldInstruction.Operand))
                    {
                        var activeField = (FieldReference)fieldInstruction.Operand;

                        var nextInstruction = cctorInstructions[i + 1];
                        cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Ldsfld, activeField));
                        cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Ldtoken, type));
                        cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Call, getTypeFromHandleMethod.Value));
                        cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Ldstr, keyClassName + activeField.Name));
                        cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Call, assembly.MainModule.Import(parameterKeysMergeMethod)));
                        cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Castclass, activeField.FieldType));
                        cctorIL.InsertBefore(nextInstruction, Instruction.Create(OpCodes.Stsfld, activeField));
                        i             = cctorInstructions.IndexOf(nextInstruction);
                        cctorModified = true;
                    }
                }

                if (cctorModified)
                {
                    effectKeysStaticConstructors.Add(cctor);
                }
            }

            if (effectKeysStaticConstructors.Count > 0)
            {
                // Add [AssemblyEffectKeysAttribute] to the assembly
                assembly.CustomAttributes.Add(new CustomAttribute(assembly.MainModule.Import(assemblyEffectKeysAttributeType.GetConstructors().First(x => !x.HasParameters))));

                // Get or create module static constructor
                var voidType          = assembly.MainModule.Import(mscorlibAssembly.MainModule.GetTypeResolved(typeof(void).FullName));
                var moduleClass       = assembly.MainModule.Types.First(t => t.Name == "<Module>");
                var staticConstructor = moduleClass.GetStaticConstructor();
                if (staticConstructor == null)
                {
                    staticConstructor = new MethodDefinition(".cctor",
                                                             MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                                                             voidType);
                    staticConstructor.Body.GetILProcessor().Append(Instruction.Create(OpCodes.Ret));

                    moduleClass.Methods.Add(staticConstructor);
                }

                var il = staticConstructor.Body.GetILProcessor();

                var returnInstruction    = staticConstructor.Body.Instructions.Last();
                var newReturnInstruction = Instruction.Create(returnInstruction.OpCode);
                newReturnInstruction.Operand = returnInstruction.Operand;

                returnInstruction.OpCode  = OpCodes.Nop;
                returnInstruction.Operand = null;

                var typeType            = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Type).FullName);
                var typeHandleProperty  = typeType.Properties.First(x => x.Name == "TypeHandle");
                var getTypeHandleMethod = assembly.MainModule.Import(typeHandleProperty.GetMethod);

                var runtimeHelpersType        = mscorlibAssembly.MainModule.GetTypeResolved(typeof(RuntimeHelpers).FullName);
                var runClassConstructorMethod = assembly.MainModule.Import(runtimeHelpersType.Methods.Single(x => x.IsPublic && x.Name == "RunClassConstructor" && x.Parameters.Count == 1 && x.Parameters[0].ParameterType.FullName == typeof(RuntimeTypeHandle).FullName));

                // Call every key class static constructor from the module static constructor so that they are properly constructed (because accessing through reflection might cause problems)
                staticConstructor.Body.SimplifyMacros();
                foreach (var effectKeysStaticConstructor in effectKeysStaticConstructors)
                {
                    il.Append(Instruction.Create(OpCodes.Ldtoken, effectKeysStaticConstructor.DeclaringType));
                    il.Append(Instruction.Create(OpCodes.Call, getTypeFromHandleMethod.Value));
                    il.Append(Instruction.Create(OpCodes.Callvirt, getTypeHandleMethod));
                    il.Append(Instruction.Create(OpCodes.Call, runClassConstructorMethod));
                }
                il.Append(newReturnInstruction);
                staticConstructor.Body.OptimizeMacros();
            }

            return(true);
        }
Exemple #12
0
        public bool Run(ref AssemblyDefinition assemblyDefinition, ref bool readWriteSymbols, out bool modified)
        {
            modified = false;

            try
            {
                var assemblyResolver = (CustomAssemblyResolver)assemblyDefinition.MainModule.AssemblyResolver;

                var processors = new List <IAssemblyDefinitionProcessor>();

                // We are no longer using it so we are deactivating it for now to avoid processing
                //if (AutoNotifyProperty)
                //{
                //    processors.Add(new NotifyPropertyProcessor());
                //}

                if (ParameterKey)
                {
                    processors.Add(new ParameterKeyProcessor());
                }

                if (NewAssemblyName != null)
                {
                    processors.Add(new RenameAssemblyProcessor(NewAssemblyName));
                }

                //processors.Add(new AsyncBridgeProcessor());

                // Always applies the interop processor
                processors.Add(new InteropProcessor());

                processors.Add(new AssemblyVersionProcessor());

                if (SerializationAssembly)
                {
                    processors.Add(new SerializationProcessor(SignKeyFile, SerializationProjectReferences));
                }

                if (GenerateUserDocumentation)
                {
                    processors.Add(new GenerateUserDocumentationProcessor(assemblyDefinition.MainModule.FullyQualifiedName));
                }

                if (ModuleInitializer)
                {
                    processors.Add(new ModuleInitializerProcessor());
                }

                processors.Add(new OpenSourceSignProcessor());

                // Check if pdb was actually read
                readWriteSymbols = assemblyDefinition.MainModule.HasDebugHeader;

                // Check if there is already a AssemblyProcessedAttribute (in which case we can skip processing, it has already been done).
                // Note that we should probably also match the command line as well so that we throw an error if processing is different (need to rebuild).
                if (assemblyDefinition.CustomAttributes.Any(x => x.AttributeType.FullName == "SiliconStudio.Core.AssemblyProcessedAttribute"))
                {
                    OnInfoAction("Assembly has already been processed, skip it.");
                    return(true);
                }

                var targetFrameworkAttribute = assemblyDefinition.CustomAttributes
                                               .FirstOrDefault(x => x.AttributeType.FullName == typeof(TargetFrameworkAttribute).FullName);
                var targetFramework = targetFrameworkAttribute != null ? (string)targetFrameworkAttribute.ConstructorArguments[0].Value : null;

                // Special handling for MonoAndroid
                // Default frameworkFolder
                var frameworkFolder = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\");

                switch (Platform)
                {
                case PlatformType.Android:
                {
                    if (string.IsNullOrEmpty(TargetFramework))
                    {
                        throw new InvalidOperationException("Expecting option target framework for Android");
                    }

                    var monoAndroidPath = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Reference Assemblies\Microsoft\Framework\MonoAndroid");
                    frameworkFolder = Path.Combine(monoAndroidPath, "v1.0");
                    var additionalFrameworkFolder = Path.Combine(monoAndroidPath, TargetFramework);
                    assemblyResolver.AddSearchDirectory(additionalFrameworkFolder);
                    assemblyResolver.AddSearchDirectory(frameworkFolder);
                    break;
                }

                case PlatformType.iOS:
                {
                    if (string.IsNullOrEmpty(TargetFramework))
                    {
                        throw new InvalidOperationException("Expecting option target framework for iOS");
                    }

                    var monoAndroidPath = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Reference Assemblies\Microsoft\Framework\MonoTouch");
                    frameworkFolder = Path.Combine(monoAndroidPath, "v1.0");
                    var additionalFrameworkFolder = Path.Combine(monoAndroidPath, TargetFramework);
                    assemblyResolver.AddSearchDirectory(additionalFrameworkFolder);
                    assemblyResolver.AddSearchDirectory(frameworkFolder);

                    break;
                }

                case PlatformType.WindowsStore:
                {
                    if (string.IsNullOrEmpty(TargetFramework))
                    {
                        throw new InvalidOperationException("Expecting option target framework for WindowsStore");
                    }

                    frameworkFolder = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Reference Assemblies\Microsoft\Framework\.NETCore", TargetFramework);
                    assemblyResolver.AddSearchDirectory(frameworkFolder);

                    // Add path to look for WinRT assemblies (Windows.winmd)
                    var windowsAssemblyPath = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Windows Kits\8.1\References\CommonConfiguration\Neutral\", "Windows.winmd");
                    var windowsAssembly     = AssemblyDefinition.ReadAssembly(windowsAssemblyPath, new ReaderParameters {
                            AssemblyResolver = assemblyResolver, ReadSymbols = false
                        });
                    assemblyResolver.Register(windowsAssembly);

                    break;
                }

                case PlatformType.WindowsPhone:
                {
                    if (string.IsNullOrEmpty(TargetFramework))
                    {
                        throw new InvalidOperationException("Expecting option target framework for WindowsPhone");
                    }

                    // Note: v8.1 is hardcoded because we currently receive v4.5.x as TargetFramework (different from TargetPlatformVersion)
                    frameworkFolder = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Reference Assemblies\Microsoft\Framework\WindowsPhoneApp", "v8.1");
                    assemblyResolver.AddSearchDirectory(frameworkFolder);

                    // Add path to look for WinRT assemblies (Windows.winmd)
                    var windowsAssemblyPath = Path.Combine(CecilExtensions.ProgramFilesx86(), @"Windows Phone Kits\8.1\References\CommonConfiguration\Neutral\", "Windows.winmd");
                    var windowsAssembly     = AssemblyDefinition.ReadAssembly(windowsAssemblyPath, new ReaderParameters {
                            AssemblyResolver = assemblyResolver, ReadSymbols = false
                        });
                    assemblyResolver.Register(windowsAssembly);

                    break;
                }
                }

                if (SerializationAssembly)
                {
                    // Resave a first version of assembly with [InteralsVisibleTo] for future serialization assembly.
                    // It will be used by serialization assembly compilation.
                    // It's recommended to do it in the original code to avoid this extra step.

                    var  mscorlibAssembly               = CecilExtensions.FindCorlibAssembly(assemblyDefinition);
                    var  stringType                     = mscorlibAssembly.MainModule.GetTypeResolved(typeof(string).FullName);
                    var  internalsVisibleToAttribute    = mscorlibAssembly.MainModule.GetTypeResolved(typeof(InternalsVisibleToAttribute).FullName);
                    var  serializationAssemblyName      = assemblyDefinition.Name.Name + ".Serializers";
                    bool internalsVisibleAlreadyApplied = false;

                    // Check if already applied
                    foreach (var customAttribute in assemblyDefinition.CustomAttributes.Where(x => x.AttributeType.FullName == internalsVisibleToAttribute.FullName))
                    {
                        var assemblyName = (string)customAttribute.ConstructorArguments[0].Value;

                        int publicKeyIndex;
                        if ((publicKeyIndex = assemblyName.IndexOf(", PublicKey=", StringComparison.InvariantCulture)) != -1 || (publicKeyIndex = assemblyName.IndexOf(",PublicKey=", StringComparison.InvariantCulture)) != -1)
                        {
                            assemblyName = assemblyName.Substring(0, publicKeyIndex);
                        }

                        if (assemblyName == serializationAssemblyName)
                        {
                            internalsVisibleAlreadyApplied = true;
                            break;
                        }
                    }

                    if (!internalsVisibleAlreadyApplied)
                    {
                        // Apply public key
                        if (assemblyDefinition.Name.HasPublicKey)
                        {
                            serializationAssemblyName += ", PublicKey=" + ByteArrayToString(assemblyDefinition.Name.PublicKey);
                        }

                        // Add [InteralsVisibleTo] attribute
                        var internalsVisibleToAttributeCtor = assemblyDefinition.MainModule.Import(internalsVisibleToAttribute.GetConstructors().Single());
                        var internalsVisibleAttribute       = new CustomAttribute(internalsVisibleToAttributeCtor)
                        {
                            ConstructorArguments =
                            {
                                new CustomAttributeArgument(assemblyDefinition.MainModule.Import(stringType), serializationAssemblyName)
                            }
                        };
                        assemblyDefinition.CustomAttributes.Add(internalsVisibleAttribute);

                        var assemblyFilePath = assemblyDefinition.MainModule.FullyQualifiedName;
                        if (string.IsNullOrEmpty(assemblyFilePath))
                        {
                            assemblyFilePath = Path.ChangeExtension(Path.GetTempFileName(), ".dll");
                        }

                        // Save updated file
                        assemblyDefinition.Write(assemblyFilePath, new WriterParameters()
                        {
                            WriteSymbols = readWriteSymbols
                        });

                        // Reread file (otherwise it seems Mono Cecil is buggy and generate invalid PDB)
                        assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyFilePath, new ReaderParameters {
                            AssemblyResolver = assemblyResolver, ReadSymbols = readWriteSymbols
                        });

                        // Check if pdb was actually read
                        readWriteSymbols = assemblyDefinition.MainModule.HasDebugHeader;
                    }
                }

                var assemblyProcessorContext = new AssemblyProcessorContext(assemblyResolver, assemblyDefinition, Platform);

                foreach (var processor in processors)
                {
                    modified = processor.Process(assemblyProcessorContext) || modified;
                }

                // Assembly might have been recreated (i.e. il-repack), so let's use it from now on
                assemblyDefinition = assemblyProcessorContext.Assembly;

                if (modified)
                {
                    // In case assembly has been modified,
                    // add AssemblyProcessedAttribute to assembly so that it doesn't get processed again
                    var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assemblyDefinition);
                    if (mscorlibAssembly == null)
                    {
                        OnErrorAction("Missing mscorlib.dll from assembly");
                        return(false);
                    }

                    var attributeType    = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Attribute).FullName);
                    var attributeTypeRef = assemblyDefinition.MainModule.Import(attributeType);
                    var attributeCtorRef = assemblyDefinition.MainModule.Import(attributeType.GetConstructors().Single(x => x.Parameters.Count == 0));
                    var voidType         = assemblyDefinition.MainModule.Import(mscorlibAssembly.MainModule.GetTypeResolved("System.Void"));

                    // Create custom attribute
                    var assemblyProcessedAttributeType = new TypeDefinition("SiliconStudio.Core", "AssemblyProcessedAttribute", TypeAttributes.BeforeFieldInit | TypeAttributes.AnsiClass | TypeAttributes.AutoClass | TypeAttributes.Public, attributeTypeRef);

                    // Add constructor (call parent constructor)
                    var assemblyProcessedAttributeConstructor = new MethodDefinition(".ctor", MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Public, voidType);
                    assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
                    assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Call, attributeCtorRef));
                    assemblyProcessedAttributeConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
                    assemblyProcessedAttributeType.Methods.Add(assemblyProcessedAttributeConstructor);

                    // Add AssemblyProcessedAttribute to assembly
                    assemblyDefinition.MainModule.Types.Add(assemblyProcessedAttributeType);
                    assemblyDefinition.CustomAttributes.Add(new CustomAttribute(assemblyProcessedAttributeConstructor));
                }
            }
            catch (Exception e)
            {
                OnErrorAction(e.Message, e);
                return(false);
            }

            return(true);
        }
Exemple #13
0
        public static AssemblyDefinition GenerateRoslynAssembly(CustomAssemblyResolver assemblyResolver, AssemblyDefinition assembly, string serializationAssemblyLocation, string signKeyFile, List <string> references, List <AssemblyDefinition> memoryReferences, TextWriter log, IEnumerable <SourceCode> sourceCodes)
        {
            var sourceFolder = Path.GetDirectoryName(serializationAssemblyLocation);
            var syntaxTrees  = sourceCodes.Select(x =>
            {
                // It has a name, let's save it as a file
                string sourcePath = null;
                if (x.Name != null)
                {
                    sourcePath = Path.Combine(sourceFolder, $"{x.Name}.cs");
                    File.WriteAllText(sourcePath, x.Code);
                }

                var result = CSharpSyntaxTree.ParseText(x.Code, null, sourcePath, Encoding.UTF8);

                return(result);
            }).ToArray();

            var compilerOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true, assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default);

            // Sign the serialization assembly the same way the source was signed
            // TODO: Transmit over command line
            if (assembly.Name.HasPublicKey)
            {
                // TODO: If delay signed, we could actually extract the public key and apply it ourself maybe?
                if (signKeyFile == null)
                {
                    throw new InvalidOperationException("Generating serialization code for signed assembly, but no key was specified.");
                }

                compilerOptions = compilerOptions.WithCryptoKeyFile(signKeyFile).WithStrongNameProvider(new DesktopStrongNameProvider());
                if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) != ModuleAttributes.StrongNameSigned)
                {
                    // Delay signed
                    compilerOptions = compilerOptions.WithDelaySign(true);
                }
            }

            // Add references (files and in-memory PE data)
            var metadataReferences = new List <MetadataReference>();

            foreach (var reference in assemblyResolver.References)
            {
                metadataReferences.Add(MetadataReference.CreateFromFile(reference));
            }

            foreach (var reference in memoryReferences)
            {
                metadataReferences.Add(CreateMetadataReference(assemblyResolver, reference));
            }

            // typeof(Dictionary<,>)
            // Special case for 4.5: Because Dictionary<,> is forwarded, we need to add a reference to the actual assembly
            var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);

            metadataReferences.Add(CreateMetadataReference(assemblyResolver, mscorlibAssembly));
            var collectionAssembly = CecilExtensions.FindCollectionsAssembly(assembly);

            metadataReferences.Add(CreateMetadataReference(assemblyResolver, collectionAssembly));
            metadataReferences.Add(CreateMetadataReference(assemblyResolver, assembly));

            // In case SiliconStudio.Core was not referenced, let's add it.
            if (assembly.Name.Name != "SiliconStudio.Core" && !references.Any(x => string.Compare(Path.GetFileNameWithoutExtension(x), "SiliconStudio.Core", StringComparison.OrdinalIgnoreCase) == 0))
            {
                metadataReferences.Add(CreateMetadataReference(assemblyResolver, assemblyResolver.Resolve("SiliconStudio.Core")));
            }

            // Create roslyn compilation object
            var assemblyName = assembly.Name.Name + ".Serializers";
            var compilation  = CSharpCompilation.Create(assemblyName, syntaxTrees, metadataReferences, compilerOptions);

            // Do the actual compilation, and check errors
            using (var peStream = new FileStream(serializationAssemblyLocation, FileMode.Create, FileAccess.Write))
                using (var pdbStream = new FileStream(Path.ChangeExtension(serializationAssemblyLocation, ".pdb"), FileMode.Create, FileAccess.Write))
                {
                    var compilationResult = compilation.Emit(peStream, pdbStream);

                    if (!compilationResult.Success)
                    {
                        var errors = new StringBuilder();
                        errors.AppendLine(string.Format("Serialization assembly compilation: {0} error(s)", compilationResult.Diagnostics.Count(x => x.Severity >= DiagnosticSeverity.Error)));
                        foreach (var error in compilationResult.Diagnostics)
                        {
                            if (error.Severity >= DiagnosticSeverity.Warning)
                            {
                                errors.AppendLine(error.ToString());
                            }
                        }
                        throw new InvalidOperationException(errors.ToString());
                    }
                }

            var repackOptions = new ILRepacking.RepackOptions(new string[0])
            {
                OutputFile     = assembly.MainModule.FullyQualifiedName,
                DebugInfo      = true,
                CopyAttributes = true,
                AllowMultipleAssemblyLevelAttributes = true,
                XmlDocumentation  = false,
                NoRepackRes       = true,
                InputAssemblies   = new[] { serializationAssemblyLocation },
                SearchDirectories = assemblyResolver.GetSearchDirectories(),
                SearchAssemblies  = references,
            };

            // Run ILMerge
            var merge = new ILRepacking.ILRepack(repackOptions)
            {
                PrimaryAssemblyDefinition = assembly,
                MemoryOnly = true,
                //KeepFirstOfMultipleAssemblyLevelAttributes = true,
                //Log = true,
                //LogFile = "ilmerge.log",
            };

            try
            {
                var consoleWriter = Console.Out;
                Console.SetOut(TextWriter.Null);

                try
                {
                    merge.Repack();
                }
                finally
                {
                    Console.SetOut(consoleWriter);
                }
            }
            catch (Exception)
            {
                log.WriteLine($"Error while ILRepacking {assembly.Name.Name}");
                throw;
            }

            // Copy name
            merge.TargetAssemblyDefinition.Name.Name    = assembly.Name.Name;
            merge.TargetAssemblyDefinition.Name.Version = assembly.Name.Version;

            // Copy assembly characterics. This is necessary especially when targeting a windows app
            merge.TargetAssemblyMainModule.Characteristics = assembly.MainModule.Characteristics;

            // Add assembly signing info
            if (assembly.Name.HasPublicKey)
            {
                merge.TargetAssemblyDefinition.Name.PublicKey      = assembly.Name.PublicKey;
                merge.TargetAssemblyDefinition.Name.PublicKeyToken = assembly.Name.PublicKeyToken;
                merge.TargetAssemblyDefinition.Name.Attributes    |= AssemblyAttributes.PublicKey;
                if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) == ModuleAttributes.StrongNameSigned)
                {
                    merge.TargetAssemblyMainModule.Attributes |= ModuleAttributes.StrongNameSigned;
                }
            }

            try
            {
                // Delete serializer dll
                File.Delete(serializationAssemblyLocation);

                var serializationAssemblyPdbFilePath = Path.ChangeExtension(serializationAssemblyLocation, "pdb");
                if (File.Exists(serializationAssemblyPdbFilePath))
                {
                    File.Delete(serializationAssemblyPdbFilePath);
                }
            }
            catch (IOException)
            {
                // Mute IOException
            }

            return(merge.TargetAssemblyDefinition);
        }
Exemple #14
0
        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
        }
Exemple #15
0
        public static AssemblyDefinition GenerateSerializationAssembly(PlatformType platformType, BaseAssemblyResolver assemblyResolver, AssemblyDefinition assembly, string serializationAssemblyLocation, string signKeyFile, List <string> references, List <AssemblyDefinition> memoryReferences, ILogger log)
        {
            // Create the serializer code generator
            var serializerGenerator = new ComplexSerializerCodeGenerator(assemblyResolver, assembly, log);

            // Register default serialization profile (to help AOT generic instantiation of serializers)
            RegisterDefaultSerializationProfile(assemblyResolver, assembly, serializerGenerator);

            // Generate serializer code
            var serializerGeneratedCode = serializerGenerator.TransformText();

            var syntaxTree = CSharpSyntaxTree.ParseText(serializerGeneratedCode);

            // Add reference from source assembly
            // Use a hash set because it seems including twice mscorlib (2.0 and 4.0) seems to be a problem.
            var skipWindows = "Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null";

            var compilerOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true, assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default);

            // Sign the serialization assembly the same way the source was signed
            // TODO: Transmit over command line
            if (assembly.Name.HasPublicKey)
            {
                // TODO: If delay signed, we could actually extract the public key and apply it ourself maybe?
                if (signKeyFile == null)
                {
                    throw new InvalidOperationException("Generating serialization code for signed assembly, but no key was specified.");
                }

                compilerOptions = compilerOptions.WithCryptoKeyFile(signKeyFile).WithStrongNameProvider(new DesktopStrongNameProvider());
                if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) != ModuleAttributes.StrongNameSigned)
                {
                    // Delay signed
                    compilerOptions = compilerOptions.WithDelaySign(true);
                }
            }

            // Add references (files and in-memory PE data)
            var metadataReferences = new List <MetadataReference>();

            foreach (var reference in references)
            {
                metadataReferences.Add(MetadataReference.CreateFromFile(reference));
            }

            foreach (var reference in memoryReferences)
            {
                metadataReferences.Add(CreateMetadataReference(assemblyResolver, reference));
            }

            // typeof(Dictionary<,>)
            // Special case for 4.5: Because Dictionary<,> is forwarded, we need to add a reference to the actual assembly
            var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);

            metadataReferences.Add(CreateMetadataReference(assemblyResolver, mscorlibAssembly));
            var collectionType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Dictionary <,>).FullName);

            metadataReferences.Add(CreateMetadataReference(assemblyResolver, collectionType.Module.Assembly));
            metadataReferences.Add(CreateMetadataReference(assemblyResolver, assembly));

            // In case SiliconStudio.Core was not referenced, let's add it.
            if (assembly.Name.Name != "SiliconStudio.Core" && !references.Any(x => string.Compare(Path.GetFileNameWithoutExtension(x), "SiliconStudio.Core", StringComparison.OrdinalIgnoreCase) == 0))
            {
                metadataReferences.Add(CreateMetadataReference(assemblyResolver, assemblyResolver.Resolve("SiliconStudio.Core")));
            }

            // Create roslyn compilation object
            var assemblyName = assembly.Name.Name + ".Serializers";
            var compilation  = CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, metadataReferences, compilerOptions);

            // Do the actual compilation, and check errors
            using (var peStream = new FileStream(serializationAssemblyLocation, FileMode.Create, FileAccess.Write))
            {
                var compilationResult = compilation.Emit(peStream);

                if (!compilationResult.Success)
                {
                    var errors = new StringBuilder();
                    errors.AppendLine(string.Format("Serialization assembly compilation: {0} error(s)", compilationResult.Diagnostics.Count(x => x.Severity >= DiagnosticSeverity.Error)));
                    foreach (var error in compilationResult.Diagnostics)
                    {
                        if (error.Severity >= DiagnosticSeverity.Warning)
                        {
                            errors.AppendLine(error.ToString());
                        }
                    }
                    throw new InvalidOperationException(errors.ToString());
                }
            }

            var repackOptions = new ILRepacking.RepackOptions(new string[0])
            {
                OutputFile     = assembly.MainModule.FullyQualifiedName,
                DebugInfo      = true,
                CopyAttributes = true,
                AllowMultipleAssemblyLevelAttributes = true,
                XmlDocumentation  = false,
                NoRepackRes       = true,
                InputAssemblies   = new[] { serializationAssemblyLocation },
                SearchDirectories = assemblyResolver.GetSearchDirectories(),
                SearchAssemblies  = references,
            };

            // Run ILMerge
            var merge = new ILRepacking.ILRepack(repackOptions)
            {
                PrimaryAssemblyDefinition = assembly,
                MemoryOnly = true,
                //KeepFirstOfMultipleAssemblyLevelAttributes = true,
                //Log = true,
                //LogFile = "ilmerge.log",
            };

            try
            {
                merge.Repack();
            }
            catch (Exception)
            {
                log.Log(new LogMessage("ILRepack", LogMessageType.Error, string.Format("Error while ILRepacking {0}", assembly.Name.Name)));
                throw;
            }

            // Copy name
            merge.TargetAssemblyDefinition.Name.Name    = assembly.Name.Name;
            merge.TargetAssemblyDefinition.Name.Version = assembly.Name.Version;

            // Add assembly signing info
            if (assembly.Name.HasPublicKey)
            {
                merge.TargetAssemblyDefinition.Name.PublicKey      = assembly.Name.PublicKey;
                merge.TargetAssemblyDefinition.Name.PublicKeyToken = assembly.Name.PublicKeyToken;
                merge.TargetAssemblyDefinition.Name.Attributes    |= AssemblyAttributes.PublicKey;
                if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) == ModuleAttributes.StrongNameSigned)
                {
                    merge.TargetAssemblyMainModule.Attributes |= ModuleAttributes.StrongNameSigned;
                }
            }

            try
            {
                // Delete serializer dll
                File.Delete(serializationAssemblyLocation);

                var serializationAssemblyPdbFilePath = Path.ChangeExtension(serializationAssemblyLocation, "pdb");
                if (File.Exists(serializationAssemblyPdbFilePath))
                {
                    File.Delete(serializationAssemblyPdbFilePath);
                }
            }
            catch (IOException)
            {
                // Mute IOException
            }

            return(merge.TargetAssemblyDefinition);
        }
        public static AssemblyDefinition GenerateSerializationAssembly(PlatformType platformType, BaseAssemblyResolver assemblyResolver, AssemblyDefinition assembly, string serializationAssemblyLocation, string signKeyFile, List <string> serializatonProjectReferencePaths)
        {
            // Make sure all assemblies in serializatonProjectReferencePaths are referenced (sometimes they might be optimized out if no direct references)
            foreach (var serializatonProjectReferencePath in serializatonProjectReferencePaths)
            {
                var shortAssemblyName = Path.GetFileNameWithoutExtension(serializatonProjectReferencePath);

                // Still in references (not optimized)
                if (assembly.MainModule.AssemblyReferences.Any(x => x.Name == shortAssemblyName))
                {
                    continue;
                }

                // For now, use AssemblyDefinition.ReadAssembly to compute full name -- maybe not very efficient but it shouldn't happen often anyway)
                var referencedAssembly = AssemblyDefinition.ReadAssembly(serializatonProjectReferencePath);

                assembly.MainModule.AssemblyReferences.Add(AssemblyNameReference.Parse(referencedAssembly.FullName));
            }

            // Create the serializer code generator
            var serializerGenerator = new ComplexSerializerCodeGenerator(assemblyResolver, assembly);

            // Register default serialization profile (to help AOT generic instantiation of serializers)
            RegisterDefaultSerializationProfile(assemblyResolver, assembly, serializerGenerator);

            // Generate serializer code
            var serializerGeneratedCode = serializerGenerator.TransformText();

            var syntaxTree = CSharpSyntaxTree.ParseText(serializerGeneratedCode);

            // Add reference from source assembly
            // Use a hash set because it seems including twice mscorlib (2.0 and 4.0) seems to be a problem.
            var skipWindows = "Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null";

            var compilerOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true);

            // Sign the serialization assembly the same way the source was signed
            // TODO: Transmit over command line
            if (assembly.Name.HasPublicKey)
            {
                // TODO: If delay signed, we could actually extract the public key and apply it ourself maybe?
                if (signKeyFile == null)
                {
                    throw new InvalidOperationException("Generating serialization code for signed assembly, but no key was specified.");
                }

                compilerOptions = compilerOptions.WithCryptoKeyFile(signKeyFile).WithStrongNameProvider(new DesktopStrongNameProvider());
                if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) != ModuleAttributes.StrongNameSigned)
                {
                    // Delay signed
                    compilerOptions = compilerOptions.WithDelaySign(true);
                }
            }

            var metadataReferences = new List <MetadataReference>();
            var assemblyLocations  = new HashSet <string>();

            foreach (var referencedAssemblyName in assembly.MainModule.AssemblyReferences)
            {
                // We skip both Windows, and current assembly (AssemblyProcessor.Common, which might be added with an alias)
                if (referencedAssemblyName.FullName != skipWindows && referencedAssemblyName.FullName != typeof(ComplexSerializerGenerator).Assembly.FullName && referencedAssemblyName.FullName != "SiliconStudio.AssemblyProcessor")
                {
                    if (assemblyLocations.Add(referencedAssemblyName.Name))
                    {
                        //Console.WriteLine("Resolve Assembly for serialization [{0}]", referencedAssemblyName.FullName);
                        metadataReferences.Add(CreateMetadataReference(assemblyResolver, assemblyResolver.Resolve(referencedAssemblyName)));
                    }
                }
            }

            // typeof(Dictionary<,>)
            // Special case for 4.5: Because Dictionary<,> is forwarded, we need to add a reference to the actual assembly
            var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);

            metadataReferences.Add(CreateMetadataReference(assemblyResolver, mscorlibAssembly));
            var collectionType = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Dictionary <,>).FullName);

            metadataReferences.Add(CreateMetadataReference(assemblyResolver, collectionType.Module.Assembly));

            // Make sure System and System.Reflection are added
            // TODO: Maybe we should do that for .NETCore and PCL too? (instead of WinRT only)
            if (platformType == PlatformType.WindowsStore || platformType == PlatformType.WindowsPhone)
            {
                if (assemblyLocations.Add("System"))
                {
                    metadataReferences.Add(CreateMetadataReference(assemblyResolver, assemblyResolver.Resolve("System")));
                }
                if (assemblyLocations.Add("System.Reflection"))
                {
                    metadataReferences.Add(CreateMetadataReference(assemblyResolver, assemblyResolver.Resolve("System.Reflection")));
                }
            }

            metadataReferences.Add(CreateMetadataReference(assemblyResolver, assembly));
            assemblyLocations.Add(assembly.Name.Name);

            // In case Paradox.Framework.Serialization was not referenced, let's add it.
            if (!assemblyLocations.Contains("SiliconStudio.Core"))
            {
                metadataReferences.Add(CreateMetadataReference(assemblyResolver, assemblyResolver.Resolve("SiliconStudio.Core")));
                assemblyLocations.Add("SiliconStudio.Core");
            }

            // Create roslyn compilation object
            var assemblyName = Path.GetFileNameWithoutExtension(serializationAssemblyLocation);
            var compilation  = CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, metadataReferences, compilerOptions);

            // Do the actual compilation, and check errors
            using (var peStream = new FileStream(serializationAssemblyLocation, FileMode.Create, FileAccess.Write))
            {
                var compilationResult = compilation.Emit(peStream);

                if (!compilationResult.Success)
                {
                    var errors = new StringBuilder();
                    errors.AppendLine(string.Format("Serialization assembly compilation: {0} error(s)", compilationResult.Diagnostics.Count(x => x.Severity >= DiagnosticSeverity.Error)));
                    foreach (var error in compilationResult.Diagnostics)
                    {
                        if (error.Severity >= DiagnosticSeverity.Warning)
                        {
                            errors.AppendLine(error.ToString());
                        }
                    }
                    throw new InvalidOperationException(errors.ToString());
                }
            }

            // Run ILMerge
            var merge = new ILRepacking.ILRepack()
            {
                OutputFile     = assembly.MainModule.FullyQualifiedName,
                DebugInfo      = true,
                CopyAttributes = true,
                AllowMultipleAssemblyLevelAttributes = true,
                XmlDocumentation          = false,
                NoRepackRes               = true,
                PrimaryAssemblyDefinition = assembly,
                WriteToDisk               = false,
                //KeepFirstOfMultipleAssemblyLevelAttributes = true,
                //Log = true,
                //LogFile = "ilmerge.log",
            };

            merge.SetInputAssemblies(new string[] { serializationAssemblyLocation });

            // Force to use the correct framework
            //merge.SetTargetPlatform("v4", frameworkFolder);
            merge.SetSearchDirectories(assemblyResolver.GetSearchDirectories());
            merge.Merge();

            // Copy name
            merge.TargetAssemblyDefinition.Name.Name    = assembly.Name.Name;
            merge.TargetAssemblyDefinition.Name.Version = assembly.Name.Version;

            // Add assembly signing info
            if (assembly.Name.HasPublicKey)
            {
                merge.TargetAssemblyDefinition.Name.PublicKey      = assembly.Name.PublicKey;
                merge.TargetAssemblyDefinition.Name.PublicKeyToken = assembly.Name.PublicKeyToken;
                merge.TargetAssemblyDefinition.Name.Attributes    |= AssemblyAttributes.PublicKey;
                if ((assembly.MainModule.Attributes & ModuleAttributes.StrongNameSigned) == ModuleAttributes.StrongNameSigned)
                {
                    merge.TargetAssemblyMainModule.Attributes |= ModuleAttributes.StrongNameSigned;
                }
            }

            try
            {
                // Delete serializer dll
                File.Delete(serializationAssemblyLocation);

                var serializationAssemblyPdbFilePath = Path.ChangeExtension(serializationAssemblyLocation, "pdb");
                if (File.Exists(serializationAssemblyPdbFilePath))
                {
                    File.Delete(serializationAssemblyPdbFilePath);
                }
            }
            catch (IOException)
            {
                // Mute IOException
            }

            return(merge.TargetAssemblyDefinition);
        }
Exemple #17
0
        public bool Process(AssemblyProcessorContext context)
        {
            var assembly         = context.Assembly;
            var mscorlibAssembly = CecilExtensions.FindCorlibAssembly(assembly);

            if (mscorlibAssembly == null)
            {
                throw new InvalidOperationException("Missing mscorlib.dll from assembly");
            }

            // For now, use import, but this can cause mixed framework versions when processing an assembly with a different framework version.
            voidType   = assembly.MainModule.TypeSystem.Void;
            stringType = assembly.MainModule.TypeSystem.String;
            objectType = assembly.MainModule.TypeSystem.Object;
            var propertyInfoType = assembly.MainModule.ImportReference(mscorlibAssembly.MainModule.GetTypeResolved(typeof(PropertyInfo).FullName));
            var typeType         = mscorlibAssembly.MainModule.GetTypeResolved(typeof(Type).FullName);


            TypeDefinition propertyChangedExtendedEventArgsType;

            AssemblyDefinition siliconStudioCoreAssembly;

            try
            {
                siliconStudioCoreAssembly = assembly.Name.Name == "SiliconStudio.Core"
                    ? assembly
                    : context.AssemblyResolver.Resolve("SiliconStudio.Core");
            }
            catch (Exception)
            {
                return(true);
            }

            propertyChangedExtendedEventArgsType = siliconStudioCoreAssembly.MainModule.GetTypes().First(x => x.Name == "PropertyChangedExtendedEventArgs").Resolve();

            var typeTokenInfoEx         = mscorlibAssembly.MainModule.GetType("System.Reflection.TypeInfo").Resolve();
            var getPropertyMethod       = typeTokenInfoEx.Methods.First(x => x.Name == "GetDeclaredProperty" && x.Parameters.Count == 1);
            var getTypeFromHandleMethod = typeType.Methods.First(x => x.Name == "GetTypeFromHandle");
            var getTokenInfoExMethod    = mscorlibAssembly.MainModule.GetType("System.Reflection.IntrospectionExtensions").Resolve().Methods.First(x => x.Name == "GetTypeInfo");

            var propertyChangedExtendedEventArgsConstructor = assembly.MainModule.ImportReference(propertyChangedExtendedEventArgsType.Methods.First(x => x.IsConstructor));

            bool modified = false;

            foreach (var type in assembly.MainModule.GetTypes())
            {
                MethodReference getPropertyChangedMethod;

                getPropertyChangedMethod = GetGetPropertyChangedMethod(assembly, type);
                //var propertyChangedField = GetPropertyChangedField(type);
                //if (propertyChangedField == null)
                //    continue;

                var propertyChangedField = GetPropertyChangedField(type);

                if (getPropertyChangedMethod == null && propertyChangedField == null)
                {
                    continue;
                }

                TypeReference propertyChangedFieldType;

                if (getPropertyChangedMethod == null)
                {
                    modified = true;
                    getPropertyChangedMethod = GetOrCreateGetPropertyChangedMethod(assembly, type, propertyChangedField);
                }

                if (propertyChangedField != null)
                {
                    propertyChangedField     = assembly.MainModule.ImportReference(propertyChangedField);
                    propertyChangedFieldType = propertyChangedField.FieldType;
                }
                else
                {
                    propertyChangedFieldType = getPropertyChangedMethod.ReturnType;
                }

                // Add generic to declaring type
                if (getPropertyChangedMethod.DeclaringType.HasGenericParameters)
                {
                    getPropertyChangedMethod = getPropertyChangedMethod.MakeGeneric(getPropertyChangedMethod.DeclaringType.GenericParameters.ToArray());
                }

                var propertyChangedInvoke = assembly.MainModule.ImportReference(propertyChangedFieldType.Resolve().Methods.First(x => x.Name == "Invoke"));

                foreach (var property in type.Properties)
                {
                    if (property.SetMethod == null || !property.HasThis)
                    {
                        continue;
                    }

                    MethodReference propertyGetMethod = property.GetMethod;

                    // Only patch properties that have a public Getter
                    var methodDefinition = propertyGetMethod.Resolve();
                    if ((methodDefinition.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
                    {
                        continue;
                    }

                    // Add generic to declaring type
                    if (propertyGetMethod.DeclaringType.HasGenericParameters)
                    {
                        propertyGetMethod = propertyGetMethod.MakeGeneric(propertyGetMethod.DeclaringType.GenericParameters.ToArray());
                    }

                    //var versionableAttribute = property.CustomAttributes.FirstOrDefault(x => x.AttributeType.FullName == typeof(VersionableAttribute).FullName);
                    //if (versionableAttribute == null)
                    //    continue;

                    modified = true;

                    FieldReference staticField = new FieldDefinition(property.Name + "PropertyInfo", FieldAttributes.Static | FieldAttributes.Private | FieldAttributes.InitOnly, propertyInfoType);
                    type.Fields.Add((FieldDefinition)staticField);

                    // Add generic to declaring type
                    if (staticField.DeclaringType.HasGenericParameters)
                    {
                        staticField = staticField.MakeGeneric(staticField.DeclaringType.GenericParameters.ToArray());
                    }

                    // In static constructor, find PropertyInfo and store it in static field
                    {
                        var staticConstructor = type.GetStaticConstructor();
                        if (staticConstructor == null)
                        {
                            staticConstructor = new MethodDefinition(".cctor",
                                                                     MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                                                                     voidType);
                            staticConstructor.Body.GetILProcessor().Append(Instruction.Create(OpCodes.Ret));

                            type.Methods.Add(staticConstructor);
                        }


                        VariableReference localTokenEx = null;
                        int localTokenExIndex          = 0;
                        for (int i = 0; i < staticConstructor.Body.Variables.Count; i++)
                        {
                            var localVar = staticConstructor.Body.Variables[i];
                            if (localVar.VariableType.FullName == typeTokenInfoEx.FullName)
                            {
                                localTokenEx      = localVar;
                                localTokenExIndex = i;
                                break;
                            }
                        }

                        if (localTokenEx == null)
                        {
                            localTokenEx = new VariableDefinition(assembly.MainModule.ImportReference(typeTokenInfoEx));
                            staticConstructor.Body.Variables.Add((VariableDefinition)localTokenEx);
                            localTokenExIndex = staticConstructor.Body.Variables.Count - 1;
                        }

                        var ilProcessor       = staticConstructor.Body.GetILProcessor();
                        var returnInstruction = staticConstructor.Body.Instructions.Last();

                        var newReturnInstruction = Instruction.Create(returnInstruction.OpCode);
                        newReturnInstruction.Operand = returnInstruction.Operand;

                        returnInstruction.OpCode  = OpCodes.Nop;
                        returnInstruction.Operand = null;

                        // Find PropertyInfo and store it in static field
                        ilProcessor.Append(Instruction.Create(OpCodes.Ldtoken, type));
                        ilProcessor.Append(Instruction.Create(OpCodes.Call, assembly.MainModule.ImportReference(getTypeFromHandleMethod)));
                        ilProcessor.Append(Instruction.Create(OpCodes.Call, assembly.MainModule.ImportReference(getTokenInfoExMethod)));
                        ilProcessor.Append(LocationToStloc(ilProcessor, localTokenExIndex));
                        ilProcessor.Append(ilProcessor.Create(OpCodes.Ldloca_S, (byte)localTokenExIndex));
                        ilProcessor.Append(Instruction.Create(OpCodes.Ldstr, property.Name));
                        ilProcessor.Append(Instruction.Create(OpCodes.Call, assembly.MainModule.ImportReference(getPropertyMethod)));
                        ilProcessor.Append(Instruction.Create(OpCodes.Stsfld, staticField));

                        ilProcessor.Append(newReturnInstruction);
                    }

                    {
                        var ilProcessor       = property.SetMethod.Body.GetILProcessor();
                        var returnInstruction = property.SetMethod.Body.Instructions.Last();

                        var firstInstruction = property.SetMethod.Body.Instructions[0];

                        if (property.SetMethod.Body.Instructions[0].OpCode != OpCodes.Nop)
                        {
                            ilProcessor.InsertBefore(property.SetMethod.Body.Instructions[0], Instruction.Create(OpCodes.Nop));
                        }

                        var newReturnInstruction = Instruction.Create(returnInstruction.OpCode);
                        newReturnInstruction.Operand = returnInstruction.Operand;

                        returnInstruction.OpCode  = OpCodes.Nop;
                        returnInstruction.Operand = null;

                        var propertyChangedVariable = new VariableDefinition("propertyChanged", assembly.MainModule.ImportReference(propertyChangedFieldType));
                        property.SetMethod.Body.Variables.Add(propertyChangedVariable);

                        var oldValueVariable = new VariableDefinition("oldValue", objectType);
                        property.SetMethod.Body.Variables.Add(oldValueVariable);

                        Instruction jump1, jump2;

                        // Prepend:
                        // var propertyChanged = GetPropertyChanged();
                        // var oldValue = propertyChanged != null ? (object)Property : null;
                        property.SetMethod.Body.SimplifyMacros();
                        ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Ldarg_0));
                        ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Call, getPropertyChangedMethod));
                        ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Stloc, propertyChangedVariable));
                        ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Ldloc, propertyChangedVariable));
                        ilProcessor.InsertBefore(firstInstruction, jump1 = Instruction.Create(OpCodes.Brtrue, Instruction.Create(OpCodes.Nop)));
                        ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Ldnull));
                        ilProcessor.InsertBefore(firstInstruction, jump2 = Instruction.Create(OpCodes.Br, Instruction.Create(OpCodes.Nop)));
                        ilProcessor.InsertBefore(firstInstruction, (Instruction)(jump1.Operand = Instruction.Create(OpCodes.Ldarg_0)));
                        ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Call, propertyGetMethod));
                        if (property.PropertyType.IsValueType)
                        {
                            ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Box, property.PropertyType));
                        }
                        ilProcessor.InsertBefore(firstInstruction, (Instruction)(jump2.Operand = Instruction.Create(OpCodes.Nop)));
                        ilProcessor.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Stloc, oldValueVariable));

                        // Append:
                        // if (propertyChanged != null)
                        //     propertyChanged(this, new PropertyChangedExtendedEventArgs("Property", oldValue, Property));
                        ilProcessor.Append(Instruction.Create(OpCodes.Ldloc, propertyChangedVariable));
                        ilProcessor.Append(Instruction.Create(OpCodes.Ldnull));
                        ilProcessor.Append(Instruction.Create(OpCodes.Ceq));
                        ilProcessor.Append(Instruction.Create(OpCodes.Brtrue, newReturnInstruction));
                        ilProcessor.Append(Instruction.Create(OpCodes.Ldloc, propertyChangedVariable));
                        ilProcessor.Append(Instruction.Create(OpCodes.Ldarg_0));
                        ilProcessor.Append(Instruction.Create(OpCodes.Ldsfld, staticField));
                        ilProcessor.Append(Instruction.Create(OpCodes.Ldloc, oldValueVariable));
                        ilProcessor.Append(Instruction.Create(OpCodes.Ldarg_0));
                        ilProcessor.Append(Instruction.Create(OpCodes.Call, propertyGetMethod));
                        if (property.PropertyType.IsValueType)
                        {
                            ilProcessor.Append(Instruction.Create(OpCodes.Box, property.PropertyType));
                        }
                        ilProcessor.Append(Instruction.Create(OpCodes.Newobj, propertyChangedExtendedEventArgsConstructor));
                        ilProcessor.Append(Instruction.Create(OpCodes.Callvirt, propertyChangedInvoke));
                        ilProcessor.Append(Instruction.Create(OpCodes.Nop));
                        ilProcessor.Append(newReturnInstruction);
                        property.SetMethod.Body.OptimizeMacros();
                    }
                }
            }

            return(modified);
        }