Пример #1
0
        /// <summary>
        /// Get the managed size of a given type. This matches an IL-level sizeof(t), even if it cannot be determined normally in C#.
        /// Note that sizeof(t) != Marshal.SizeOf(t), f.e. when t is char.
        /// </summary>
        /// <param name="t">The type to get the size from.</param>
        /// <returns>The managed type size.</returns>
        public static int GetManagedSize(this Type t) {
            if (_GetManagedSizeCache.TryGetValue(t, out int size))
                return size;

            if (_GetManagedSizeHelper == null) {
                Assembly asm;

                const string @namespace = "MonoMod.Utils";
                const string @name = "GetManagedSizeHelper";
                const string @fullName = @namespace + "." + @name;

#if !CECIL0_9
                using (
#endif
                ModuleDefinition module = ModuleDefinition.CreateModule(
                    @fullName,
                    new ModuleParameters() {
                        Kind = ModuleKind.Dll,
#if !CECIL0_9 && MONOMOD_UTILS
                        ReflectionImporterProvider = MMReflectionImporter.Provider
#endif
                    }
                )
#if CECIL0_9
                ;
#else
                )
#endif
                {

                    TypeDefinition type = new TypeDefinition(
                        @namespace,
                        @name,
                        MC.TypeAttributes.Public | MC.TypeAttributes.Abstract | MC.TypeAttributes.Sealed
                    ) {
                        BaseType = module.TypeSystem.Object
                    };
                    module.Types.Add(type);

                    MethodDefinition method = new MethodDefinition(@name,
                        MC.MethodAttributes.Public | MC.MethodAttributes.Static | MC.MethodAttributes.HideBySig,
                        module.TypeSystem.Int32
                    );
                    GenericParameter genParam = new GenericParameter("T", method);
                    method.GenericParameters.Add(genParam);
                    type.Methods.Add(method);

                    ILProcessor il = method.Body.GetILProcessor();
                    il.Emit(OpCodes.Sizeof, genParam);
                    il.Emit(OpCodes.Ret);

                    asm = ReflectionHelper.Load(module);
                }

                _GetManagedSizeHelper = asm.GetType(@fullName).GetMethod(@name);
            }

            size =  (_GetManagedSizeHelper.MakeGenericMethod(t).CreateDelegate<Func<int>>() as Func<int>)();
            lock (_GetManagedSizeCache) {
                return _GetManagedSizeCache[t] = size;
            }
        }
Пример #2
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
            }
        }