コード例 #1
0
      public static Func<T, F> CreateFastFieldGetter<T, F>( FieldInfo fieldInfo )
      {
         if( fieldInfo == null )
            throw new ArgumentNullException( nameof( fieldInfo ) );
         if( !typeof( F ).IsAssignableFrom( fieldInfo.FieldType ) )
            throw new ArgumentException( "FieldInfo type does not match return type." );
         if( typeof( T ) != typeof( object ) )
            if( fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom( typeof( T ) ) )
               throw new MissingFieldException( typeof( T ).Name, fieldInfo.Name );

         var name = $"FastReflection<{typeof( T ).FullName}.Get_{fieldInfo.Name}>";

         var dm = new DynamicMethodDefinition( name, typeof( F ), new[] { typeof( T ) } );

         var il = dm.GetILProcessor();
         if( !fieldInfo.IsStatic )
         {
            il.Emit( OpCodes.Ldarg_0 );
            il.Emit( OpCodes.Castclass, fieldInfo.DeclaringType );
         }

         il.Emit( fieldInfo.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, fieldInfo );
         if( fieldInfo.FieldType.IsValueType != typeof( F ).IsValueType )
         {
            il.Emit( OpCodes.Box, fieldInfo.FieldType );
         }
         il.Emit( OpCodes.Ret );

         return (Func<T, F>)dm.Generate().CreateDelegate( typeof( Func<T, F> ) );
      }
コード例 #2
0
        public MethodBase GetDetourTarget(MethodBase from, MethodBase to) {
            Type context = to.DeclaringType;

            MethodInfo dm = null;

            if (GlueThiscallStructRetPtr != GlueThiscallStructRetPtrOrder.Original &&
                from is MethodInfo fromInfo && !from.IsStatic &&
                to is MethodInfo toInfo && to.IsStatic &&
                fromInfo.ReturnType == toInfo.ReturnType &&
                fromInfo.ReturnType.IsValueType) {

                int size = fromInfo.ReturnType.GetManagedSize();
                if (size == 3 || size == 5 || size == 6 || size == 7 || size >= 9) {
                    Type thisType = from.GetThisParamType();
                    Type retType = fromInfo.ReturnType.MakeByRefType(); // Refs are shiny pointers.

                    int thisPos = 0;
                    int retPos = 1;

                    if (GlueThiscallStructRetPtr == GlueThiscallStructRetPtrOrder.RetThisArgs) {
                        thisPos = 1;
                        retPos = 0;
                    }

                    List<Type> argTypes = new List<Type> {
                        thisType
                    };
                    argTypes.Insert(retPos, retType);

                    argTypes.AddRange(from.GetParameters().Select(p => p.ParameterType));

                    using (DynamicMethodDefinition dmd = new DynamicMethodDefinition(
                        $"Glue:ThiscallStructRetPtr<{from.GetID(simple: true)},{to.GetID(simple: true)}>",
                        typeof(void), argTypes.ToArray()
                    )) {
                        ILProcessor il = dmd.GetILProcessor();

                        // Load the return buffer address.
                        il.Emit(OpCodes.Ldarg, retPos);

                        // Invoke the target method with all remaining arguments.
                        {
                            il.Emit(OpCodes.Ldarg, thisPos);
                            for (int i = 2; i < argTypes.Count; i++)
                                il.Emit(OpCodes.Ldarg, i);
                            il.Emit(OpCodes.Call, il.Body.Method.Module.ImportReference(to));
                        }

                        // Store the returned object to the return buffer.
                        il.Emit(OpCodes.Stobj, il.Body.Method.Module.ImportReference(fromInfo.ReturnType));
                        il.Emit(OpCodes.Ret);

                        dm = dmd.Generate();
                    }
                }
            }

            return dm ?? to;
        }
コード例 #3
0
		/// <summary>Returns the methods unmodified list of CodeInstructions</summary>
		/// <param name="original">The original method</param>
		/// <param name="generator">A new generator that now contains all local variables and labels contained in the result</param>
		/// <returns>A list containing all the original CodeInstructions</returns>
		public static List<CodeInstruction> GetOriginalInstructions(MethodBase original, out ILGenerator generator)
		{
			// Create a copy
			var dmd = new DynamicMethodDefinition(original);
			// Create a manipulator to obtain the instructions
			var manipulator = new ILManipulator(dmd.Definition.Body);
			generator = new CecilILGenerator(dmd.GetILProcessor()).GetProxy();
			return manipulator.GetInstructions(generator);
		}
