Beispiel #1
0
        protected override MethodInfo _Generate(DynamicMethodDefinition dmd, object context)
        {
            TypeBuilder   typeBuilder = context as TypeBuilder;
            MethodBuilder method      = GenerateMethodBuilder(dmd, typeBuilder);

            typeBuilder = (TypeBuilder)method.DeclaringType;
            Type type = typeBuilder.CreateType();

            if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("MONOMOD_DMD_DUMP")))
            {
                string path = method.Module.FullyQualifiedName;
                string name = Path.GetFileName(path);
                string dir  = Path.GetDirectoryName(path);
                if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                if (File.Exists(path))
                {
                    File.Delete(path);
                }
                ((AssemblyBuilder)typeBuilder.Assembly).Save(name);
            }
            return(type.GetMethod(method.Name, BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static));
        }
        /// <summary>
        /// Get a native function pointer for a given method. This matches an IL-level ldftn.
        /// </summary>
        /// <remarks>
        /// ldftn doesn't JIT-compile the method on mono, which thus keeps the class constructor untouched.
        /// On the other hand, its result thus doesn't always match that of MethodHandle.GetFunctionPointer().
        /// </remarks>
        /// <param name="m">The method to get a native function pointer for.</param>
        /// <returns>The native function pointer.</returns>
        public static IntPtr GetLdftnPointer(this MethodBase m) {
            if (_GetLdftnPointerCache.TryGetValue(m, out Func<IntPtr> func))
                return func();

            DynamicMethodDefinition dmd = new DynamicMethodDefinition(
                $"GetLdftnPointer<{m.GetID(simple: true)}>",
                typeof(int), Type.EmptyTypes
            );

            ILProcessor il = dmd.GetILProcessor();
            il.Emit(OpCodes.Ldftn, dmd.Definition.Module.ImportReference(m));
            il.Emit(OpCodes.Ret);

            lock (_GetLdftnPointerCache) {
                return (_GetLdftnPointerCache[m] = dmd.Generate().CreateDelegate<Func<IntPtr>>() as Func<IntPtr>)();
            }
        }
 /// <summary>
 /// Fill the DynamicMethod with a stub.
 /// </summary>
 public static DynamicMethodDefinition Stub(this DynamicMethodDefinition dmd)
 {
     CIL.ILProcessor il = dmd.GetILProcessor();
     for (int i = 0; i < 32; i++)
     {
         // Prevent mono from inlining the DynamicMethod.
         il.Emit(CIL.OpCodes.Nop);
     }
     if (dmd.Definition.ReturnType != dmd.Definition.Module.TypeSystem.Void)
     {
         il.Body.Variables.Add(new CIL.VariableDefinition(dmd.Definition.ReturnType));
         il.Emit(CIL.OpCodes.Ldloca_S, (sbyte)0);
         il.Emit(CIL.OpCodes.Initobj, dmd.Definition.ReturnType);
         il.Emit(CIL.OpCodes.Ldloc_0);
     }
     il.Emit(CIL.OpCodes.Ret);
     return(dmd);
 }
Beispiel #4
0
        public static int GetManagedSize(this Type t)
        {
            if (_GetManagedSizeCache.TryGetValue(t, out int size))
            {
                return(size);
            }

            // Note: sizeof is more accurate for the "managed size" than Marshal.SizeOf (marshalled size)
            // It also returns a value for types of which the size cannot be determined otherwise.

            DynamicMethodDefinition dmd = new DynamicMethodDefinition(
                $"GetSize<{t.FullName}>",
                typeof(int), Type.EmptyTypes
                );

            ILProcessor il = dmd.GetILProcessor();

            il.Emit(OpCodes.Sizeof, dmd.Definition.Module.ImportReference(t));
            il.Emit(OpCodes.Ret);

            lock (_GetManagedSizeCache) {
                return(_GetManagedSizeCache[t] = (dmd.Generate().CreateDelegate(typeof(Func <int>)) as Func <int>)());
            }
        }
