Example #1
0
        protected override MethodInfo _Generate(DynamicMethodDefinition dmd, object context)
        {
            MethodDefinition def     = dmd.Definition;
            TypeDefinition   typeDef = context as TypeDefinition;

            bool             moduleIsTemporary   = false;
            ModuleDefinition module              = typeDef?.Module;
            HashSet <string> accessChecksIgnored = null;

            if (typeDef == null)
            {
                moduleIsTemporary   = true;
                accessChecksIgnored = new HashSet <string>();

                string name = dmd.GetDumpName("Cecil");
                module = ModuleDefinition.CreateModule(name, new ModuleParameters()
                {
                    Kind = ModuleKind.Dll,
#if !CECIL0_9
                    ReflectionImporterProvider = MMReflectionImporter.ProviderNoDefault
#endif
                });

                module.Assembly.CustomAttributes.Add(new CustomAttribute(module.ImportReference(DynamicMethodDefinition.c_UnverifiableCodeAttribute)));

                if (dmd.Debug)
                {
                    CustomAttribute caDebug = new CustomAttribute(module.ImportReference(DynamicMethodDefinition.c_DebuggableAttribute));
                    caDebug.ConstructorArguments.Add(new CustomAttributeArgument(
                                                         module.ImportReference(typeof(DebuggableAttribute.DebuggingModes)),
                                                         DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.Default
                                                         ));
                    module.Assembly.CustomAttributes.Add(caDebug);
                }

                typeDef = new TypeDefinition(
                    "",
                    $"DMD<{dmd.OriginalMethod?.Name?.Replace('.', '_')}>?{GetHashCode()}",
                    Mono.Cecil.TypeAttributes.Public | Mono.Cecil.TypeAttributes.Abstract | Mono.Cecil.TypeAttributes.Sealed | Mono.Cecil.TypeAttributes.Class
                    )
                {
                    BaseType = module.TypeSystem.Object
                };

                module.Types.Add(typeDef);
            }

            try {
#pragma warning disable IDE0039 // Use local function
                Relinker relinker = (mtp, ctx) => {
                    return(module.ImportReference(mtp));
                };
#pragma warning restore IDE0039 // Use local function

                MethodDefinition clone = new MethodDefinition("_" + def.Name.Replace('.', '_'), def.Attributes, module.TypeSystem.Void)
                {
                    MethodReturnType = def.MethodReturnType,
                    Attributes       = Mono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.Static,
                    ImplAttributes   = Mono.Cecil.MethodImplAttributes.IL | Mono.Cecil.MethodImplAttributes.Managed,
                    DeclaringType    = typeDef,
                    NoInlining       = true
                };

                foreach (ParameterDefinition param in def.Parameters)
                {
                    clone.Parameters.Add(param.Clone().Relink(relinker, clone));
                }

                clone.ReturnType = def.ReturnType.Relink(relinker, clone);

                typeDef.Methods.Add(clone);

                clone.HasThis = def.HasThis;
                Mono.Cecil.Cil.MethodBody body = clone.Body = def.Body.Clone(clone);

                foreach (VariableDefinition var in clone.Body.Variables)
                {
                    var.VariableType = var.VariableType.Relink(relinker, clone);
                }

                foreach (ExceptionHandler handler in clone.Body.ExceptionHandlers)
                {
                    if (handler.CatchType != null)
                    {
                        handler.CatchType = handler.CatchType.Relink(relinker, clone);
                    }
                }

                for (int instri = 0; instri < body.Instructions.Count; instri++)
                {
                    Instruction instr   = body.Instructions[instri];
                    object      operand = instr.Operand;

                    // Import references.
                    if (operand is ParameterDefinition param)
                    {
                        operand = clone.Parameters[param.Index];
                    }
                    else if (operand is IMetadataTokenProvider mtp)
                    {
                        operand = mtp.Relink(relinker, clone);
                    }

                    if (operand is DynamicMethodReference dmref)
                    {
                        // TODO: Fix up DynamicMethod inline refs.
                    }

                    if (accessChecksIgnored != null && operand is MemberReference mref)
                    {
                        IMetadataScope asmRef = (mref as TypeReference)?.Scope ?? mref.DeclaringType.Scope;
                        if (!accessChecksIgnored.Contains(asmRef.Name))
                        {
                            CustomAttribute caAccess = new CustomAttribute(module.ImportReference(DynamicMethodDefinition.c_IgnoresAccessChecksToAttribute));
                            caAccess.ConstructorArguments.Add(new CustomAttributeArgument(
                                                                  module.ImportReference(typeof(DebuggableAttribute.DebuggingModes)),
                                                                  asmRef.Name
                                                                  ));
                            module.Assembly.CustomAttributes.Add(caAccess);
                            accessChecksIgnored.Add(asmRef.Name);
                        }
                    }

                    instr.Operand = operand;
                }

                clone.HasThis = false;

                if (def.HasThis)
                {
                    TypeReference type = def.DeclaringType;
                    if (type.IsValueType)
                    {
                        type = new ByReferenceType(type);
                    }
                    clone.Parameters.Insert(0, new ParameterDefinition("<>_this", Mono.Cecil.ParameterAttributes.None, type.Relink(relinker, clone)));
                }

                if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("MONOMOD_DMD_DUMP")))
                {
                    string dir  = Path.GetFullPath(Environment.GetEnvironmentVariable("MONOMOD_DMD_DUMP"));
                    string name = module.Name + ".dll";
                    string path = Path.Combine(dir, name);
                    dir = Path.GetDirectoryName(path);
                    if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
                    {
                        Directory.CreateDirectory(dir);
                    }
                    if (File.Exists(path))
                    {
                        File.Delete(path);
                    }
                    using (Stream fileStream = File.OpenWrite(path))
                        module.Write(fileStream);
                }

                Assembly asm = ReflectionHelper.Load(module);

                return(asm.GetType(typeDef.FullName.Replace("+", "\\+"), false, false)
                       .GetMethod(clone.Name, BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static));
            } finally {
#if !CECIL0_9
                if (moduleIsTemporary)
                {
                    module.Dispose();
                }
#endif
            }
        }