コード例 #4
0
 internal static void Initialize()
 {
     foreach (var field in AccessTools.GetDeclaredFields(typeof(OS)).Where(x => x.FieldType == typeof(Color)))
     {
         var dynMethod = new DynamicMethodDefinition(field.Name, typeof(Color).MakeByRefType(), new Type[] { typeof(OS) });
         var p         = dynMethod.GetILProcessor();
         p.Emit(OpCodes.Ldarg_0);
         p.Emit(OpCodes.Ldflda, field);
         p.Emit(OpCodes.Ret);
         OSColorFieldsFast.Add(field.Name, dynMethod.Generate().CreateDelegate <RefColorFieldDelegate>());
     }
 }
コード例 #5
0
        public static Delegate GenerateDelegate(MethodBase method, bool useCallVirt)
        {
            var parameterTypes   = GetActualParameters(method);
            var actionParameters = GetActionParameters(method);
            var returnType       = method is MethodInfo mi ? mi.ReturnType : typeof(void);

            var dynamicMethod = new DynamicMethodDefinition("DynamicMethod_" + method.Name, returnType, actionParameters);

            var il = dynamicMethod.GetILProcessor();

            if (actionParameters.Length >= 1)
            {
                il.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_0);
                il.Emit(Mono.Cecil.Cil.OpCodes.Castclass, parameterTypes[0]);
                if (actionParameters.Length >= 2)
                {
                    il.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_1);
                    il.Emit(Mono.Cecil.Cil.OpCodes.Castclass, parameterTypes[1]);
                    if (actionParameters.Length >= 3)
                    {
                        il.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_2);
                        il.Emit(Mono.Cecil.Cil.OpCodes.Castclass, parameterTypes[2]);
                        if (actionParameters.Length >= 4)
                        {
                            il.Emit(Mono.Cecil.Cil.OpCodes.Ldarg_3);
                            il.Emit(Mono.Cecil.Cil.OpCodes.Castclass, parameterTypes[3]);
                        }
                    }
                }
            }
            il.Emit(useCallVirt ? Mono.Cecil.Cil.OpCodes.Callvirt : Mono.Cecil.Cil.OpCodes.Call, method);
            il.Emit(Mono.Cecil.Cil.OpCodes.Ret);

            var delegateType = returnType == typeof(void) ? GetGenericActionType(actionParameters) : GetGenericFuncType(actionParameters, returnType);
            var actionOrFunc = dynamicMethod.Generate().CreateDelegate(delegateType);

            return(actionOrFunc);
        }
コード例 #6
0
        public MethodInfo GetDelegateInvoker <T>() where T : Delegate
        {
            Type       t = typeof(T);
            MethodInfo invoker;

            if (invokerCache.TryGetValue(t, out WeakReference invokerRef))
            {
                if (invokerRef == null)
                {
                    return(null);
                }

                invoker = invokerRef.Target as MethodInfo;
                if (invokerRef.IsAlive)
                {
                    return(invoker);
                }
            }

            MethodInfo delInvoke = t.GetMethod("Invoke");

            ParameterInfo[] args = delInvoke.GetParameters();
            if (args.Length == 0)
            {
                invokerCache[t] = null;
                return(null);
            }

            invoker = FastDelegateInvokers.GetInvoker(delInvoke);
            if (invoker != null)
            {
                invokerCache[t] = new WeakReference(invoker);
                return(invoker);
            }

            Type[] argTypes = new Type[args.Length + 1];
            for (int i = 0; i < args.Length; i++)
            {
                argTypes[i] = args[i].ParameterType;
            }
            argTypes[args.Length] = typeof(T);

            using (DynamicMethodDefinition dmdInvoke = new DynamicMethodDefinition(
                       $"MMIL:Invoke<{delInvoke.DeclaringType.FullName}>",
                       delInvoke.ReturnType, argTypes
                       )) {
                ILProcessor il = dmdInvoke.GetILProcessor();

                // Load the delegate reference first.
                il.Emit(OpCodes.Ldarg, args.Length);

                // Load the rest of the args
                for (int i = 0; i < args.Length; i++)
                {
                    il.Emit(OpCodes.Ldarg, i);
                }

                // Invoke the delegate and return its result.
                il.Emit(OpCodes.Callvirt, delInvoke);
                il.Emit(OpCodes.Ret);

                invoker         = dmdInvoke.Generate();
                invokerCache[t] = new WeakReference(invoker);
                return(invoker);
            }
        }