Beispiel #5
0
        public static IntPtr GetLdftnPointer(this MethodBase m)
        {
            if (_GetLdftnPointerCache.TryGetValue(m, out Func <IntPtr> func))
            {
                return(func());
            }

            // Note: ldftn doesn't JIT the method on mono, keeping the class constructor untouched.
            // Its result thus doesn't always match MethodHandle.GetFunctionPointer().

            DynamicMethodDefinition dmd = new DynamicMethodDefinition(
                $"GetLdftnPointer<{m.GetFindableID(simple: true)}>",
                typeof(int), Type.EmptyTypes
                );

            ILProcessor il = dmd.GetILProcessor();

            il.Emit(OpCodes.Ldftn, dmd.Definition.Module.ImportReference(m));
            il.Emit(OpCodes.Ret);

            lock (_GetLdftnPointerCache) {
                return((_GetLdftnPointerCache[m] = dmd.Generate().CreateDelegate(typeof(Func <IntPtr>)) as Func <IntPtr>)());
            }
        }
Beispiel #6
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
            }
        }
Beispiel #7
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);
Beispiel #8
0
        public static void Generate(DynamicMethodDefinition dmd, MethodBase _mb, ILGenerator il)
        {
            MethodDefinition def = dmd.Definition;
            DynamicMethod    dm  = _mb as DynamicMethod;

#if !NETSTANDARD
            MethodBuilder mb            = _mb as MethodBuilder;
            ModuleBuilder moduleBuilder = mb?.Module as ModuleBuilder;
            // moduleBuilder.Assembly sometimes avoids the .Assembly override under mysterious circumstances.
            AssemblyBuilder    assemblyBuilder     = (mb?.DeclaringType as TypeBuilder)?.Assembly as AssemblyBuilder;
            HashSet <Assembly> accessChecksIgnored = null;
            if (mb != null)
            {
                accessChecksIgnored = new HashSet <Assembly>();
            }
#endif

#if !CECIL0_9
            MethodDebugInformation defInfo = dmd.Debug ? def.DebugInformation : null;
#endif

            if (dm != null)
            {
                foreach (ParameterDefinition param in def.Parameters)
                {
                    dm.DefineParameter(param.Index + 1, (System.Reflection.ParameterAttributes)param.Attributes, param.Name);
                }
            }
#if !NETSTANDARD
            if (mb != null)
            {
                foreach (ParameterDefinition param in def.Parameters)
                {
                    mb.DefineParameter(param.Index + 1, (System.Reflection.ParameterAttributes)param.Attributes, param.Name);
                }
            }
#endif

            LocalBuilder[] locals = def.Body.Variables.Select(
                var => {
                LocalBuilder local = il.DeclareLocal(var.VariableType.ResolveReflection(), var.IsPinned);
#if !NETSTANDARD && !CECIL0_9
                if (mb != null && defInfo != null && defInfo.TryGetName(var, out string name))
                {
                    local.SetLocalSymInfo(name);
                }
#endif
                return(local);
            }
                ).ToArray();

            // Pre-pass - Set up label map.
            Dictionary <Instruction, Label> labelMap = new Dictionary <Instruction, Label>();
            foreach (Instruction instr in def.Body.Instructions)
            {
                if (instr.Operand is Instruction[] targets)
                {
                    foreach (Instruction target in targets)
                    {
                        if (!labelMap.ContainsKey(target))
                        {
                            labelMap[target] = il.DefineLabel();
                        }
                    }
                }
                else if (instr.Operand is Instruction target)
                {
                    if (!labelMap.ContainsKey(target))
                    {
                        labelMap[target] = il.DefineLabel();
                    }
                }
            }

#if !NETSTANDARD && !CECIL0_9
            Dictionary <Document, ISymbolDocumentWriter> infoDocCache = mb == null ? null : new Dictionary <Document, ISymbolDocumentWriter>();
#endif

            int      paramOffs        = def.HasThis ? 1 : 0;
            object[] emitArgs         = new object[2];
            bool     checkTryEndEarly = false;
            foreach (Instruction instr in def.Body.Instructions)
            {
                if (labelMap.TryGetValue(instr, out Label label))
                {
                    il.MarkLabel(label);
                }

#if !NETSTANDARD && !CECIL0_9
                SequencePoint instrInfo = defInfo?.GetSequencePoint(instr);
                if (mb != null && instrInfo != null)
                {
                    if (!infoDocCache.TryGetValue(instrInfo.Document, out ISymbolDocumentWriter infoDoc))
                    {
                        infoDocCache[instrInfo.Document] = infoDoc = moduleBuilder.DefineDocument(
                            instrInfo.Document.Url,
                            instrInfo.Document.LanguageGuid,
                            instrInfo.Document.LanguageVendorGuid,
                            instrInfo.Document.TypeGuid
                            );
                    }
                    il.MarkSequencePoint(infoDoc, instrInfo.StartLine, instrInfo.StartColumn, instrInfo.EndLine, instrInfo.EndColumn);
                }
#endif

                foreach (ExceptionHandler handler in def.Body.ExceptionHandlers)
                {
                    if (checkTryEndEarly && handler.HandlerEnd == instr)
                    {
                        il.EndExceptionBlock();
                    }

                    if (handler.TryStart == instr)
                    {
                        il.BeginExceptionBlock();
                    }
                    else if (handler.FilterStart == instr)
                    {
                        il.BeginExceptFilterBlock();
                    }
                    else if (handler.HandlerStart == instr)
                    {
                        switch (handler.HandlerType)
                        {
                        case ExceptionHandlerType.Filter:
                            il.BeginCatchBlock(null);
                            break;

                        case ExceptionHandlerType.Catch:
                            il.BeginCatchBlock(handler.CatchType.ResolveReflection());
                            break;

                        case ExceptionHandlerType.Finally:
                            il.BeginFinallyBlock();
                            break;

                        case ExceptionHandlerType.Fault:
                            il.BeginFaultBlock();
                            break;
                        }
                    }

                    // Avoid duplicate endfilter / endfinally
                    if (handler.HandlerStart == instr.Next)
                    {
                        switch (handler.HandlerType)
                        {
                        case ExceptionHandlerType.Filter:
                            if (instr.OpCode == Mono.Cecil.Cil.OpCodes.Endfilter)
                            {
                                goto SkipEmit;
                            }
                            break;

                        case ExceptionHandlerType.Finally:
                            if (instr.OpCode == Mono.Cecil.Cil.OpCodes.Endfinally)
                            {
                                goto SkipEmit;
                            }
                            break;
                        }
                    }
                }

                if (instr.OpCode.OperandType == Mono.Cecil.Cil.OperandType.InlineNone)
                {
                    il.Emit(_ReflOpCodes[instr.OpCode.Value]);
                }
                else
                {
                    object operand = instr.Operand;

                    if (operand is Instruction[] targets)
                    {
                        operand = targets.Select(target => labelMap[target]).ToArray();
                        // Let's hope that the JIT treats the long forms identically to the short forms.
                        instr.OpCode = instr.OpCode.ToLongOp();
                    }
                    else if (operand is Instruction target)
                    {
                        operand = labelMap[target];
                        // Let's hope that the JIT treats the long forms identically to the short forms.
                        instr.OpCode = instr.OpCode.ToLongOp();
                    }
                    else if (operand is VariableDefinition var)
                    {
                        operand = locals[var.Index];
                    }
                    else if (operand is ParameterDefinition param)
                    {
                        operand = param.Index + paramOffs;
                    }
                    else if (operand is MemberReference mref)
                    {
                        MemberInfo member = mref.ResolveReflection();
                        operand = member;
#if !NETSTANDARD
                        if (mb != null && member != null)
                        {
                            Assembly asm = member.Module?.Assembly;
                            if (asm != null && !accessChecksIgnored.Contains(asm))
                            {
                                // while (member.DeclaringType != null)
                                //     member = member.DeclaringType;
                                assemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(DynamicMethodDefinition.c_IgnoresAccessChecksToAttribute, new object[] {
                                    asm.GetName().Name
                                }));
                                accessChecksIgnored.Add(asm);
                            }
                        }
#endif
                    }
                    else if (operand is CallSite csite)
                    {
                        if (dm != null)
                        {
                            // SignatureHelper in unmanaged contexts cannot be fully made use of for DynamicMethods.
                            _EmitCallSite(dm, il, _ReflOpCodes[instr.OpCode.Value], csite);
                            continue;
                        }
#if !NETSTANDARD
                        operand = csite.ResolveReflection(mb.Module);
#else
                        throw new NotSupportedException();
#endif
                    }

#if !NETSTANDARD
                    if (mb != null && operand is MethodBase called && called.DeclaringType == null)
                    {
                        // "Global" methods (f.e. DynamicMethods) cannot be tokenized.
                        if (instr.OpCode == Mono.Cecil.Cil.OpCodes.Call)
                        {
                            if (operand is DynamicMethod target)
                            {
                                // This should be heavily optimizable.
                                operand = _CreateMethodProxy(mb, target);
                            }
                            else
                            {
                                IntPtr ptr = called.GetLdftnPointer();
                                if (IntPtr.Size == 4)
                                {
                                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)ptr);
                                }
                                else
                                {
                                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_I8, (long)ptr);
                                }
                                il.Emit(System.Reflection.Emit.OpCodes.Conv_I);
                                instr.OpCode = Mono.Cecil.Cil.OpCodes.Calli;
                                operand      = ((MethodReference)instr.Operand).ResolveReflectionSignature(mb.Module);
                            }
                        }
                        else
                        {
                            throw new NotSupportedException($"Unsupported global method operand on opcode {instr.OpCode.Name}");
                        }
                    }
