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); }
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>)()); } }
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>)()); } }
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 } }
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);
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; } }
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))); }
public static MethodInfo Generate(DynamicMethodDefinition dmd, object context = null) => _Postbuild((_Instance ?? (_Instance = new TSelf()))._Generate(dmd, context));
MethodInfo _IDMDGenerator.Generate(DynamicMethodDefinition dmd, object context) { return(_Postbuild(_Generate(dmd, context))); }
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); }