コード例 #7
0
      public static FastReflectionDelegate CreateFastDelegate( MethodBase method, bool directBoxValueAccess, bool forceNonVirtcall )
      {
         DynamicMethodDefinition dmd = new DynamicMethodDefinition( $"FastReflection<{method.DeclaringType.FullName + "." + method.Name}>", 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 || forceNonVirtcall )
         {
            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 ) );
      }
コード例 #8
0
ファイル: Hook.cs プロジェクト: JackPendarvesRead/MonoMod
        public Hook(MethodBase from, MethodInfo to, object target, ref HookConfig config)
        {
            Method         = from;
            Target         = to;
            DelegateTarget = target;

            // Check if hook ret -> method ret is valid. Don't check for method ret -> hook ret, as that's too strict.
            Type returnType = (from as MethodInfo)?.ReturnType ?? typeof(void);

            if (to.ReturnType != returnType && !to.ReturnType.IsCompatible(returnType))
            {
                throw new InvalidOperationException($"Return type of hook for {from} doesn't match, must be {((from as MethodInfo)?.ReturnType ?? typeof(void)).FullName}");
            }

            if (target == null && !to.IsStatic)
            {
                throw new InvalidOperationException($"Hook for method {from} must be static, or you must pass a target instance.");
            }

            ParameterInfo[] hookArgs = Target.GetParameters();

            // Check if the parameters match.
            // If the delegate has got an extra first parameter that itself is a delegate, it's the orig trampoline passthrough.
            ParameterInfo[] args = Method.GetParameters();
            Type[]          argTypes;
            if (!Method.IsStatic)
            {
                argTypes    = new Type[args.Length + 1];
                argTypes[0] = Method.GetThisParamType();
                for (int i = 0; i < args.Length; i++)
                {
                    argTypes[i + 1] = args[i].ParameterType;
                }
            }
            else
            {
                argTypes = new Type[args.Length];
                for (int i = 0; i < args.Length; i++)
                {
                    argTypes[i] = args[i].ParameterType;
                }
            }

            Type origType = null;

            if (hookArgs.Length == argTypes.Length + 1 && typeof(Delegate).IsAssignableFrom(hookArgs[0].ParameterType))
            {
                _OrigDelegateType = origType = hookArgs[0].ParameterType;
            }
            else if (hookArgs.Length != argTypes.Length)
            {
                throw new InvalidOperationException($"Parameter count of hook for {from} doesn't match, must be {argTypes.Length}");
            }

            for (int i = 0; i < argTypes.Length; i++)
            {
                Type argMethod = argTypes[i];
                Type argHook   = hookArgs[i + (origType == null ? 0 : 1)].ParameterType;
                if (!argMethod.IsCompatible(argHook))
                {
                    throw new InvalidOperationException($"Parameter #{i} of hook for {from} doesn't match, must be {argMethod.FullName} or related");
                }
            }

            MethodInfo origInvoke = _OrigDelegateInvoke = origType?.GetMethod("Invoke");
            // TODO: Check origType Invoke arguments.

            DynamicMethodDefinition dmd;
            ILProcessor             il;

            using (dmd = new DynamicMethodDefinition(
                       $"Hook<{Method.GetID(simple: true)}>?{GetHashCode()}",
                       (Method as MethodInfo)?.ReturnType ?? typeof(void), argTypes
                       )) {
                il = dmd.GetILProcessor();

                if (target != null)
                {
                    _RefTarget = il.EmitReference(target);
                }

                if (origType != null)
                {
                    _RefTrampoline = il.EmitReference <Delegate>(null);
                }

                for (int i = 0; i < argTypes.Length; i++)
                {
                    il.Emit(OpCodes.Ldarg, i);
                }

                il.Emit(OpCodes.Call, Target);

                il.Emit(OpCodes.Ret);

                TargetReal = dmd.Generate().Pin();
            }

            // Temporarily provide a trampoline that waits for the proper trampoline.
            if (origType != null)
            {
                ParameterInfo[] origArgs     = origInvoke.GetParameters();
                Type[]          origArgTypes = new Type[origArgs.Length];
                for (int i = 0; i < origArgs.Length; i++)
                {
                    origArgTypes[i] = origArgs[i].ParameterType;
                }

                using (dmd = new DynamicMethodDefinition(
                           $"Chain:TMP<{Method.GetID(simple: true)}>?{GetHashCode()}",
                           (origInvoke as MethodInfo)?.ReturnType ?? typeof(void), origArgTypes
                           )) {
                    il = dmd.GetILProcessor();

                    // while (ref == null) { }
                    _RefTrampolineTmp = il.EmitReference <Delegate>(null);
                    il.Emit(OpCodes.Brfalse, il.Body.Instructions[0]);

                    // Invoke the generated delegate.
                    il.EmitGetReference <Delegate>(_RefTrampolineTmp.Value);

                    for (int i = 0; i < argTypes.Length; i++)
                    {
                        il.Emit(OpCodes.Ldarg, i);
                    }

                    il.Emit(OpCodes.Callvirt, origInvoke);

                    il.Emit(OpCodes.Ret);

                    DynamicMethodHelper.SetReference(_RefTrampoline.Value, dmd.Generate().CreateDelegate(origType));
                }
            }

            _Detour = new Detour(Method, TargetReal, new DetourConfig()
            {
                ManualApply = config.ManualApply,
                Priority    = config.Priority,
                ID          = config.ID,
                Before      = config.Before,
                After       = config.After
            });

            _UpdateOrig(null);
        }