Example #2
0
        public static MethodBuilder GenerateMethodBuilder(DynamicMethodDefinition dmd, TypeBuilder typeBuilder)
        {
            MethodBase       orig = dmd.OriginalMethod;
            MethodDefinition def  = dmd.Definition;

            if (typeBuilder == null)
            {
                string dumpDir = Environment.GetEnvironmentVariable("MONOMOD_DMD_DUMP");
                if (string.IsNullOrEmpty(dumpDir))
                {
                    dumpDir = null;
                }
                else
                {
                    dumpDir = Path.GetFullPath(dumpDir);
                }
                bool            collect = string.IsNullOrEmpty(dumpDir) && _MBCanRunAndCollect;
                AssemblyBuilder ab      = AppDomain.CurrentDomain.DefineDynamicAssembly(
                    new AssemblyName()
                {
                    Name = dmd.GetDumpName("MethodBuilder")
                },
                    collect ? (AssemblyBuilderAccess)9 : AssemblyBuilderAccess.RunAndSave,
                    dumpDir
                    );

                ab.SetCustomAttribute(new CustomAttributeBuilder(DynamicMethodDefinition.c_UnverifiableCodeAttribute, new object[] {
                }));

                if (dmd.Debug)
                {
                    ab.SetCustomAttribute(new CustomAttributeBuilder(DynamicMethodDefinition.c_DebuggableAttribute, new object[] {
                        DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.Default
                    }));
                }

                // Note: Debugging can fail on mono if Mono.CompilerServices.SymbolWriter.dll cannot be found,
                // or if Mono.CompilerServices.SymbolWriter.SymbolWriterImpl can't be found inside of that.
                // https://github.com/mono/mono/blob/f879e35e3ed7496d819bd766deb8be6992d068ed/mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs#L146
                ModuleBuilder module = ab.DefineDynamicModule($"{ab.GetName().Name}.dll", $"{ab.GetName().Name}.dll", dmd.Debug);
                typeBuilder = module.DefineType(
                    $"DMD<{orig?.GetID(simple: true)?.Replace('.', '_')}>?{dmd.GetHashCode()}",
                    System.Reflection.TypeAttributes.Public | System.Reflection.TypeAttributes.Abstract | System.Reflection.TypeAttributes.Sealed | System.Reflection.TypeAttributes.Class
                    );
            }

            Type[]   argTypes;
            Type[][] argTypesModReq;
            Type[][] argTypesModOpt;

            if (orig != null)
            {
                ParameterInfo[] args = orig.GetParameters();
                int             offs = 0;
                if (!orig.IsStatic)
                {
                    offs++;
                    argTypes          = new Type[args.Length + 1];
                    argTypesModReq    = new Type[args.Length + 1][];
                    argTypesModOpt    = new Type[args.Length + 1][];
                    argTypes[0]       = orig.GetThisParamType();
                    argTypesModReq[0] = Type.EmptyTypes;
                    argTypesModOpt[0] = Type.EmptyTypes;
                }
                else
                {
                    argTypes       = new Type[args.Length];
                    argTypesModReq = new Type[args.Length][];
                    argTypesModOpt = new Type[args.Length][];
                }

                for (int i = 0; i < args.Length; i++)
                {
                    argTypes[i + offs]       = args[i].ParameterType;
                    argTypesModReq[i + offs] = args[i].GetRequiredCustomModifiers();
                    argTypesModOpt[i + offs] = args[i].GetOptionalCustomModifiers();
                }
            }
            else
            {
                int offs = 0;
                if (def.HasThis)
                {
                    offs++;
                    argTypes       = new Type[def.Parameters.Count + 1];
                    argTypesModReq = new Type[def.Parameters.Count + 1][];
                    argTypesModOpt = new Type[def.Parameters.Count + 1][];
                    Type type = def.DeclaringType.ResolveReflection();
                    if (type.IsValueType)
                    {
                        type = type.MakeByRefType();
                    }
                    argTypes[0]       = type;
                    argTypesModReq[0] = Type.EmptyTypes;
                    argTypesModOpt[0] = Type.EmptyTypes;
                }
                else
                {
                    argTypes       = new Type[def.Parameters.Count];
                    argTypesModReq = new Type[def.Parameters.Count][];
                    argTypesModOpt = new Type[def.Parameters.Count][];
                }

                List <Type> modReq = new List <Type>();
                List <Type> modOpt = new List <Type>();

                for (int i = 0; i < def.Parameters.Count; i++)
                {
                    _DMDEmit.ResolveWithModifiers(def.Parameters[i].ParameterType, out Type paramType, out Type[] paramTypeModReq, out Type[] paramTypeModOpt, modReq, modOpt);