/// <summary> /// Creates a dynamic detour method of the specified delegate type to wrap a base game /// method with the specified name. The dynamic method will automatically adapt if /// optional parameters are added, filling in their default values. /// </summary> /// <typeparam name="D">The delegate type to be used to call the detour.</typeparam> /// <param name="target">The target method to be called.</param> /// <returns>The detour that will call that method.</returns> /// <exception cref="DetourException">If the delegate does not match the target.</exception> public static D Detour <D>(this MethodInfo target) where D : Delegate { if (target == null) { throw new ArgumentNullException("target"); } if (target.ContainsGenericParameters) { throw new ArgumentException("Generic types must have all parameters defined"); } var expected = DelegateInfo.Create(typeof(D)); var parentType = target.DeclaringType; var expectedParamTypes = expected.ParameterTypes; var actualParams = ValidateDelegate(expected, target); int offset = target.IsStatic ? 0 : 1; // Method will be "declared" in the type of the target, as we are detouring around // a method of that type var caller = new DynamicMethod(target.Name + "_Detour", expected.ReturnType, expectedParamTypes, parentType, true); var generator = caller.GetILGenerator(); // Load the known method arguments onto the stack int n = expectedParamTypes.Length, need = actualParams.Length + offset; if (n > 0) { generator.Emit(OpCodes.Ldarg_0); } if (n > 1) { generator.Emit(OpCodes.Ldarg_1); } if (n > 2) { generator.Emit(OpCodes.Ldarg_2); } if (n > 3) { generator.Emit(OpCodes.Ldarg_3); } for (int i = 4; i < n; i++) { generator.Emit(OpCodes.Ldarg_S, i); } // Load the rest as defaults for (int i = n; i < need; i++) { var param = actualParams[i - offset]; PTranspilerTools.GenerateDefaultLoad(generator, param.ParameterType, param. DefaultValue); } if (parentType.IsValueType || target.IsStatic) { generator.Emit(OpCodes.Call, target); } else { generator.Emit(OpCodes.Callvirt, target); } generator.Emit(OpCodes.Ret); // Define the parameter names, parameter indexes start at 1 if (offset > 0) { caller.DefineParameter(1, ParameterAttributes.None, "this"); } for (int i = offset; i < n; i++) { var oldParam = actualParams[i - offset]; caller.DefineParameter(i + 1, oldParam.Attributes, oldParam.Name); } #if DEBUG PUtil.LogDebug("Created delegate {0} for method {1}.{2} with parameters [{3}]". F(caller.Name, parentType.FullName, target.Name, actualParams.Join(","))); #endif return(caller.CreateDelegate(typeof(D)) as D); }
public static void Main() { // Create an array that specifies the types of the parameters // of the dynamic method. This dynamic method has a String // parameter and an Integer parameter. Type[] helloArgs = { typeof(string), typeof(int) }; // Create a dynamic method with the name "Hello", a return type // of Integer, and two parameters whose types are specified by // the array helloArgs. Create the method in the module that // defines the String class. DynamicMethod hello = new DynamicMethod("Hello", typeof(int), helloArgs, typeof(string).Module); // Create an array that specifies the parameter types of the // overload of Console.WriteLine to be used in Hello. Type[] writeStringArgs = { typeof(string) }; // Get the overload of Console.WriteLine that has one // String parameter. MethodInfo writeString = typeof(Console).GetMethod("WriteLine", writeStringArgs); // Get an ILGenerator and emit a body for the dynamic method, // using a stream size larger than the IL that will be // emitted. ILGenerator il = hello.GetILGenerator(256); // Load the first argument, which is a string, onto the stack. il.Emit(OpCodes.Ldarg_0); // Call the overload of Console.WriteLine that prints a string. il.EmitCall(OpCodes.Call, writeString, null); // The Hello method returns the value of the second argument; // to do this, load the onto the stack and return. il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ret); // Add parameter information to the dynamic method. (This is not // necessary, but can be useful for debugging.) For each parameter, // identified by position, supply the parameter attributes and a // parameter name. hello.DefineParameter(1, ParameterAttributes.In, "message"); hello.DefineParameter(2, ParameterAttributes.In, "valueToReturn"); // Create a delegate that represents the dynamic method. This // action completes the method. Any further attempts to // change the method are ignored. HelloDelegate hi = (HelloDelegate)hello.CreateDelegate(typeof(HelloDelegate)); // Use the delegate to execute the dynamic method. Console.WriteLine("\r\nUse the delegate to execute the dynamic method:"); int retval = hi("\r\nHello, World!", 42); Console.WriteLine("Invoking delegate hi(\"Hello, World!\", 42) returned: " + retval); // Execute it again, with different arguments. retval = hi("\r\nHi, Mom!", 5280); Console.WriteLine("Invoking delegate hi(\"Hi, Mom!\", 5280) returned: " + retval); Console.WriteLine("\r\nUse the Invoke method to execute the dynamic method:"); // Create an array of arguments to use with the Invoke method. object[] invokeArgs = { "\r\nHello, World!", 42 }; // Invoke the dynamic method using the arguments. This is much // slower than using the delegate, because you must create an // array to contain the arguments, and value-type arguments // must be boxed. object objRet = hello.Invoke(null, BindingFlags.ExactBinding, null, invokeArgs, new CultureInfo("en-us")); Console.WriteLine("hello.Invoke returned: " + objRet); Console.WriteLine("\r\n ----- Display information about the dynamic method -----"); // Display MethodAttributes for the dynamic method, set when // the dynamic method was created. Console.WriteLine("\r\nMethod Attributes: {0}", hello.Attributes); // Display the calling convention of the dynamic method, set when the // dynamic method was created. Console.WriteLine("\r\nCalling convention: {0}", hello.CallingConvention); // Display the declaring type, which is always null for dynamic // methods. if (hello.DeclaringType == null) { Console.WriteLine("\r\nDeclaringType is always null for dynamic methods."); } else { Console.WriteLine("DeclaringType: {0}", hello.DeclaringType); } // Display the default value for InitLocals. if (hello.InitLocals) { Console.Write("\r\nThis method contains verifiable code."); } else { Console.Write("\r\nThis method contains unverifiable code."); } Console.WriteLine(" (InitLocals = {0})", hello.InitLocals); // Display the module specified when the dynamic method was created. Console.WriteLine("\r\nModule: {0}", hello.Module); // Display the name specified when the dynamic method was created. // Note that the name can be blank. Console.WriteLine("\r\nName: {0}", hello.Name); // For dynamic methods, the reflected type is always null. if (hello.ReflectedType == null) { Console.WriteLine("\r\nReflectedType is null."); } else { Console.WriteLine("\r\nReflectedType: {0}", hello.ReflectedType); } if (hello.ReturnParameter == null) { Console.WriteLine("\r\nMethod has no return parameter."); } else { Console.WriteLine("\r\nReturn parameter: {0}", hello.ReturnParameter); } // If the method has no return type, ReturnType is System.Void. Console.WriteLine("\r\nReturn type: {0}", hello.ReturnType); // ReturnTypeCustomAttributes returns an ICustomeAttributeProvider // that can be used to enumerate the custom attributes of the // return value. At present, there is no way to set such custom // attributes, so the list is empty. if (hello.ReturnType == typeof(void)) { Console.WriteLine("The method has no return type."); } else { ICustomAttributeProvider caProvider = hello.ReturnTypeCustomAttributes; object[] returnAttributes = caProvider.GetCustomAttributes(true); if (returnAttributes.Length == 0) { Console.WriteLine("\r\nThe return type has no custom attributes."); } else { Console.WriteLine("\r\nThe return type has the following custom attributes:"); foreach (object attr in returnAttributes) { Console.WriteLine("\t{0}", attr.ToString()); } } } Console.WriteLine("\r\nToString: {0}", hello.ToString()); // Display parameter information. ParameterInfo[] parameters = hello.GetParameters(); Console.WriteLine("\r\nParameters: name, type, ParameterAttributes"); foreach (ParameterInfo p in parameters) { Console.WriteLine("\t{0}, {1}, {2}", p.Name, p.ParameterType, p.Attributes); } }
private static void GenerateSerializeMethod() { object[] @namespace = new object[] { typeof(SerializeWriterHelper <Type, W>).Namespace, typeof(SerializeWriterHelper <Type, W>).Name, typeof(T).Namespace, typeof(T).Name }; string str = string.Format("{0}.{1}.SerializeCore[{2}.{3}]", @namespace); Type[] typeArray = new Type[] { typeof(W).MakeByRefType(), typeof(T) }; DynamicMethod dynamicMethod = new DynamicMethod(str, null, typeArray, typeof(SerializeWriterHelper <T, W>), true); dynamicMethod.DefineParameter(1, ParameterAttributes.In | ParameterAttributes.Out, "writer"); dynamicMethod.DefineParameter(2, ParameterAttributes.In, "value"); ILGenerator lGenerator = dynamicMethod.GetILGenerator(); Type baseType = typeof(T); if (!baseType.IsSerializable && SerializeWriterHelper <T, W> .FindDefinedSerializeMethod(baseType) == null) { throw new SerializationException(string.Format("Type is not serializable: {0}", baseType.AssemblyQualifiedName)); } Label?nullable = null; if (!baseType.IsValueType && SerializeWriterHelper <T, W> .FindDefinedSerializeMethod(baseType) == null) { MethodInfo method = SerializeWriterHelper <T, W> .FindDefinedSerializeMethod(typeof(bool)); if (method == null) { Type type = typeof(SerializeWriterHelper <,>); Type[] typeArray1 = new Type[] { typeof(bool), typeof(W) }; method = type.MakeGenericType(typeArray1).GetMethod("Serialize"); } lGenerator.Emit(OpCodes.Ldarg_0); lGenerator.Emit(OpCodes.Ldarg_1); lGenerator.Emit(OpCodes.Ldnull); lGenerator.Emit(OpCodes.Ceq); lGenerator.Emit(OpCodes.Ldc_I4_0); lGenerator.Emit(OpCodes.Ceq); lGenerator.EmitCall(OpCodes.Call, method, null); lGenerator.Emit(OpCodes.Ldarg_1); nullable = new Label?(lGenerator.DefineLabel()); lGenerator.Emit(OpCodes.Brfalse, nullable.Value); } Stack <Type> types = new Stack <Type>(); while (true) { if (baseType != null) { MethodInfo methodInfo = SerializeWriterHelper <T, W> .FindDefinedSerializeMethod(baseType); if (methodInfo == null) { if (baseType.IsSerializable) { types.Push(baseType); } baseType = baseType.BaseType; } else { SerializeWriterHelper <T, W> .EmitWritePredefinedType(lGenerator, methodInfo); break; } } else { break; } } while (0 < types.Count) { SerializeWriterHelper <T, W> .EmitWriteFields(lGenerator, types.Pop()); } if (nullable.HasValue) { lGenerator.MarkLabel(nullable.Value); } lGenerator.Emit(OpCodes.Ret); SerializeWriterHelper <T, W> .serializeCore = dynamicMethod.CreateDelegate(typeof(SerializeWriterHelper <T, W> .SerializeDelegate)) as SerializeWriterHelper <T, W> .SerializeDelegate; if (typeof(T).IsSealed || SerializeWriterHelper <T, W> .FindDefinedSerializeMethod(typeof(T)) != null) { SerializeWriterHelper <T, W> .serialize = SerializeWriterHelper <T, W> .serializeCore; return; } SerializeWriterHelper <T, W> .serialize = new SerializeWriterHelper <T, W> .SerializeDelegate(SerializeWriterHelper <T, W> .SerializeCoreVirtual); }
private static DynamicMethod CreateIl2CppShim(DynamicMethod patch, MethodBase original) { var patchName = patch.Name + "_il2cpp"; var parameters = patch.GetParameters(); var result = parameters.Types().ToList(); var origParamTypes = result.ToArray(); var paramTypes = new Type[origParamTypes.Length]; for (int i = 0; i < paramTypes.Length; ++i) { paramTypes[i] = Il2CppTypeForPatchType(origParamTypes[i]); } var origReturnType = AccessTools.GetReturnedType(patch); var returnType = Il2CppTypeForPatchType(origReturnType); DynamicMethod method = new DynamicMethod( patchName, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, returnType, paramTypes, original.DeclaringType, true ); for (var i = 0; i < parameters.Length; i++) { method.DefineParameter(i + 1, parameters[i].Attributes, parameters[i].Name); } var il = method.GetILGenerator(); LocalBuilder[] byRefValues = new LocalBuilder[parameters.Length]; LocalBuilder returnLocal = null; if (origReturnType != typeof(void)) { returnLocal = il.DeclareLocal(origReturnType); Emitter.LogLocalVariable(il, returnLocal); } LocalBuilder exceptionLocal = il.DeclareLocal(typeof(Exception)); Emitter.LogLocalVariable(il, exceptionLocal); // Start a try-block for the call to the original patch Emitter.MarkBlockBefore(il, new ExceptionBlock(ExceptionBlockType.BeginExceptionBlock, null), out _); // Load arguments, invoking the IntPrt -> Il2CppObject constructor for IL2CPP types for (int i = 0; i < origParamTypes.Length; ++i) { Emitter.Emit(il, OpCodes.Ldarg, i); ConvertArgument(il, origParamTypes[i], ref byRefValues[i]); if (byRefValues[i] != null) { Emitter.LogLocalVariable(il, byRefValues[i]); } } // Call the original patch with the now-correct types Emitter.Emit(il, OpCodes.Call, patch); // Store the result, if any if (returnLocal != null) { Emitter.Emit(il, OpCodes.Stloc, returnLocal); } // Catch any exceptions that may have been thrown Emitter.MarkBlockBefore(il, new ExceptionBlock(ExceptionBlockType.BeginCatchBlock, typeof(Exception)), out _); // CumLogger.LogError("Exception in ...\n" + exception.ToString()); Emitter.Emit(il, OpCodes.Stloc, exceptionLocal); Emitter.Emit(il, OpCodes.Ldstr, $"Exception in Harmony patch of method {original.FullDescription()}:\n"); Emitter.Emit(il, OpCodes.Ldloc, exceptionLocal); Emitter.Emit(il, OpCodes.Call, AccessTools.DeclaredMethod(typeof(Exception), "ToString", new Type[0])); Emitter.Emit(il, OpCodes.Call, AccessTools.DeclaredMethod(typeof(string), "Concat", new Type[] { typeof(string), typeof(string) })); Emitter.Emit(il, OpCodes.Call, AccessTools.DeclaredMethod(typeof(CumLogger), "LogError", new Type[] { typeof(string) })); // Close the exception block Emitter.MarkBlockAfter(il, new ExceptionBlock(ExceptionBlockType.EndExceptionBlock, null)); // Write back the pointers of ref arguments for (int i = 0; i < parameters.Length; ++i) { if (byRefValues[i] == null) { continue; } Emitter.Emit(il, OpCodes.Ldarg, i); // -> [intptr*] Emitter.Emit(il, OpCodes.Ldloc, byRefValues[i]); // -> [intptr*, obj] if (origParamTypes[i].GetElementType() == typeof(string)) { Emitter.Emit(il, OpCodes.Call, UnhollowerSupport.ManagedStringToIl2CppMethod); // -> [intptr*, intptr] } else { Emitter.Emit(il, OpCodes.Call, UnhollowerSupport.Il2CppObjectBaseToPtrMethod); // -> [intptr*, intptr] } Emitter.Emit(il, OpCodes.Stind_I); // -> [] } // Load the return value, if any, and unwrap it if required if (returnLocal != null) { Emitter.Emit(il, OpCodes.Ldloc, returnLocal); ConvertReturnValue(il, origReturnType); } Emitter.Emit(il, OpCodes.Ret); DynamicTools.PrepareDynamicMethod(method); return(method); }
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) { if (mref is DynamicMethodReference dmref) { operand = dmref.DynamicMethod; } else { MemberInfo member = mref.ResolveReflection(); operand = member; #if !NETSTANDARD if (mb != null && member != null) { Assembly asm = member.Module.Assembly; if (!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; } }
/// <summary> /// Define a method in this module with the specified name and parameters. /// </summary> public MethodInfo DefineMethod(string name, Type returnType, Type[] paramTypes, string[] paramNames, XmlILMethodAttributes xmlAttrs) { MethodInfo methResult; int uniqueId = 1; string nameOrig = name; Type[] paramTypesNew; bool isRaw = (xmlAttrs & XmlILMethodAttributes.Raw) != 0; // Ensure that name is unique while (this.methods[name] != null) { // Add unique id to end of name in order to make it unique within this module uniqueId++; name = nameOrig + " (" + uniqueId + ")"; } if (!isRaw) { // XmlQueryRuntime is always 0th parameter paramTypesNew = new Type[paramTypes.Length + 1]; paramTypesNew[0] = typeof(XmlQueryRuntime); Array.Copy(paramTypes, 0, paramTypesNew, 1, paramTypes.Length); paramTypes = paramTypesNew; } if (!this.useLRE) { MethodBuilder methBldr; methBldr = this.typeBldr.DefineMethod( name, MethodAttributes.Private | MethodAttributes.Static, returnType, paramTypes); if (emitSymbols && (xmlAttrs & XmlILMethodAttributes.NonUser) != 0) { // Add DebuggerStepThroughAttribute and DebuggerNonUserCodeAttribute to non-user methods so that debugging is a better experience methBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.StepThrough, new object[] {})); methBldr.SetCustomAttribute(new CustomAttributeBuilder(XmlILConstructors.NonUserCode, new object[] {})); } if (!isRaw) { methBldr.DefineParameter(1, ParameterAttributes.None, RuntimeName); } for (int i = 0; i < paramNames.Length; i++) { if (paramNames[i] != null && paramNames[i].Length != 0) { methBldr.DefineParameter(i + (isRaw ? 1 : 2), ParameterAttributes.None, paramNames[i]); } } methResult = methBldr; } else { DynamicMethod methDyn = new DynamicMethod(name, returnType, paramTypes, LREModule); methDyn.InitLocals = true; if (!isRaw) { methDyn.DefineParameter(1, ParameterAttributes.None, RuntimeName); } for (int i = 0; i < paramNames.Length; i++) { if (paramNames[i] != null && paramNames[i].Length != 0) { methDyn.DefineParameter(i + (isRaw ? 1 : 2), ParameterAttributes.None, paramNames[i]); } } methResult = methDyn; } // Index method by name this.methods[name] = methResult; return(methResult); }
private static void CreateDynamicAssembly() { // 1. Assert permissions demanded by the DynamicMethod ctor. new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Assert(); // BlessedAssert // 2. Create the transparent methods, each wrapping a call to a reflection method, // and cache a delegate to each method. Type[] parameterTypes; // signature of the reflection method Type[] wrappedParameterTypes; // signature of the wrapping method (when different) MethodInfo mi; // descriptor for the reflection method DynamicMethod method; // wrapping method ILGenerator il; // wrapping method's generator // 2a. Delegate.CreateDelegate( Type, Type, String ) parameterTypes = new Type[] { typeof(Type), typeof(Type), typeof(String) }; mi = typeof(Delegate).GetMethod("CreateDelegate", parameterTypes); method = new DynamicMethod("CreateDelegate", typeof(Delegate), parameterTypes); method.DefineParameter(1, ParameterAttributes.In, "delegateType"); method.DefineParameter(2, ParameterAttributes.In, "targetType"); method.DefineParameter(3, ParameterAttributes.In, "methodName"); il = method.GetILGenerator(5); il.Emit(OpCodes.Ldarg_0); // push delegateType il.Emit(OpCodes.Ldarg_1); // push targetType il.Emit(OpCodes.Ldarg_2); // push methodName il.EmitCall(OpCodes.Call, mi, null); // call Delegate.CreateDelegate il.Emit(OpCodes.Ret); // return the result s_CreateDelegate1 = (CreateDelegate1Delegate)method.CreateDelegate(typeof(CreateDelegate1Delegate)); // 2b. Delegate.CreateDelegate( Type, Object, String ) parameterTypes = new Type[] { typeof(Type), typeof(Object), typeof(String) }; mi = typeof(Delegate).GetMethod("CreateDelegate", parameterTypes); method = new DynamicMethod("CreateDelegate", typeof(Delegate), parameterTypes); method.DefineParameter(1, ParameterAttributes.In, "delegateType"); method.DefineParameter(2, ParameterAttributes.In, "target"); method.DefineParameter(3, ParameterAttributes.In, "methodName"); il = method.GetILGenerator(5); il.Emit(OpCodes.Ldarg_0); // push delegateType il.Emit(OpCodes.Ldarg_1); // push target il.Emit(OpCodes.Ldarg_2); // push methodName il.EmitCall(OpCodes.Call, mi, null); // call Delegate.CreateDelegate il.Emit(OpCodes.Ret); // return the result s_CreateDelegate2 = (CreateDelegate2Delegate)method.CreateDelegate(typeof(CreateDelegate2Delegate)); // 2c. Activator.CreateInstance( Type, Object[] ) parameterTypes = new Type[] { typeof(Type), typeof(Object[]) }; mi = typeof(Activator).GetMethod("CreateInstance", parameterTypes); method = new DynamicMethod("CreateInstance", typeof(Object), parameterTypes); method.DefineParameter(1, ParameterAttributes.In, "type"); method.DefineParameter(2, ParameterAttributes.In, "arguments"); il = method.GetILGenerator(4); il.Emit(OpCodes.Ldarg_0); // push type il.Emit(OpCodes.Ldarg_1); // push arguments il.EmitCall(OpCodes.Call, mi, null); // call Activator.CreateInstance il.Emit(OpCodes.Ret); // return the result s_CreateInstance = (CreateInstanceDelegate)method.CreateDelegate(typeof(CreateInstanceDelegate)); // 2d. MethodInfo.Invoke(object, args) parameterTypes = new Type[] { typeof(Object), typeof(Object[]) }; wrappedParameterTypes = new Type[] { typeof(MethodInfo), typeof(Object), typeof(Object[]) }; mi = typeof(MethodInfo).GetMethod("Invoke", parameterTypes); method = new DynamicMethod("InvokeMethod", typeof(Object), wrappedParameterTypes); method.DefineParameter(1, ParameterAttributes.In, "method"); method.DefineParameter(2, ParameterAttributes.In, "instance"); method.DefineParameter(3, ParameterAttributes.In, "args"); il = method.GetILGenerator(5); il.Emit(OpCodes.Ldarg_0); // push method il.Emit(OpCodes.Ldarg_1); // push instance il.Emit(OpCodes.Ldarg_2); // push args il.EmitCall(OpCodes.Callvirt, mi, null); // call method.Invoke il.Emit(OpCodes.Ret); // return the result s_InvokeMethod = (InvokeMethodDelegate)method.CreateDelegate(typeof(InvokeMethodDelegate)); }
/// <summary> /// Creates a dynamic method for testing units. All units take the same parameters. /// </summary> /// <param name="runner">The runner.</param> /// <returns></returns> public static DynamicUnitTiming CreateTestMethod(MethodRunner runner) { // Create the basic signature. var signature = new[] { typeof(object), typeof(int) }; var method = new DynamicMethod("DynamicUnitTest" + (counter++), typeof(void), signature, typeof(MethodRunnerCompiler)); // Create an IL generator for the method body. ILGenerator il = method.GetILGenerator(256); // We determine what type of IL code we generate based on the singleton type. if (runner.TimingAttribute.Singleton) { // Create a single call version. CreateSingleton(runner, il); } else { // Create the local variables. il.DeclareLocal(typeof(int)); il.DeclareLocal(typeof(bool)); // Declare the labels. Label loopLabel = il.DefineLabel(); Label topLabel = il.DefineLabel(); // Assign zero to the count variable. il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Br_S, loopLabel); // Build up the actual execution. il.MarkLabel(topLabel); // Figure out how to call this method. il.Emit(OpCodes.Ldarg_0); switch (runner.MethodSignature) { case MethodSignature.CountInt32: il.Emit(OpCodes.Ldloc_0); break; case MethodSignature.CountIterationInt32: il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldarg_1); break; } il.EmitCall(OpCodes.Call, runner.Method, null); // Increment the counter. il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc_0); // Create the loop test. This loads the count variable and compares // it to the second argument (iterations). il.MarkLabel(loopLabel); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Clt); il.Emit(OpCodes.Stloc_1); il.Emit(OpCodes.Ldloc_1); il.Emit(OpCodes.Brtrue_S, topLabel); } // Finish up with a return IL. il.Emit(OpCodes.Ret); // Create the paramters. method.DefineParameter(0, ParameterAttributes.In, "target"); method.DefineParameter(1, ParameterAttributes.In, "iteration"); // Create the delegate and return it. return((DynamicUnitTiming)method.CreateDelegate(typeof(DynamicUnitTiming))); }
private static DynamicMethod CreateIl2CppShim(DynamicMethod original, Type owner) { var patchName = original.Name + "_il2cpp"; var parameters = original.GetParameters(); var result = parameters.Types().ToList(); var origParamTypes = result.ToArray(); var paramTypes = new Type[origParamTypes.Length]; for (int i = 0; i < paramTypes.Length; ++i) { paramTypes[i] = IsIl2CppType(origParamTypes[i]) ? typeof(IntPtr) : origParamTypes[i]; } var origReturnType = AccessTools.GetReturnedType(original); var returnType = IsIl2CppType(origReturnType) ? typeof(IntPtr) : origReturnType; DynamicMethod method; method = new DynamicMethod( patchName, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, returnType, paramTypes, owner, true ); for (var i = 0; i < parameters.Length; i++) { method.DefineParameter(i + 1, parameters[i].Attributes, parameters[i].Name); } var il = method.GetILGenerator(); // Load arguments, invoking the IntPrt -> Il2CppObject constructor for IL2CPP types for (int i = 0; i < origParamTypes.Length; ++i) { Emitter.Emit(il, OpCodes.Ldarg, i); if (IsIl2CppType(origParamTypes[i])) { Emitter.Emit(il, OpCodes.Newobj, Il2CppConstuctor(origParamTypes[i])); } } // Call the original patch with the now-correct types Emitter.Emit(il, OpCodes.Call, original); // If needed, unwrap the return value; then return if (IsIl2CppType(origReturnType)) { var pointerGetter = AccessTools.DeclaredProperty(typeof(Il2CppObjectBase), "Pointer").GetMethod; Emitter.Emit(il, OpCodes.Call, pointerGetter); } Emitter.Emit(il, OpCodes.Ret); DynamicTools.PrepareDynamicMethod(method); return(method); }
private static Func <InputBitStream <ushort>, ushort> GetBitfieldReader(byte enabledFlags) { if (enabledFlags > 0x1f) { throw new ArgumentOutOfRangeException("enabledFlags"); } // Lazily initialize the bitfield readers if (BitfieldReaders[enabledFlags] == null) { // Lock the array for thread safety lock (BitfieldReaders) { // If the bitfield reader has been compiled while we were waiting for the lock, don't initialize it again! if (BitfieldReaders[enabledFlags] == null) { DynamicMethod method = new DynamicMethod( string.Format(CultureInfo.InvariantCulture, "ReadBitfield<{0}>", enabledFlags), typeof(ushort), new Type[] { typeof(InputBitStream <ushort>) }); method.DefineParameter(0, ParameterAttributes.None, "bitStream"); ILGenerator ilg = method.GetILGenerator(); if (enabledFlags == 0) { ilg.Emit(OpCodes.Ldc_I4_0); } else { // Keep track of how many bits are set, so we can generate the correct number of 'or' instructions int bits = 0; // Loop through the bits for (int i = 4; i >= 0; i--) { // Test bits 4 to 0 if ((enabledFlags & (1 << i)) != 0) { ++bits; // Call InputBitStream<ushort>.Get() ilg.Emit(OpCodes.Ldarg_0); // bitStream ilg.Emit(OpCodes.Callvirt, UShortInputBitStreamGet); // Shift the value by 15 to 11, depending on the bit being tested ilg.Emit(OpCodes.Ldc_I4_S, 11 + i); ilg.Emit(OpCodes.Shl); } } // Decrement by one to keep one value on the stack // For example, if enabledFlags is 0x1f, there will be 5 values on the stack. We want to end up with // one value on the stack, so we must emit 4 'or' instructions. --bits; for (int i = 0; i < bits; i++) { // Emit 'or' instructions ilg.Emit(OpCodes.Or); } } ilg.Emit(OpCodes.Ret); BitfieldReaders[enabledFlags] = (Func <InputBitStream <ushort>, ushort>)method.CreateDelegate( typeof(Func <InputBitStream <ushort>, ushort>)); } } } return(BitfieldReaders[enabledFlags]); }
static Func <T, Action <PropertyChangedEventArgs>?> GetHandlerFinder() { var methods = typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); var methodAndParams = methods .Where(x => (x.Name == "OnPropertyChanged" || x.Name == "RaisePropertyChanged") && x.ReturnType == typeof(void)) .Select(method => (method, parameters: method.GetParameters())) .Where(x => x.parameters.Length == 1) .Select(x => (x.method, param: x.parameters[0])) .OrderBy(x => x.method.Name); // Grant priority for "OnPropertyChanged" foreach (var(method, param) in methodAndParams) { if (param.ParameterType == typeof(PropertyChangedEventArgs)) { // C#: // instance => instance.${method} // IL: // ldarg.0 // #if (is_virtual_method(${method})) // dup // ldvirtftn ${method} // #else // ldftn ${method} // newobj instance void Action<PropertyChangedEventArgs>::.ctor(object, native int) // ret var dynamicMethod = new DynamicMethod("FindHandlerFromMethod", typeof(Action <PropertyChangedEventArgs>), new[] { typeof(T) }, true); dynamicMethod.DefineParameter(1, ParameterAttributes.In, "instance"); var ilGenerator = dynamicMethod.GetILGenerator(); ilGenerator.Emit(OpCodes.Ldarg_0); if (method.IsVirtual) { ilGenerator.Emit(OpCodes.Dup); ilGenerator.Emit(OpCodes.Ldvirtftn, method); } else { ilGenerator.Emit(OpCodes.Ldftn, method); } ilGenerator.Emit(OpCodes.Newobj, typeof(Action <PropertyChangedEventArgs>).GetConstructor(new[] { typeof(object), typeof(IntPtr) }) !); ilGenerator.Emit(OpCodes.Ret); return((Func <T, Action <PropertyChangedEventArgs> >)dynamicMethod.CreateDelegate(typeof(Func <T, Action <PropertyChangedEventArgs> >))); } else if (param.ParameterType == typeof(string)) { // instance => e => instance.${method}(e.PropertyName); var instance = Expression.Parameter(typeof(T)); var e = Expression.Parameter(typeof(PropertyChangedEventArgs)); return(Expression.Lambda <Func <T, Action <PropertyChangedEventArgs> > >( Expression.Lambda <Action <PropertyChangedEventArgs> >( Expression.Call(instance, method, Expression.PropertyOrField(e, nameof(PropertyChangedEventArgs.PropertyName))), e ), instance ).Compile()); } } var field = typeof(T).GetField(nameof(INotifyPropertyChanged.PropertyChanged), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(PropertyChangedEventHandler)) { // instance => e => instance.${field}(instance, e); var instance = Expression.Parameter(typeof(T)); var e = Expression.Parameter(typeof(PropertyChangedEventArgs)); return(Expression.Lambda <Func <T, Action <PropertyChangedEventArgs> > >( Expression.Lambda <Action <PropertyChangedEventArgs> >( Expression.Invoke(Expression.Field(instance, field), instance, e), e ), instance ).Compile()); } return(_ => null); }
public static Formatter <T> GetFormatter <T>() where T : UdonSharpBehaviour { lock (_emitLock) { if (_formatters.TryGetValue(typeof(T), out IFormatter formatter)) { return((Formatter <T>)formatter); } List <FieldInfo> serializedFieldList = new List <FieldInfo>(); List <FieldInfo> nonSerializedFieldList = new List <FieldInfo>(); Stack <Type> baseTypes = new Stack <Type>(); Type currentType = typeof(T); while (currentType != null && currentType != typeof(UdonSharpBehaviour)) { baseTypes.Push(currentType); currentType = currentType.BaseType; } List <FieldInfo> allFields = new List <FieldInfo>(); while (baseTypes.Count > 0) { currentType = baseTypes.Pop(); allFields.AddRange(currentType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)); } foreach (FieldInfo field in allFields) { // if (field.IsDefined(typeof(CompilerGeneratedAttribute), false)) // continue; if (FieldSymbol.IsFieldSerialized(field)) { serializedFieldList.Add(field); } else { nonSerializedFieldList.Add(field); } } FieldInfo[] publicFields = serializedFieldList.ToArray(); FieldInfo[] privateFields = nonSerializedFieldList.ToArray(); EmittedFormatter <T> .Init(publicFields, privateFields); InitializeRuntimeAssemblyBuilder(); BuildHelperType(typeof(T), publicFields, privateFields, out var serializerFields); Type formatterType = typeof(EmittedFormatter <>).MakeGenericType(typeof(T)); Delegate readDel, writeDel; // Read { Type readDelegateType = typeof(ReadDataMethodDelegate <>).MakeGenericType(typeof(T)); MethodInfo readDataMethod = formatterType.GetMethods(Flags.InstancePublic).First(e => e.Name == "Read" && e.GetParameters().Length == 2); DynamicMethod readMethod = new DynamicMethod($"Dynamic_{typeof(T).GetCompilableNiceFullName()}_Read", null, new[] { typeof(IValueStorage[]), typeof(T).MakeByRefType(), typeof(bool) }, true); foreach (ParameterInfo param in readDataMethod.GetParameters()) { readMethod.DefineParameter(param.Position, param.Attributes, param.Name); } EmitReadMethod(readMethod.GetILGenerator(), publicFields, privateFields, serializerFields); readDel = readMethod.CreateDelegate(readDelegateType); } // Write { Type writeDelegateType = typeof(WriteDataMethodDelegate <>).MakeGenericType(typeof(T)); MethodInfo writeDataMethod = formatterType.GetMethods(Flags.InstancePublic).First(e => e.Name == "Write" && e.GetParameters().Length == 2); DynamicMethod writeMethod = new DynamicMethod($"Dynamic_{typeof(T).GetCompilableNiceFullName()}_Write", null, new[] { typeof(IValueStorage[]), typeof(T).MakeByRefType(), typeof(bool) }, true); foreach (ParameterInfo param in writeDataMethod.GetParameters()) { writeMethod.DefineParameter(param.Position, param.Attributes, param.Name); } EmitWriteMethod(writeMethod.GetILGenerator(), publicFields, privateFields, serializerFields); writeDel = writeMethod.CreateDelegate(writeDelegateType); } formatter = (Formatter <T>)Activator.CreateInstance(typeof(EmittedFormatter <T>), readDel, writeDel); _formatters.Add(typeof(T), formatter); return((Formatter <T>)formatter); } }
protected override ParameterBuilder DefineParameter(int position, ParameterAttributes attributes, string parameterName) { return(dm.DefineParameter(position, attributes, parameterName)); }
public static Formatter <T> GetFormatter <T>() where T : UdonSharpBehaviour { lock (emitLock) { IFormatter formatter; if (formatters.TryGetValue(typeof(T), out formatter)) { return((Formatter <T>)formatter); } List <FieldInfo> serializedFieldList = new List <FieldInfo>(); List <FieldInfo> nonSerializedFieldList = new List <FieldInfo>(); FieldInfo[] allFields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (FieldInfo field in allFields) { if ((field.IsPublic && field.GetAttribute <System.NonSerializedAttribute>() == null) || (!field.IsPublic && field.GetAttribute <SerializeField>() != null)) { serializedFieldList.Add(field); } else { nonSerializedFieldList.Add(field); } } FieldInfo[] publicFields = serializedFieldList.ToArray(); FieldInfo[] privateFields = nonSerializedFieldList.ToArray(); EmittedFormatter <T> .Init(publicFields, privateFields); InitializeRuntimeAssemblyBuilder(); Dictionary <System.Type, FieldBuilder> serializerFields; BuildHelperType(typeof(T), publicFields, privateFields, out serializerFields); System.Type formatterType = typeof(EmittedFormatter <>).MakeGenericType(typeof(T)); System.Delegate readDel, writeDel; // Read { System.Type readDelegateType = typeof(ReadDataMethodDelegate <>).MakeGenericType(typeof(T)); MethodInfo readDataMethod = formatterType.GetMethods(Flags.InstancePublic).Where(e => e.Name == "Read" && e.GetParameters().Length == 2).First(); DynamicMethod readMethod = new DynamicMethod($"Dynamic_{typeof(T).GetCompilableNiceFullName()}_Read", null, new[] { typeof(IValueStorage[]), typeof(T).MakeByRefType(), typeof(bool) }, true); foreach (ParameterInfo param in readDataMethod.GetParameters()) { readMethod.DefineParameter(param.Position, param.Attributes, param.Name); } EmitReadMethod(readMethod.GetILGenerator(), typeof(T), publicFields, privateFields, serializerFields); readDel = readMethod.CreateDelegate(readDelegateType); } // Write { System.Type writeDelegateType = typeof(WriteDataMethodDelegate <>).MakeGenericType(typeof(T)); MethodInfo writeDataMethod = formatterType.GetMethods(Flags.InstancePublic).Where(e => e.Name == "Write" && e.GetParameters().Length == 2).First(); DynamicMethod writeMethod = new DynamicMethod($"Dynamic_{typeof(T).GetCompilableNiceFullName()}_Write", null, new[] { typeof(IValueStorage[]), typeof(T).MakeByRefType(), typeof(bool) }, true); foreach (ParameterInfo param in writeDataMethod.GetParameters()) { writeMethod.DefineParameter(param.Position, param.Attributes, param.Name); } EmitWriteMethod(writeMethod.GetILGenerator(), typeof(T), publicFields, privateFields, serializerFields); writeDel = writeMethod.CreateDelegate(writeDelegateType); } formatter = (Formatter <T>)System.Activator.CreateInstance(typeof(EmittedFormatter <T>), readDel, writeDel); formatters.Add(typeof(T), formatter); return((Formatter <T>)formatter); } }
internal static DynamicMethod CreateDynamicMethod(MethodBase original, string suffix) { if (original == null) { throw new ArgumentNullException(nameof(original)); } var patchName = original.Name + suffix; patchName = patchName.Replace("<>", ""); var parameters = original.GetParameters(); var parameterTypes = parameters.Types().ToList(); if (original.IsStatic == false) { if (AccessTools.IsStruct(original.DeclaringType)) { parameterTypes.Insert(0, original.DeclaringType.MakeByRefType()); } else { parameterTypes.Insert(0, original.DeclaringType); } } var firstArgIsReturnBuffer = NativeThisPointer.NeedsNativeThisPointerFix(original); if (firstArgIsReturnBuffer) { parameterTypes.Insert(0, typeof(IntPtr)); } var returnType = firstArgIsReturnBuffer ? typeof(void) : AccessTools.GetReturnedType(original); // DynamicMethod does not support byref return types if (returnType == null || returnType.IsByRef) { return(null); } DynamicMethod method; try { method = new DynamicMethod( patchName, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, returnType, parameterTypes.ToArray(), original.DeclaringType, true ); } catch (Exception) { return(null); } var offset = (original.IsStatic ? 0 : 1) + (firstArgIsReturnBuffer ? 1 : 0); for (var i = 0; i < parameters.Length; i++) { method.DefineParameter(i + offset, parameters[i].Attributes, parameters[i].Name); } return(method); }
public static void Main() { // Create an array that specifies the types of the parameters // of the dynamic method. This dynamic method has a String // parameter and an Integer parameter. Type[] helloArgs = {typeof(string), typeof(int), typeof(int)}; // Create a dynamic method with the name "Hello", a return type // of Integer, and two parameters whose types are specified by // the array helloArgs. Create the method in the module that // defines the String class. DynamicMethod hello = new DynamicMethod("Hello", typeof(int), helloArgs, typeof(string).Module); // Create an array that specifies the parameter types of the // overload of Console.WriteLine to be used in Hello. Type[] writeStringArgs = {typeof(string)}; // Get the overload of Console.WriteLine that has one // String parameter. MethodInfo writeString = typeof(Console).GetMethod("WriteLine", writeStringArgs); // Get an ILGenerator and emit a body for the dynamic method, // using a stream size larger than the IL that will be // emitted. ILGenerator il = hello.GetILGenerator(256); // Load the first argument, which is a string, onto the stack. il.Emit(OpCodes.Ldarg_0); // Call the overload of Console.WriteLine that prints a string. il.EmitCall(OpCodes.Call, writeString, null); // The Hello method returns the value of the second argument; // to do this, load the onto the stack and return. il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldc_I4_X, 1337); il.Emit(OpCodes.Add); il.Emit(OpCodes.Ret); // Add parameter information to the dynamic method. (This is not // necessary, but can be useful for debugging.) For each parameter, // identified by position, supply the parameter attributes and a // parameter name. hello.DefineParameter(1, ParameterAttributes.In, "message"); hello.DefineParameter(2, ParameterAttributes.In, "valueToReturn"); // Create a delegate that represents the dynamic method. This // action completes the method. Any further attempts to // change the method are ignored. HelloDelegate hi = (HelloDelegate) hello.CreateDelegate(typeof(HelloDelegate)); // Use the delegate to execute the dynamic method. Console.WriteLine("\r\nUse the delegate to execute the dynamic method:"); int retval = hi("\r\nHello, World!", 42, 30); Console.WriteLine("Invoking delegate hi(\"Hello, World!\", 42, 30) returned: " + retval); // Execute it again, with different arguments. retval = hi("\r\nHi, Mom!", 5280, 37); Console.WriteLine("Invoking delegate hi(\"Hi, Mom!\", 5280, 37) returned: " + retval); Console.WriteLine("\r\nUse the Invoke method to execute the dynamic method:"); // Create an array of arguments to use with the Invoke method. object[] invokeArgs = {"\r\nHello, World!", 42, 30}; // Invoke the dynamic method using the arguments. This is much // slower than using the delegate, because you must create an // array to contain the arguments, and value-type arguments // must be boxed. object objRet = hello.Invoke(null, BindingFlags.ExactBinding, null, invokeArgs, new CultureInfo("en-us")); Console.WriteLine("hello.Invoke returned: " + objRet); Console.WriteLine("\r\n ----- Display information about the dynamic method -----"); // Display MethodAttributes for the dynamic method, set when // the dynamic method was created. Console.WriteLine("\r\nMethod Attributes: {0}", hello.Attributes); // Display the calling convention of the dynamic method, set when the // dynamic method was created. Console.WriteLine("\r\nCalling convention: {0}", hello.CallingConvention); // Display the declaring type, which is always null for dynamic // methods. if (hello.DeclaringType == null) { Console.WriteLine("\r\nDeclaringType is always null for dynamic methods."); } else { Console.WriteLine("DeclaringType: {0}", hello.DeclaringType); } // Display the default value for InitLocals. if (hello.InitLocals) { Console.Write("\r\nThis method contains verifiable code."); } else { Console.Write("\r\nThis method contains unverifiable code."); } Console.WriteLine(" (InitLocals = {0})", hello.InitLocals); // Display the module specified when the dynamic method was created. Console.WriteLine("\r\nModule: {0}", hello.Module); // Display the name specified when the dynamic method was created. // Note that the name can be blank. Console.WriteLine("\r\nName: {0}", hello.Name); // For dynamic methods, the reflected type is always null. if (hello.ReflectedType == null) { Console.WriteLine("\r\nReflectedType is null."); } else { Console.WriteLine("\r\nReflectedType: {0}", hello.ReflectedType); } //beyond scope of project // if (hello.ReturnParameter == null) // { // Console.WriteLine("\r\nMethod has no return parameter."); // } // else // { // Console.WriteLine("\r\nReturn parameter: {0}", hello.ReturnParameter); // } // If the method has no return type, ReturnType is System.Void. Console.WriteLine("\r\nReturn type: {0}", hello.ReturnType); // ReturnTypeCustomAttributes returns an ICustomeAttributeProvider // that can be used to enumerate the custom attributes of the // return value. At present, there is no way to set such custom // attributes, so the list is empty. //beyond scope of project // if (hello.ReturnType == typeof(void)) // { // Console.WriteLine("The method has no return type."); // } // else // { // ICustomAttributeProvider caProvider = hello.ReturnTypeCustomAttributes; // object[] returnAttributes = caProvider.GetCustomAttributes(true); // if (returnAttributes.Length == 0) // { // Console.WriteLine("\r\nThe return type has no custom attributes."); // } // else // { // Console.WriteLine("\r\nThe return type has the following custom attributes:"); // foreach( object attr in returnAttributes ) // { // Console.WriteLine("\t{0}", attr.ToString()); // } // } // } Console.WriteLine("\r\nToString: {0}", hello.ToString()); Console.WriteLine("\r\nToString: {0}", hello.ToString()); // Display parameter information. ParameterInfo[] parameters = hello.GetParameters(); Console.WriteLine("\r\nParameters: name, type, ParameterAttributes"); foreach( ParameterInfo p in parameters ) { Console.WriteLine("\t{0}, {1}, {2}", p.Name, p.ParameterType, p.Attributes); } Console.WriteLine("array assignment"); Type[] paramTypes = { typeof(uint), typeof(string), typeof(string), typeof(uint) }; Console.WriteLine(paramTypes[1]); }
public static Delegate InstanceDelegate(Type dType, object target, FieldInfo funcField, MethodInfo methodAdapter) { MethodInfo dMethod = dType.GetMethod("Invoke"); ParameterInfo[] dParemeters = dMethod.GetParameters(); int len = dParemeters.Length; Type[] dParameterTypes = new Type[len + 1]; dParameterTypes[0] = target.GetType(); for (int i = 0; i < len; i++) { dParameterTypes[i + 1] = dParemeters[i].ParameterType; } DynamicMethod dynamicMethod = new DynamicMethod( Constant.FUNC_CON_INSTANCE_INVOKE, dMethod.ReturnType, dParameterTypes, target.GetType()); ILGenerator il = dynamicMethod.GetILGenerator(256); il.DeclareLocal(typeof(object[])); //object[] L0; il.DeclareLocal(typeof(object)); //object ret; il.DeclareLocal(dMethod.ReturnType); il.Emit(OpCodes.Ldc_I4, len); il.Emit(OpCodes.Newarr, typeof(object)); il.Emit(OpCodes.Stloc, 0); for (int i = 0; i < len; i++) { il.Emit(OpCodes.Ldloc, 0); //LOAD L0 il.Emit(OpCodes.Ldc_I4, i); //LOAD i il.Emit(OpCodes.Ldarg, i + 1); //LOAD arg[i+1] if (dParameterTypes[i].IsValueType) { il.Emit(OpCodes.Box, dParameterTypes[i]); } il.Emit(OpCodes.Stelem_Ref); } il.Emit(OpCodes.Ldarg, 0); //LOAD target il.Emit(OpCodes.Ldfld, funcField); //LOAD field il.Emit(OpCodes.Ldloc, 0); //LOAD L0 il.EmitCall(OpCodes.Call, methodAdapter, null); //CallFunc(VAL, L0); il.Emit(OpCodes.Stloc, 1); il.Emit(OpCodes.Ldloc, 1); if (dMethod.ReturnType.IsValueType) { il.Emit(OpCodes.Unbox_Any, dMethod.ReturnType); il.Emit(OpCodes.Stloc, 2); il.Emit(OpCodes.Ldloc, 2); } il.Emit(OpCodes.Ret); for (int i = 0; i < len + 1; i++) { dynamicMethod.DefineParameter(i, ParameterAttributes.In, "arg" + i); } return(dynamicMethod.CreateDelegate(dType, target)); }