コード例 #9
0
ファイル: NativeDetour.cs プロジェクト: opl-/MonoMod
        /// <summary>
        /// Generate a new DynamicMethod with which you can invoke the previous state.
        /// If the NativeDetour holds a reference to a managed method, a copy of the original method is returned.
        /// If the NativeDetour holds a reference to a native function, an "undo-call-redo" trampoline with a matching signature is returned.
        /// </summary>
        public MethodBase GenerateTrampoline(MethodBase signature = null)
        {
            MethodBase remoteTrampoline = OnGenerateTrampoline?.InvokeWhileNull <MethodBase>(this, signature);

            if (remoteTrampoline != null)
            {
                return(remoteTrampoline);
            }

            if (_IsFree)
            {
                throw new InvalidOperationException("Free() has been called on this detour.");
            }

            if (_BackupMethod != null)
            {
                // If we're detouring an IL method and have an IL copy, invoke the IL copy.
                // Note that this ignores the passed signature.
                return(_BackupMethod);
            }

            /*
             * if (signature == null)
             *  signature = _BackupMethod;
             */
            if (signature == null)
            {
                throw new ArgumentNullException("A signature must be given if the NativeDetour doesn't hold a reference to a managed method.");
            }

            // Otherwise, undo the detour, call the method and reapply the detour.

            MethodBase methodCallable = Method;

            if (methodCallable == null)
            {
                methodCallable = DetourHelper.GenerateNativeProxy(Data.Method, signature);
            }

            Type returnType = (signature as MethodInfo)?.ReturnType ?? typeof(void);

            ParameterInfo[] args     = signature.GetParameters();
            Type[]          argTypes = new Type[args.Length];
            for (int i = 0; i < args.Length; i++)
            {
                argTypes[i] = args[i].ParameterType;
            }

            using (DynamicMethodDefinition dmd = new DynamicMethodDefinition(
                       $"Trampoline:Native<{Method?.GetFindableID(simple: true) ?? ((long) Data.Method).ToString("X16")}>?{GetHashCode()}",
                       returnType, argTypes
                       )) {
                ILProcessor il = dmd.GetILProcessor();

                ExceptionHandler eh = new ExceptionHandler(ExceptionHandlerType.Finally);
                il.Body.ExceptionHandlers.Add(eh);

                il.EmitDetourCopy(_BackupNative, Data.Method, Data.Type);

                // Store the return value in a local as we can't preserve the stack across exception block boundaries.
                VariableDefinition localResult = null;
                if (returnType != typeof(void))
                {
                    il.Body.Variables.Add(localResult = new VariableDefinition(il.Import(returnType)));
                }

                // Label blockTry = il.BeginExceptionBlock();
                int instriTryStart = il.Body.Instructions.Count;

                for (int i = 0; i < argTypes.Length; i++)
                {
                    il.Emit(OpCodes.Ldarg, i);
                }

                if (methodCallable is MethodInfo)
                {
                    il.Emit(OpCodes.Call, (MethodInfo)methodCallable);
                }
                else if (methodCallable is ConstructorInfo)
                {
                    il.Emit(OpCodes.Call, (ConstructorInfo)methodCallable);
                }
                else
                {
                    throw new NotSupportedException($"Method type {methodCallable.GetType().FullName} not supported.");
                }

                if (localResult != null)
                {
                    il.Emit(OpCodes.Stloc, localResult);
                }

                il.Emit(OpCodes.Leave, (object)null);
                Instruction instrLeave = il.Body.Instructions[il.Body.Instructions.Count - 1];

                // il.BeginFinallyBlock();
                int instriTryEnd       = il.Body.Instructions.Count;
                int instriFinallyStart = il.Body.Instructions.Count;

                // Reapply the detour even if the method threw an exception.
                il.EmitDetourApply(Data);

                // il.EndExceptionBlock();
                int instriFinallyEnd = il.Body.Instructions.Count;

                Instruction instrLeaveTarget = null;

                if (localResult != null)
                {
                    il.Emit(OpCodes.Ldloc, localResult);
                    instrLeaveTarget = il.Body.Instructions[il.Body.Instructions.Count - 1];
                }

                il.Emit(OpCodes.Ret);
                instrLeaveTarget   = instrLeaveTarget ?? il.Body.Instructions[il.Body.Instructions.Count - 1];
                instrLeave.Operand = instrLeaveTarget;

                // TODO: Are the exception handler indices correct?
                eh.TryStart     = il.Body.Instructions[instriTryStart];
                eh.TryEnd       = il.Body.Instructions[instriTryEnd];
                eh.HandlerStart = il.Body.Instructions[instriTryEnd];
                eh.HandlerEnd   = il.Body.Instructions[instriFinallyEnd];

                return(dmd.Generate().Pin());
            }
        }