#endif

                    if (operand == null)
                    {
                        throw new NullReferenceException($"Unexpected null in {def} @ {instr}");
                    }

                    il.DynEmit(_ReflOpCodes[instr.OpCode.Value], operand);
                }

                if (!checkTryEndEarly)
                {
                    foreach (ExceptionHandler handler in def.Body.ExceptionHandlers)
                    {
                        if (handler.HandlerEnd == instr.Next)
                        {
                            il.EndExceptionBlock();
                        }
                    }
                }

                checkTryEndEarly = false;
                continue;

SkipEmit:
                checkTryEndEarly = true;
                continue;
            }
        }
Beispiel #9
0
        private static FastReflectionDelegate _CreateFastDelegate(MethodBase method, bool directBoxValueAccess = true)
        {
            DynamicMethodDefinition dmd = new DynamicMethodDefinition($"FastReflection<{method.GetID(simple: true)}>", typeof(object), _DynamicMethodDelegateArgs);
            ILProcessor             il  = dmd.GetILProcessor();

            ParameterInfo[] args = method.GetParameters();

            bool generateLocalBoxValuePtr = true;

            if (!method.IsStatic)
            {
                il.Emit(OpCodes.Ldarg_0);
                if (method.DeclaringType.IsValueType)
                {
                    il.Emit(OpCodes.Unbox_Any, method.DeclaringType);
                }
            }

            for (int i = 0; i < args.Length; i++)
            {
                Type argType    = args[i].ParameterType;
                bool argIsByRef = argType.IsByRef;
                if (argIsByRef)
                {
                    argType = argType.GetElementType();
                }
                bool argIsValueType = argType.IsValueType;

                if (argIsByRef && argIsValueType && !directBoxValueAccess)
                {
                    // Used later when storing back the reference to the new box in the array.
                    il.Emit(OpCodes.Ldarg_1);
                    il.Emit(OpCodes.Ldc_I4, i);
                }

                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Ldc_I4, i);

                if (argIsByRef && !argIsValueType)
                {
                    il.Emit(OpCodes.Ldelema, typeof(object));
                }
                else
                {
                    il.Emit(OpCodes.Ldelem_Ref);
                    if (argIsValueType)
                    {
                        if (!argIsByRef || !directBoxValueAccess)
                        {
                            // if !directBoxValueAccess, create a new box if required
                            il.Emit(OpCodes.Unbox_Any, argType);
                            if (argIsByRef)
                            {
                                // box back
                                il.Emit(OpCodes.Box, argType);

                                // store new box value address to local 0
                                il.Emit(OpCodes.Dup);
                                il.Emit(OpCodes.Unbox, argType);
                                if (generateLocalBoxValuePtr)
                                {
                                    generateLocalBoxValuePtr = false;
                                    dmd.Definition.Body.Variables.Add(new VariableDefinition(new PinnedType(new PointerType(dmd.Definition.Module.TypeSystem.Void))));
                                }
                                il.Emit(OpCodes.Stloc_0);

                                // arr and index set up already
                                il.Emit(OpCodes.Stelem_Ref);

                                // load address back to stack
                                il.Emit(OpCodes.Ldloc_0);
                            }
                        }
                        else
                        {
                            // if directBoxValueAccess, emit unbox (get value address)
                            il.Emit(OpCodes.Unbox, argType);
                        }
                    }
                }
            }

            if (method.IsConstructor)
            {
                il.Emit(OpCodes.Newobj, method as ConstructorInfo);
            }
            else if (method.IsFinal || !method.IsVirtual)
            {
                il.Emit(OpCodes.Call, method as MethodInfo);
            }
            else
            {
                il.Emit(OpCodes.Callvirt, method as MethodInfo);
            }

            Type returnType = method.IsConstructor ? method.DeclaringType : (method as MethodInfo).ReturnType;

            if (returnType != typeof(void))
            {
                if (returnType.IsValueType)
                {
                    il.Emit(OpCodes.Box, returnType);
                }
            }
            else
            {
                il.Emit(OpCodes.Ldnull);
            }

            il.Emit(OpCodes.Ret);

            return((FastReflectionDelegate)dmd.Generate().CreateDelegate(typeof(FastReflectionDelegate)));
        }