コード例 #10
0
        public static DynamicMethodDefinition ToDynamicMethod(this MethodDefinition method)
        {
            List <Type> parameters = new List <Type>();

            foreach (var param in method.Parameters)
            {
                string[] typeArr = param.ParameterType.FullName.Split('.');
                Array.Resize(ref typeArr, typeArr.Length - 1);
                string nameSpace = string.Join(".", typeArr);

                Assembly asm = null;

                if (nameSpace.StartsWith("System"))
                {
                    asm = typeof(object).Assembly;
                }
                else if (nameSpace.StartsWith("Terraria"))
                {
                    asm = typeof(Main).Assembly;
                }
                else if (nameSpace.StartsWith("Microsoft"))
                {
                    asm = typeof(Vector2).Assembly;
                }

                Type type = asm.GetType(param.ParameterType.FullName);

                if (param.ParameterType.IsByReference)
                {
                    type = type.MakeByRefType();
                }

                parameters.Add(type);
            }

            DynamicMethodDefinition dynamicMethod = new DynamicMethodDefinition($"{method.DeclaringType.Name}_{method.Name}", Type.GetType(method.ReturnType.FullName), parameters.ToArray());
            ILProcessor             il            = dynamicMethod.GetILProcessor();

            foreach (Instruction instruction in method.Body.Instructions)
            {
                if (instruction.Operand is FieldReference reference)
                {
                    TypeReference fieldType = reference.FieldType;

                    if (fieldType.Scope.ToString().StartsWith("tConfig"))
                    {
                        fieldType = new TypeReference(fieldType.Namespace, fieldType.Name, TerrariaModule, TerrariaModule);
                    }
                    TypeReference declaringType = reference.DeclaringType;
                    if (declaringType.Scope.ToString().StartsWith("tConfig"))
                    {
                        declaringType = new TypeReference(declaringType.Namespace, declaringType.Name, TerrariaModule, TerrariaModule);
                    }
                    il.Emit(instruction.OpCode, new FieldReference(reference.Name, fieldType, declaringType));
                }
                else
                {
                    il.Emit(instruction.OpCode, instruction.Operand);
                }
            }

            foreach (Instruction inst in dynamicMethod.Definition.Body.Instructions)
            {
                if (inst.Operand is Instruction targetOrig)
                {
                    inst.Operand = dynamicMethod.Definition.Body.Instructions[method.Body.Instructions.IndexOf(targetOrig)];
                }
            }

            return(dynamicMethod);
        }