Beispiel #10
0
 public static MethodInfo Generate(DynamicMethodDefinition dmd, object context = null)
 => _Postbuild((_Instance ?? (_Instance = new TSelf()))._Generate(dmd, context));
Beispiel #11
0
 MethodInfo _IDMDGenerator.Generate(DynamicMethodDefinition dmd, object context)
 {
     return(_Postbuild(_Generate(dmd, context)));
 }
Beispiel #12
0
 protected abstract MethodInfo _Generate(DynamicMethodDefinition dmd, object context);
        protected override MethodInfo _Generate(DynamicMethodDefinition dmd, object context)
        {
            MethodBase       orig = dmd.OriginalMethod;
            MethodDefinition def  = dmd.Definition;

            Type[] argTypes;

            if (orig != null)
            {
                ParameterInfo[] args = orig.GetParameters();
                int             offs = 0;
                if (!orig.IsStatic)
                {
                    offs++;
                    argTypes    = new Type[args.Length + 1];
                    argTypes[0] = orig.GetThisParamType();
                }
                else
                {
                    argTypes = new Type[args.Length];
                }
                for (int i = 0; i < args.Length; i++)
                {
                    argTypes[i + offs] = args[i].ParameterType;
                }
            }
            else
            {
                int offs = 0;
                if (def.HasThis)
                {
                    offs++;
                    argTypes = new Type[def.Parameters.Count + 1];
                    Type type = def.DeclaringType.ResolveReflection();
                    if (type.IsValueType)
                    {
                        type = type.MakeByRefType();
                    }
                    argTypes[0] = type;
                }
                else
                {
                    argTypes = new Type[def.Parameters.Count];
                }
                for (int i = 0; i < def.Parameters.Count; i++)
                {
                    argTypes[i + offs] = def.Parameters[i].ParameterType.ResolveReflection();
                }
            }

            DynamicMethod dm = new DynamicMethod(
                $"DMD<{orig?.GetID(simple: true) ?? def.GetID(simple: true)}>",
                typeof(void), argTypes,
                orig?.DeclaringType ?? typeof(DynamicMethodDefinition),
                true // If any random errors pop up, try setting this to false first.
                );

            // DynamicMethods don't officially "support" certain return types, such as ByRef types.
            _DynamicMethod_returnType.SetValue(dm, (orig as MethodInfo)?.ReturnType ?? def.ReturnType?.ResolveReflection());

            ILGenerator il = dm.GetILGenerator();

            _DMDEmit.Generate(dmd, dm, il);

            return(dm);
        }
        protected override MethodInfo _Generate(DynamicMethodDefinition dmd, object context)
        {
            MethodBase       orig = dmd.OriginalMethod;
            MethodDefinition def  = dmd.Definition;

            Type[] argTypes;

            if (orig != null)
            {
                ParameterInfo[] args = orig.GetParameters();
                int             offs = 0;
                if (!orig.IsStatic)
                {
                    offs++;
                    argTypes    = new Type[args.Length + 1];
                    argTypes[0] = orig.GetThisParamType();
                }
                else
                {
                    argTypes = new Type[args.Length];
                }
                for (int i = 0; i < args.Length; i++)
                {
                    argTypes[i + offs] = args[i].ParameterType;
                }
            }
            else
            {
                int offs = 0;
                if (def.HasThis)
                {
                    offs++;
                    argTypes = new Type[def.Parameters.Count + 1];
                    Type type = def.DeclaringType.ResolveReflection();
                    if (type.IsValueType)
                    {
                        type = type.MakeByRefType();
                    }
                    argTypes[0] = type;
                }
                else
                {
                    argTypes = new Type[def.Parameters.Count];
                }
                for (int i = 0; i < def.Parameters.Count; i++)
                {
                    argTypes[i + offs] = def.Parameters[i].ParameterType.ResolveReflection();
                }
            }

            string name    = dmd.Name ?? $"DMD<{orig?.GetID(simple: true) ?? def.GetID(simple: true)}>";
            Type   retType = (orig as MethodInfo)?.ReturnType ?? def.ReturnType?.ResolveReflection();

            MMDbgLog.Log($"new DynamicMethod: {retType} {name}({string.Join(",", argTypes.Select(type => type?.ToString()).ToArray())})");
            if (orig != null)
            {
                MMDbgLog.Log($"orig: {(orig as MethodInfo)?.ReturnType?.ToString() ?? "NULL"} {orig.Name}({string.Join(",", orig.GetParameters().Select(arg => arg?.ParameterType?.ToString() ?? "NULL").ToArray())})");
            }
            MMDbgLog.Log($"mdef: {def.ReturnType?.ToString() ?? "NULL"} {name}({string.Join(",", def.Parameters.Select(arg => arg?.ParameterType?.ToString() ?? "NULL").ToArray())})");

            DynamicMethod dm = new DynamicMethod(
                name,
                typeof(void), argTypes,
                orig?.DeclaringType ?? dmd.OwnerType ?? typeof(DynamicMethodDefinition),
                true // If any random errors pop up, try setting this to false first.
                );

            // DynamicMethods don't officially "support" certain return types, such as ByRef types.
            _DynamicMethod_returnType.SetValue(dm, retType);

            ILGenerator il = dm.GetILGenerator();

            _DMDEmit.Generate(dmd, dm, il);

            return(dm);
        }