コード例 #1
0
 public void Remove(GenericInstanceMethod genericInstanceMethod)
 {
     this.Remove(genericInstanceMethod.ElementMethod.FullName, genericInstanceMethod);
 }
コード例 #2
0
ファイル: Extensions.cs プロジェクト: freedomWind/ILRuntime
        public static List <IType> GetParamList(this MethodReference def, ILRuntime.Runtime.Enviorment.AppDomain appdomain, IType contextType, IMethod contextMethod, IType[] genericArguments)
        {
            if (def.HasParameters)
            {
                List <IType> param = new List <IType>();
                var          dt    = appdomain.GetType(def.DeclaringType, contextType, contextMethod);
                foreach (var i in def.Parameters)
                {
                    IType t = null;
                    t = appdomain.GetType(i.ParameterType, dt, null);
                    if (t == null && def.IsGenericInstance)
                    {
                        GenericInstanceMethod gim = (GenericInstanceMethod)def;
                        string name = i.ParameterType.IsByReference ? i.ParameterType.GetElementType().FullName : i.ParameterType.FullName;

                        for (int j = 0; j < gim.GenericArguments.Count; j++)
                        {
                            var gp = gim.ElementMethod.GenericParameters[j];
                            var ga = gim.GenericArguments[j];
                            if (name == gp.Name)
                            {
                                t = appdomain.GetType(ga, contextType, contextMethod);
                                if (t == null && genericArguments != null)
                                {
                                    t = genericArguments[j];
                                }
                                break;
                            }
                            else if (name.Contains(gp.Name))
                            {
                                t = appdomain.GetType(ga, contextType, contextMethod);
                                if (t == null && genericArguments != null)
                                {
                                    t = genericArguments[j];
                                }
                                if (name == gp.Name)
                                {
                                    name = t.FullName;
                                }
                                else if (name == gp.Name + "[]")
                                {
                                    name = t.FullName + "[]";
                                }
                                else
                                {
                                    /*name = name.Replace("<" + gp.Name + ">", "<" + ga.FullName + ">");
                                    *  name = name.Replace("<" + gp.Name + "[", "<" + ga.FullName + "[");
                                    *  name = name.Replace("<" + gp.Name + ",", "<" + ga.FullName + ",");
                                    *  name = name.Replace("," + gp.Name + ">", "," + ga.FullName + ">");
                                    *  name = name.Replace("," + gp.Name + "[", "," + ga.FullName + "[");
                                    *  name = name.Replace("," + gp.Name + ",", "," + ga.FullName + ",");
                                    *  name = name.Replace("," + gp.Name + "[", "," + ga.FullName + "[");*/
                                    name = ReplaceGenericArgument(name, gp.Name, ga.FullName);
                                }
                                t = null;
                            }
                        }
                        if (t == null)
                        {
                            t = appdomain.GetType(name);
                        }
                    }

                    param.Add(t);
                }
                return(param);
            }
            else
            {
                return(EmptyParamList);
            }
        }
コード例 #3
0
        internal static TypeReference GetTypeWithGenericResolved(
            this GenericInstanceType genericInstanceParameter,
            GenericInstanceType genericInstanceType,
            GenericInstanceMethod genericInstanceMethod)
        {
            GenericInstanceType newGenericInstanceType = new GenericInstanceType(genericInstanceParameter.ElementType);

            foreach (var genericArg in genericInstanceParameter.GenericArguments)
            {
                TypeReference newGenericArg = genericArg;
                bool          isByReference = false;
                bool          isArray       = false;
                int           arrayRank     = 0;
                if (newGenericArg.IsByReference)
                {
                    isByReference = true;
                    ByReferenceType byReferenceType = (ByReferenceType)newGenericArg;
                    newGenericArg = byReferenceType.ElementType;
                }

                if (newGenericArg.IsArray)
                {
                    isArray = true;
                    ArrayType arrayType = (ArrayType)newGenericArg;
                    arrayRank     = arrayType.Rank;
                    newGenericArg = arrayType.ElementType;
                }

                if (newGenericArg.IsGenericInstance)
                {
                    newGenericArg = ((GenericInstanceType)newGenericArg).GetTypeWithGenericResolved(genericInstanceType, genericInstanceMethod);
                }

                if (newGenericArg.IsGenericParameter)
                {
                    GenericParameter tmp = newGenericArg as GenericParameter;
                    if (tmp.DeclaringType != null && genericInstanceType != null)
                    {
                        int position = genericInstanceType.ElementType.GenericParameters.GetIndexByName(newGenericArg.Name);
                        if (position != -1)
                        {
                            newGenericArg = genericInstanceType.GenericArguments[position];
                        }
                    }
                    else if (tmp.DeclaringMethod != null && genericInstanceMethod != null)
                    {
                        int position = genericInstanceMethod.GetElementMethod().GenericParameters.GetIndexByName(newGenericArg.Name);
                        if (position != -1)
                        {
                            newGenericArg = genericInstanceMethod.GenericArguments[position];
                        }
                    }
                }

                if (isArray)
                {
                    newGenericArg = new ArrayType(newGenericArg, arrayRank);
                }

                if (isByReference)
                {
                    newGenericArg = new ByReferenceType(newGenericArg);
                }

                newGenericInstanceType.GenericArguments.Add(newGenericArg);
            }

            return(newGenericInstanceType);
        }
コード例 #4
0
 public TypeResolver(GenericInstanceMethod methodDefinitionContext)
 {
     this._methodDefinitionContext = methodDefinitionContext;
 }
コード例 #5
0
        public static PropertyDefinition BuildPropertyCore(Property property, TypeDefinition type)
        {
            var mod = type.Module;
            //从缓存中查找clr type
            var ptype = property.PropertyType.GetTypeReference();

            var fieldInfo = new FieldDefinition("_" + property.称, FieldAttributes.Private, ptype);

            type.Fields.Add(fieldInfo);
            // type.DefineField("_" + property.名称, ptype, FieldAttributes.Private);

            var propertyInfo = new PropertyDefinition(property.称, PropertyAttributes.None, ptype)
            {
                HasThis = true
            };

            type.Properties.Add(propertyInfo);
            #region 基本属性设置

            if (property.Size != 100 && property.Size != 0)
            {
                propertyInfo.Size(property.Size);
            }

            //if (!string.IsNullOrEmpty(property.Expression))
            //{
            //    propertyInfo.PersistentAlias(property.Expression);
            //}

            #endregion ;

            #region getter
            //.method public hidebysig specialname instance string get_创建者() cil managedMono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.SpecialName
            var attr    = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.FamANDAssem | MethodAttributes.Family;
            var setattr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.FamANDAssem | MethodAttributes.Family;

            var getMethod = new MethodDefinition("get_" + property.称, attr, ptype);

            var getMethodIl = getMethod.Body.GetILProcessor();

            getMethod.Body.MaxStackSize = 8;
            getMethod.Body.InitLocals   = true;

            getMethodIl.Emit(OpCodes.Ldarg_0);
            getMethodIl.Emit(OpCodes.Ldfld, fieldInfo);
            getMethodIl.Emit(OpCodes.Ret);
            type.Methods.Add(getMethod);
            propertyInfo.GetMethod = getMethod;

            #endregion

            #region 非计算类型

            if (string.IsNullOrEmpty(property.Expression))
            {
                var set  = new MethodDefinition("set_" + property.称, setattr, mod.ImportReference(typeof(void)));
                var para = new ParameterDefinition("value", ParameterAttributes.None, ptype);
                set.Parameters.Add(para);
                var setPropertyValue = mod.ImportReference(
                    typeof(PersistentBase)
                    .GetMethods(
                        SR.BindingFlags.InvokeMethod | SR.BindingFlags.NonPublic |
                        SR.BindingFlags.Instance)
                    .Single(x => x.Name.StartsWith("SetPropertyValue") && x.IsGenericMethod &&
                            x.GetParameters().Length == 3)
                    );
                var setPropertyValueMethod = new GenericInstanceMethod(setPropertyValue);
                setPropertyValueMethod.GenericArguments.Add(ptype);
                //setPropertyValue =  setPropertyValue.MakeGenericMethod(ptype);

                var setIl = set.Body.Instructions;
                setIl.Add(Instruction.Create(OpCodes.Ldarg_0));
                setIl.Add(Instruction.Create(OpCodes.Ldstr, property.称));
                setIl.Add(Instruction.Create(OpCodes.Ldarg_0));
                setIl.Add(Instruction.Create(OpCodes.Ldflda, fieldInfo));
                setIl.Add(Instruction.Create(OpCodes.Ldarg_1));
                setIl.Add(Instruction.Create(OpCodes.Call, setPropertyValueMethod));
                setIl.Add(Instruction.Create(OpCodes.Pop));
                setIl.Add(Instruction.Create(OpCodes.Ret));
                propertyInfo.SetMethod = set;
                type.Methods.Add(set);
            }

            #endregion

            return(propertyInfo);
        }
コード例 #6
0
        /// <summary>
        /// Get method signature of invoked method. It will be resolved with
        /// generic arguments while the method is invoked.
        /// </summary>
        /// <param name="method">Method to get resolved signature.</param>
        /// <param name="methodDef">Method definition of method parameter.</param>
        /// <returns>
        /// Method signature with generic parameters resolved, e.g., List&lt;string&gt;
        /// Generic parameters are resolved to argument values.
        /// </returns>
        public static string GetResolvedMethodSignature(this MethodReference method, MethodDefinition methodDef)
        {
            string typeSignature = GetResolvedTypeSignature(method.DeclaringType);
            string methodSignature;

            if (method.Name.StartsWith(GetPrefix))
            {
                methodSignature = $"{method.Name.Substring(GetPrefix.Length)}.get";
            }
            else if (method.Name.StartsWith(SetPrefix))
            {
                methodSignature = $"{method.Name.Substring(SetPrefix.Length)}.set";
            }
            else
            {
                methodSignature = method.Name;
            }

            if (method.IsGenericInstance)
            {
                GenericInstanceMethod genericInstance = (GenericInstanceMethod)method;
                var genericParameters = genericInstance.GenericArguments.Select(genericArgument => genericArgument.GetResolvedTypeSignature());
                methodSignature = genericParameters.Count() != 0 ? $"{methodSignature}<{string.Join(",", genericParameters)}>" : methodSignature;
            }

            IList <string> parameters = new List <string>();

            if (method.IsGenericInstance)
            {
                GenericInstanceMethod genericInstanceMethod = (GenericInstanceMethod)method;
                for (int i = 0; i < method.Parameters.Count; i++)
                {
                    ParameterDefinition parameter             = method.Parameters[i];
                    ParameterDefinition parameterOfMethodDef  = methodDef.Parameters[i];
                    TypeReference       resolvedParameterType = parameter.GetTypeWithGenericResolved(genericInstanceMethod);
                    if (resolvedParameterType.IsByReference)
                    {
                        ByReferenceType byReference = resolvedParameterType as ByReferenceType;
                        string          prefix;
                        if (parameterOfMethodDef.IsOut)
                        {
                            prefix = "out";
                        }
                        else if (parameterOfMethodDef.IsIn)
                        {
                            prefix = "in";
                        }
                        else
                        {
                            prefix = "ref";
                        }

                        parameters.Add($"{prefix}{byReference.ElementType.GetResolvedTypeSignature()}");
                    }
                    else if (parameterOfMethodDef.IsParams())
                    {
                        parameters.Add($"params{resolvedParameterType.GetResolvedTypeSignature()}");
                    }
                    else
                    {
                        parameters.Add(resolvedParameterType.GetResolvedTypeSignature());
                    }
                }
            }
            else
            {
                for (int i = 0; i < method.Parameters.Count; i++)
                {
                    ParameterDefinition parameter             = method.Parameters[i];
                    ParameterDefinition parameterOfMethodDef  = methodDef.Parameters[i];
                    TypeReference       resolvedParameterType = parameter.GetTypeWithGenericResolved();
                    if (resolvedParameterType.IsByReference)
                    {
                        ByReferenceType byReference = resolvedParameterType as ByReferenceType;
                        string          prefix;
                        if (parameterOfMethodDef.IsOut)
                        {
                            prefix = "out";
                        }
                        else if (parameterOfMethodDef.IsIn)
                        {
                            prefix = "in";
                        }
                        else
                        {
                            prefix = "ref";
                        }

                        parameters.Add($"{prefix}{byReference.ElementType.GetResolvedTypeSignature()}");
                    }
                    else if (parameterOfMethodDef.IsParams())
                    {
                        parameters.Add($"params{resolvedParameterType.GetResolvedTypeSignature()}");
                    }
                    else
                    {
                        parameters.Add(resolvedParameterType.GetResolvedTypeSignature());
                    }
                }
            }

            return($"{typeSignature}.{methodSignature}({string.Join(",", parameters)})");
        }
コード例 #7
0
        void DeserializeField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefinition deserialize)
        {
            // check for Hook function
            if (!SyncVarProcessor.CheckForHookFunction(netBehaviourSubclass, syncVar, out MethodDefinition foundMethod))
            {
                return;
            }

            // [SyncVar] GameObject/NetworkIdentity?

            /*
             * Generates code like:
             *  uint oldNetId = ___qNetId;
             *  GameObject oldSyncVar = syncvar.getter; // returns GetSyncVarGameObject(___qNetId)
             *  ___qNetId = reader.ReadPackedUInt32();
             *  if (!SyncVarEqual(oldNetId, ref ___goNetId))
             *  {
             *      OnSetQ(oldSyncVar, syncvar.getter); // getter returns GetSyncVarGameObject(___qNetId)
             *  }
             */
            if (syncVar.FieldType.FullName == Weaver.gameObjectType.FullName ||
                syncVar.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
            {
                // GameObject/NetworkIdentity SyncVar:
                //   OnSerialize sends writer.Write(go);
                //   OnDeserialize reads to __netId manually so we can use
                //     lookups in the getter (so it still works if objects
                //     move in and out of range repeatedly)
                FieldDefinition netIdField = syncVarNetIds[syncVar];

                // uint oldNetId = ___qNetId;
                VariableDefinition oldNetId = new VariableDefinition(Weaver.uint32Type);
                deserialize.Body.Variables.Add(oldNetId);
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldfld, netIdField));
                serWorker.Append(serWorker.Create(OpCodes.Stloc, oldNetId));

                // GameObject/NetworkIdentity oldSyncVar = syncvar.getter;
                VariableDefinition oldSyncVar = new VariableDefinition(syncVar.FieldType);
                deserialize.Body.Variables.Add(oldSyncVar);
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));
                serWorker.Append(serWorker.Create(OpCodes.Stloc, oldSyncVar));

                // read id and store in netId field BEFORE calling the hook
                // -> this makes way more sense. by definition, the hook is
                //    supposed to be called after it was changed. not before.
                // -> setting it BEFORE calling the hook fixes the following bug:
                //    https://github.com/vis2k/Mirror/issues/1151 in host mode
                //    where the value during the Hook call would call Cmds on
                //    the host server, and they would all happen and compare
                //    values BEFORE the hook even returned and hence BEFORE the
                //    actual value was even set.
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));                                      // put 'this.' onto stack for 'this.netId' below
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));                                      // reader. for 'reader.Read()' below
                serWorker.Append(serWorker.Create(OpCodes.Call, Readers.GetReadFunc(Weaver.uint32Type))); // Read()
                serWorker.Append(serWorker.Create(OpCodes.Stfld, netIdField));                            // netId

                if (foundMethod != null)
                {
                    // call Hook(this.GetSyncVarGameObject/NetworkIdentity(reader.ReadPackedUInt32()))
                    // because we send/receive the netID, not the GameObject/NetworkIdentity
                    // but only if SyncVar changed. otherwise a client would
                    // get hook calls for all initial values, even if they
                    // didn't change from the default values on the client.
                    // see also: https://github.com/vis2k/Mirror/issues/1278

                    // IMPORTANT: for GameObjects/NetworkIdentities we usually
                    //            use SyncVarGameObjectEqual to compare equality.
                    //            in this case however, we can just use
                    //            SyncVarEqual with the two uint netIds.
                    //            => this is easier weaver code because we don't
                    //               have to get the GameObject/NetworkIdentity
                    //               from the uint netId
                    //            => this is faster because we void one
                    //               GetComponent call for GameObjects to get
                    //               their NetworkIdentity when comparing.

                    // Generates: if (!SyncVarEqual);
                    Instruction syncVarEqualLabel = serWorker.Create(OpCodes.Nop);

                    // 'this.' for 'this.SyncVarEqual'
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    // 'oldNetId'
                    serWorker.Append(serWorker.Create(OpCodes.Ldloc, oldNetId));
                    // 'ref this.__netId'
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    serWorker.Append(serWorker.Create(OpCodes.Ldflda, netIdField));
                    // call the function
                    GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(Weaver.syncVarEqualReference);
                    syncVarEqualGm.GenericArguments.Add(netIdField.FieldType);
                    serWorker.Append(serWorker.Create(OpCodes.Call, syncVarEqualGm));
                    serWorker.Append(serWorker.Create(OpCodes.Brtrue, syncVarEqualLabel));

                    // call the hook
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));           // this.
                    serWorker.Append(serWorker.Create(OpCodes.Ldloc, oldSyncVar)); // oldSyncVar GO/NI
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));           // this.
                    serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));    // syncvar.get (finds current GO/NI from netId)
                    serWorker.Append(serWorker.Create(OpCodes.Call, foundMethod));

                    // Generates: end if (!SyncVarEqual);
                    serWorker.Append(syncVarEqualLabel);
                }
            }
            // [SyncVar] int/float/struct/etc.?

            /*
             * Generates code like:
             *  int oldValue = a; // for hook
             *  Networka = reader.ReadPackedInt32();
             *  if (!SyncVarEqual(oldValue, ref a))
             *  {
             *      OnSetA(oldValue, Networka);
             *  }
             */
            else
            {
                MethodReference readFunc = Readers.GetReadFunc(syncVar.FieldType);
                if (readFunc == null)
                {
                    Weaver.Error($"{syncVar} has unsupported type. Use a supported Mirror type instead");
                    return;
                }

                // T oldValue = value;
                VariableDefinition oldValue = new VariableDefinition(syncVar.FieldType);
                deserialize.Body.Variables.Add(oldValue);
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));
                serWorker.Append(serWorker.Create(OpCodes.Stloc, oldValue));

                // read value and store in syncvar BEFORE calling the hook
                // -> this makes way more sense. by definition, the hook is
                //    supposed to be called after it was changed. not before.
                // -> setting it BEFORE calling the hook fixes the following bug:
                //    https://github.com/vis2k/Mirror/issues/1151 in host mode
                //    where the value during the Hook call would call Cmds on
                //    the host server, and they would all happen and compare
                //    values BEFORE the hook even returned and hence BEFORE the
                //    actual value was even set.
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));        // put 'this.' onto stack for 'this.syncvar' below
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));        // reader. for 'reader.Read()' below
                serWorker.Append(serWorker.Create(OpCodes.Call, readFunc)); // reader.Read()
                serWorker.Append(serWorker.Create(OpCodes.Stfld, syncVar)); // syncvar

                if (foundMethod != null)
                {
                    // call hook
                    // but only if SyncVar changed. otherwise a client would
                    // get hook calls for all initial values, even if they
                    // didn't change from the default values on the client.
                    // see also: https://github.com/vis2k/Mirror/issues/1278

                    // Generates: if (!SyncVarEqual);
                    Instruction syncVarEqualLabel = serWorker.Create(OpCodes.Nop);

                    // 'this.' for 'this.SyncVarEqual'
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    // 'oldValue'
                    serWorker.Append(serWorker.Create(OpCodes.Ldloc, oldValue));
                    // 'ref this.syncVar'
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                    serWorker.Append(serWorker.Create(OpCodes.Ldflda, syncVar));
                    // call the function
                    GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(Weaver.syncVarEqualReference);
                    syncVarEqualGm.GenericArguments.Add(syncVar.FieldType);
                    serWorker.Append(serWorker.Create(OpCodes.Call, syncVarEqualGm));
                    serWorker.Append(serWorker.Create(OpCodes.Brtrue, syncVarEqualLabel));

                    // call the hook
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));         // this.
                    serWorker.Append(serWorker.Create(OpCodes.Ldloc, oldValue)); // oldvalue
                    serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));         // this.
                    serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));  // syncvar.get
                    serWorker.Append(serWorker.Create(OpCodes.Call, foundMethod));

                    // Generates: end if (!SyncVarEqual);
                    serWorker.Append(syncVarEqualLabel);
                }
            }
        }
コード例 #8
0
    public void FindCoreReferences()
    {
        var types = new List <TypeDefinition>();

        AddAssemblyIfExists("mscorlib", types);
        AddAssemblyIfExists("System", types);
        AddAssemblyIfExists("System.Runtime", types);
        AddAssemblyIfExists("System.Core", types);
        AddAssemblyIfExists("netstandard", types);
        AddAssemblyIfExists("System.ObjectModel", types);
        AddAssemblyIfExists("System.Threading", types);

        var objectDefinition      = types.First(x => x.Name == "Object");
        var constructorDefinition = objectDefinition.Methods.First(x => x.IsConstructor);

        ObjectConstructor = ModuleDefinition.ImportReference(constructorDefinition);
        var objectEqualsMethodDefinition = objectDefinition.Methods.First(x => x.Name == "Equals" && x.Parameters.Count == 2);

        ObjectEqualsMethod = ModuleDefinition.ImportReference(objectEqualsMethodDefinition);

        var nullableDefinition = types.FirstOrDefault(x => x.Name == "Nullable");

        NullableEqualsMethod = ModuleDefinition.ImportReference(nullableDefinition).Resolve().Methods.First(x => x.Name == "Equals");

        EqualityComparerTypeReference = types.FirstOrDefault(x => x.Name == "EqualityComparer`1");

        var actionDefinition = types.First(x => x.Name == "Action");

        ActionTypeReference = ModuleDefinition.ImportReference(actionDefinition);

        var actionConstructor = actionDefinition.Methods.First(x => x.IsConstructor);

        ActionConstructorReference = ModuleDefinition.ImportReference(actionConstructor);

        var propChangedInterfaceDefinition = types.First(x => x.Name == "INotifyPropertyChanged");

        PropChangedInterfaceReference = ModuleDefinition.ImportReference(propChangedInterfaceDefinition);
        var propChangedHandlerDefinition = types.First(x => x.Name == "PropertyChangedEventHandler");

        PropChangedHandlerReference = ModuleDefinition.ImportReference(propChangedHandlerDefinition);
        ComponentModelPropertyChangedEventHandlerInvokeReference = ModuleDefinition.ImportReference(propChangedHandlerDefinition.Methods.First(x => x.Name == "Invoke"));
        var propChangedArgsDefinition = types.First(x => x.Name == "PropertyChangedEventArgs");

        ComponentModelPropertyChangedEventConstructorReference = ModuleDefinition.ImportReference(propChangedArgsDefinition.Methods.First(x => x.IsConstructor));

        var delegateDefinition      = types.First(x => x.Name == "Delegate");
        var combineMethodDefinition = delegateDefinition.Methods
                                      .Single(x =>
                                              x.Name == "Combine" &&
                                              x.Parameters.Count == 2 &&
                                              x.Parameters.All(p => p.ParameterType == delegateDefinition));

        DelegateCombineMethodRef = ModuleDefinition.ImportReference(combineMethodDefinition);
        var removeMethodDefinition = delegateDefinition.Methods.First(x => x.Name == "Remove");

        DelegateRemoveMethodRef = ModuleDefinition.ImportReference(removeMethodDefinition);

        var interlockedDefinition = types.First(x => x.FullName == "System.Threading.Interlocked");
        var genericCompareExchangeMethodDefinition = interlockedDefinition
                                                     .Methods.First(x =>
                                                                    x.IsStatic &&
                                                                    x.Name == "CompareExchange" &&
                                                                    x.GenericParameters.Count == 1 &&
                                                                    x.Parameters.Count == 3);
        var genericCompareExchangeMethod = ModuleDefinition.ImportReference(genericCompareExchangeMethodDefinition);

        InterlockedCompareExchangeForPropChangedHandler = new GenericInstanceMethod(genericCompareExchangeMethod);
        InterlockedCompareExchangeForPropChangedHandler.GenericArguments.Add(PropChangedHandlerReference);
    }
コード例 #9
0
        private void ProcessMethod(TypeDefinition type, MethodDefinition method, ICodeGenerator generator)
        {
            List <ParameterDefinition> dependencyParameters = method.Parameters.Where(
                p => p.CustomAttributes.Any(a => a.AttributeType.IsType(Import.AutoDI.DependencyAttributeType))).ToList();

            List <PropertyDefinition> dependencyProperties = method.IsConstructor ?
                                                             type.Properties.Where(p => p.CustomAttributes.Any(a => a.AttributeType.IsType(Import.AutoDI.DependencyAttributeType))).ToList() :
                                                             new List <PropertyDefinition>();

            if (dependencyParameters.Any() || dependencyProperties.Any())
            {
                Logger.Debug($"Processing method '{method.Name}' for '{method.DeclaringType.FullName}'", DebugLogLevel.Verbose);

                var injector = new Injector(method);

                IMethodGenerator methodGenerator = generator?.Method(method);
                foreach (ParameterDefinition parameter in dependencyParameters)
                {
                    if (!parameter.IsOptional)
                    {
                        Logger.Info(
                            $"Constructor parameter {parameter.ParameterType.Name} {parameter.Name} is marked with {Import.AutoDI.DependencyAttributeType.FullName} but is not an optional parameter. In {type.FullName}.");
                    }
                    if (parameter.Constant != null)
                    {
                        Logger.Warning(
                            $"Constructor parameter {parameter.ParameterType.Name} {parameter.Name} in {type.FullName} does not have a null default value. AutoDI will only resolve dependencies that are null");
                    }

                    var initInstruction  = Instruction.Create(OpCodes.Ldarg, parameter);
                    var storeInstruction = Instruction.Create(OpCodes.Starg, parameter);
                    ResolveDependency(parameter.ParameterType, parameter,
                                      new[] { initInstruction },
                                      null,
                                      storeInstruction,
                                      parameter.Name);
                }


                foreach (PropertyDefinition property in dependencyProperties)
                {
                    FieldDefinition backingField = null;
                    //Store the return from the resolve method in the method parameter
                    if (property.SetMethod == null)
                    {
                        //NB: Constant string, compiler detail... yuck yuck and double duck
                        backingField = property.DeclaringType.Fields.FirstOrDefault(f => f.Name == $"<{property.Name}>k__BackingField");
                        if (backingField == null)
                        {
                            Logger.Warning(
                                $"{property.FullName} is marked with {Import.AutoDI.DependencyAttributeType.FullName} but cannot be set. Dependency properties must either be auto properties or have a setter");
                            continue;
                        }
                    }

                    //injector.Insert(OpCodes.Call, property.GetMethod);
                    ResolveDependency(property.PropertyType, property,
                                      new[]
                    {
                        Instruction.Create(OpCodes.Ldarg_0),
                        Instruction.Create(OpCodes.Call, property.GetMethod),
                    },
                                      Instruction.Create(OpCodes.Ldarg_0),
                                      property.SetMethod != null
                            ? Instruction.Create(OpCodes.Call, property.SetMethod)
                            : Instruction.Create(OpCodes.Stfld, backingField),
                                      property.Name);
                }

                methodGenerator?.Append($"//We now return you to your regularly scheduled method{Environment.NewLine}");

                method.Body.OptimizeMacros();

                void ResolveDependency(TypeReference dependencyType, ICustomAttributeProvider source,
                                       Instruction[] loadSource,
                                       Instruction resolveAssignmentTarget,
                                       Instruction setResult,
                                       string dependencyName)
                {
                    //Push dependency parameter onto the stack
                    if (methodGenerator != null)
                    {
                        methodGenerator.Append($"if ({dependencyName} == null)", loadSource.First());
                        methodGenerator.Append(Environment.NewLine + "{" + Environment.NewLine);
                    }

                    injector.Insert(loadSource);
                    var afterParam = Instruction.Create(OpCodes.Nop);

                    //Push null onto the stack
                    injector.Insert(OpCodes.Ldnull);
                    //Push 1 if the values are equal, 0 if they are not equal
                    injector.Insert(OpCodes.Ceq);
                    //Branch if the value is false (0), the dependency was set by the caller we wont replace it
                    injector.Insert(OpCodes.Brfalse_S, afterParam);
                    //Push the dependency resolver onto the stack
                    if (resolveAssignmentTarget != null)
                    {
                        injector.Insert(resolveAssignmentTarget);
                    }

                    //Create parameters array
                    var dependencyAttribute = source.CustomAttributes.First(x => x.AttributeType.IsType(Import.AutoDI.DependencyAttributeType));
                    var values =
                        (dependencyAttribute.ConstructorArguments?.FirstOrDefault().Value as CustomAttributeArgument[])
                        ?.Select(x => x.Value)
                        .OfType <CustomAttributeArgument>()
                        .ToArray();
                    //Create array of appropriate length
                    Instruction loadArraySize = injector.Insert(OpCodes.Ldc_I4, values?.Length ?? 0);

                    if (methodGenerator != null)
                    {
                        methodGenerator.Append($"    {dependencyName} = GlobalDI.GetService<{dependencyType.FullNameCSharp()}>();", resolveAssignmentTarget ?? loadArraySize);
                        methodGenerator.Append(Environment.NewLine);
                    }

                    injector.Insert(OpCodes.Newarr, ModuleDefinition.ImportReference(Import.System.Object));
                    if (values?.Length > 0)
                    {
                        for (int i = 0; i < values.Length; ++i)
                        {
                            injector.Insert(OpCodes.Dup);
                            //Push the array index to insert
                            injector.Insert(OpCodes.Ldc_I4, i);
                            //Insert constant value with any boxing/conversion needed
                            InsertObjectConstant(injector, values[i].Value, values[i].Type.Resolve());
                            //Push the object into the array at index
                            injector.Insert(OpCodes.Stelem_Ref);
                        }
                    }

                    //Call the resolve method
                    var getServiceMethod = new GenericInstanceMethod(Import.AutoDI.GlobalDI.GetService)
                    {
                        GenericArguments = { ModuleDefinition.ImportReference(dependencyType) }
                    };

                    injector.Insert(OpCodes.Call, getServiceMethod);
                    //Set the return from the resolve method into the parameter
                    injector.Insert(setResult);
                    injector.Insert(afterParam);

                    if (methodGenerator != null)
                    {
                        methodGenerator.Append("}", afterParam);
                        methodGenerator.Append(Environment.NewLine);
                    }
                }
            }
        }
コード例 #10
0
        static void CreateConvertMethod(TypeDefinition authoringType, TypeDefinition componentDataType)
        {
            var moduleDefinition           = componentDataType.Module;
            var entityTypeReference        = moduleDefinition.ImportReference(typeof(Unity.Entities.Entity));
            var entityManagerTypeReference = moduleDefinition.ImportReference(typeof(Unity.Entities.EntityManager));
            var gameObjectTypeReference    = moduleDefinition.ImportReference(typeof(UnityEngine.GameObject));

            var convertMethod = new MethodDefinition("Convert",
                                                     MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.HideBySig |
                                                     MethodAttributes.Virtual, moduleDefinition.TypeSystem.Void)
            {
                Parameters =
                {
                    new ParameterDefinition("entity",             ParameterAttributes.None, entityTypeReference),
                    new ParameterDefinition("destinationManager", ParameterAttributes.None, entityManagerTypeReference),
                    new ParameterDefinition("conversionSystem",   ParameterAttributes.None,
                                            moduleDefinition.ImportReference(typeof(GameObjectConversionSystem)))
                }
            };

            authoringType.Methods.Add(convertMethod);

            // Make a local variable which we'll populate with the values stored in the MonoBehaviour
            var variableDefinition = new VariableDefinition(componentDataType);

            convertMethod.Body.Variables.Add(variableDefinition);

            var ilProcessor = convertMethod.Body.GetILProcessor();

            // Initialize the local variable.  (we might not need this, but all c# compilers emit it, so let's play it safe for now
            ilProcessor.Emit(OpCodes.Ldloca_S, variableDefinition);
            ilProcessor.Emit(OpCodes.Initobj, componentDataType);

            var getPrimaryEntityGameObjectMethod = moduleDefinition.ImportReference(
                typeof(GameObjectConversionSystem).GetMethod("GetPrimaryEntity", new Type[] { typeof(UnityEngine.GameObject) }));
            var getPrimaryEntityComponentMethod = moduleDefinition.ImportReference(
                typeof(GameObjectConversionSystem).GetMethod("GetPrimaryEntity", new Type[] { typeof(UnityEngine.Component) }));

            // Let's transfer every field in the MonoBehaviour over to the corresponding field in the IComponentData
            foreach (var field in authoringType.Fields)
            {
                var destinationField = componentDataType.Fields.Single(f => f.Name == field.Name);

                // Load the local iComponentData we are populating, so we can later write to it
                ilProcessor.Emit(OpCodes.Ldloca_S, variableDefinition);

                if (destinationField.FieldType.TypeReferenceEquals(entityTypeReference))
                {
                    // conversionSystem.GetPrimaryEntity(myThing);
                    ilProcessor.Emit(OpCodes.Ldarg_3);
                    ilProcessor.Emit(OpCodes.Ldarg_0);
                    ilProcessor.Emit(OpCodes.Ldfld, field);

                    var methodToCall = field.FieldType.TypeReferenceEquals(gameObjectTypeReference)
                        ? getPrimaryEntityGameObjectMethod
                        : getPrimaryEntityComponentMethod;
                    ilProcessor.Emit(OpCodes.Callvirt, methodToCall);
                }
                else
                {
                    // Load this (our MonoBehaviour itself)
                    ilProcessor.Emit(OpCodes.Ldarg_0);
                    // Load the field in question from the MonoBehaviour
                    ilProcessor.Emit(OpCodes.Ldfld, field);
                }

                // Store it to the IComponentData we already placed on the stack
                ilProcessor.Emit(OpCodes.Stfld, destinationField);
            }

            // Now that our local IComponentData is properly setup, the only thing left for us is to call:
            // entityManager.AddComponentData(entity, myPopulatedIComponentData).
            // IL method arguments go on the stack from first to last so:
            ilProcessor.Emit(OpCodes.Ldarg_2); //entityManager
            ilProcessor.Emit(OpCodes.Ldarg_1); //entity
            ilProcessor.Emit(OpCodes.Ldloc_0); //myPopulatedIComponentData

            // Build a MethodReference to EntityManager.AddComponentData<T>(Entity target, T payload);
            var addComponentDataMethodReference =
                new MethodReference("AddComponentData", moduleDefinition.TypeSystem.Void, entityManagerTypeReference)
            {
                HasThis    = true,
                Parameters =
                {
                    new ParameterDefinition("entity", ParameterAttributes.None, entityTypeReference),
                },
                ReturnType = moduleDefinition.TypeSystem.Boolean
            };
            var genericParameter = new GenericParameter("T", addComponentDataMethodReference);

            addComponentDataMethodReference.GenericParameters.Add(genericParameter);
            addComponentDataMethodReference.Parameters.Add(new ParameterDefinition("payload", ParameterAttributes.None,
                                                                                   genericParameter));

            // Since AddComponentData<T> is a generic method, we cannot call it super easily.
            // We have to wrap the generic method reference into a GenericInstanceMethod,
            // which let's us specify what we want to use for T for this specific invocation.
            // In our case T is the IComponentData we're operating on
            var genericInstanceMethod = new GenericInstanceMethod(addComponentDataMethodReference)
            {
                GenericArguments = { componentDataType },
            };

            ilProcessor.Emit(OpCodes.Callvirt, genericInstanceMethod);

            // Pop off return value since AddComponentData returns a bool
            ilProcessor.Emit(OpCodes.Pop);

            // We're done already!  Easy peasy.
            ilProcessor.Emit(OpCodes.Ret);
        }
コード例 #11
0
ファイル: Modify.cs プロジェクト: MrBlue/uMod.Patcher
        private Instruction CreateInstruction(MethodDefinition method, ILWeaver weaver, InstructionData instructionData, List <Instruction> insts, Patching.Patcher patcher)
        {
            OpCode      opcode      = opCodes[instructionData.OpCode];
            OpType      optype      = instructionData.OpType;
            Instruction Instruction = null;
            int         start;
            int         end;

            switch (optype)
            {
            case OpType.None:
                Instruction = Instruction.Create(opcode);
                break;

            case OpType.Byte:
                Instruction = Instruction.Create(opcode, Convert.ToByte(instructionData.Operand));
                break;

            case OpType.SByte:
                Instruction = Instruction.Create(opcode, Convert.ToSByte(instructionData.Operand));
                break;

            case OpType.Int32:
                Instruction = Instruction.Create(opcode, Convert.ToInt32(instructionData.Operand));
                break;

            case OpType.Int64:
                Instruction = Instruction.Create(opcode, Convert.ToInt64(instructionData.Operand));
                break;

            case OpType.Single:
                Instruction = Instruction.Create(opcode, Convert.ToSingle(instructionData.Operand));
                break;

            case OpType.Double:
                Instruction = Instruction.Create(opcode, Convert.ToDouble(instructionData.Operand));
                break;

            case OpType.String:
                Instruction = Instruction.Create(opcode, Convert.ToString(instructionData.Operand));
                break;

            case OpType.VerbatimString:
                Instruction = Instruction.Create(opcode, Regex.Unescape(Convert.ToString(instructionData.Operand)));
                break;

            case OpType.Instruction:
                int index = Convert.ToInt32(instructionData.Operand);
                Instruction = Instruction.Create(opcode, index < 1024 ? weaver.Instructions[index] : insts[index - 1024]);
                break;

            case OpType.Variable:
                Instruction = Instruction.Create(opcode, method.Body.Variables[Convert.ToInt32(instructionData.Operand)]);
                break;

            case OpType.Parameter:
                Instruction = Instruction.Create(opcode, method.Parameters[Convert.ToInt32(instructionData.Operand)]);
                break;

            case OpType.Field:
                string[]       fieldData = Convert.ToString(instructionData.Operand).Split('|');
                TypeDefinition fieldType = GetType(fieldData[0], fieldData[1], patcher);
                if (fieldType == null)
                {
                    return(null);
                }

                FieldDefinition fieldField = fieldType.Fields.FirstOrDefault(f => f.Name.Equals(fieldData[2]));
                if (fieldField == null)
                {
                    ShowMsg($"The Field '{fieldData[2]}' for '{Name}' could not be found!", "Missing Field", patcher);
                    return(null);
                }
                Instruction = Instruction.Create(opcode, method.Module.Import(fieldField));
                break;

            case OpType.Method:
                string[]       methodData = Convert.ToString(instructionData.Operand).Split('|');
                TypeDefinition methodType = GetType(methodData[0], methodData[1], patcher);
                if (methodType == null)
                {
                    return(null);
                }

                if (methodData.Length > 3)
                {
                    methodData[2] = string.Join("|", methodData.Skip(2).ToArray());
                }
                MethodReference methodMethod;
                start = methodData[2].IndexOf('(');
                end   = methodData[2].IndexOf(')');
                if (start >= 0 && end >= 0 && start < end)
                {
                    string           name      = TagsRegex.Replace(methodData[2], string.Empty).Trim();
                    string           methodSig = methodData[2].Substring(start + 1, end - start - 1);
                    string[]         sigData   = methodSig.Split(',');
                    TypeDefinition[] sigTypes  = new TypeDefinition[sigData.Length];
                    for (int i = 0; i < sigData.Length; i++)
                    {
                        string s       = sigData[i];
                        string sigName = s.Trim();
                        string assem   = "mscorlib";
                        if (sigName.Contains('|'))
                        {
                            string[] split = sigName.Split('|');
                            assem   = split[0].Trim();
                            sigName = split[1].Trim();
                        }
                        TypeDefinition sigType = GetType(assem, sigName, patcher);
                        if (sigType == null)
                        {
                            ShowMsg($"SigType '{sigName}' not found", "Missing Method", patcher);
                            return(null);
                        }
                        sigTypes[i] = sigType;
                    }
                    methodMethod = null;
                    foreach (MethodDefinition methodDefinition in methodType.Methods)
                    {
                        if (!methodDefinition.Name.Equals(name) || methodDefinition.Parameters.Count != sigTypes.Length)
                        {
                            continue;
                        }

                        bool match = true;
                        for (int i = 0; i < methodDefinition.Parameters.Count; i++)
                        {
                            ParameterDefinition parameter = methodDefinition.Parameters[i];
                            if (!parameter.ParameterType.FullName.Equals(sigTypes[i].FullName))
                            {
                                match = false;
                                break;
                            }
                        }
                        if (!match)
                        {
                            continue;
                        }

                        methodMethod = methodDefinition;
                        break;
                    }
                }
                else
                {
                    string methodName = methodData[2];
                    int    position   = methodName.IndexOf('[');
                    if (position > 0)
                    {
                        methodName = methodName.Substring(0, position);
                    }

                    methodMethod = methodType.Methods.FirstOrDefault(f =>
                    {
                        if (!f.Name.Equals(methodName))
                        {
                            return(false);
                        }

                        if (position <= 0)
                        {
                            return(true);
                        }

                        return(f.HasGenericParameters);
                    });
                }
                if (methodMethod == null)
                {
                    ShowMsg($"The Method '{methodData[2]}' for '{Name}' could not be found!", "Missing Method", patcher);
                    return(null);
                }
                start = methodData[2].IndexOf('[');
                end   = methodData[2].IndexOf(']');
                if (start >= 0 && end >= 0 && start < end)
                {
                    GenericInstanceMethod generic = new GenericInstanceMethod(methodMethod);
                    string           methodG      = methodData[2].Substring(start + 1, end - start - 1);
                    string[]         genData      = methodG.Split(',');
                    TypeDefinition[] genTypes     = new TypeDefinition[genData.Length];
                    for (int i = 0; i < genData.Length; i++)
                    {
                        string s       = genData[i];
                        string genName = s.Trim();
                        string assem   = "mscorlib";
                        if (genName.Contains('|'))
                        {
                            string[] split = genName.Split('|');
                            assem   = split[0].Trim();
                            genName = split[1].Trim();
                        }
                        TypeDefinition genType = GetType(assem, genName, patcher);
                        if (genType == null)
                        {
                            ShowMsg($"GenericType '{genName}' not found", "Missing Method", patcher);
                            return(null);
                        }
                        genTypes[i] = genType;
                    }
                    foreach (TypeDefinition type in genTypes)
                    {
                        generic.GenericArguments.Add(type);
                    }

                    methodMethod = generic;
                }
                Instruction = Instruction.Create(opcode, method.Module.Import(methodMethod));
                break;

            case OpType.Generic:
                break;

            case OpType.Type:
                string[]      typeData = Convert.ToString(instructionData.Operand).Split('|');
                TypeReference typeType = GetType(typeData[0], TagsRegex.Replace(typeData[1], string.Empty).Trim(), patcher);
                if (typeType == null)
                {
                    return(null);
                }

                start = typeData[1].IndexOf('[');
                end   = typeData[1].IndexOf(']');
                if (start >= 0 && end >= 0 && start < end)
                {
                    GenericInstanceType generic = new GenericInstanceType(typeType);
                    string           typeG      = typeData[1].Substring(start + 1, end - start - 1);
                    string[]         genData    = typeG.Split(',');
                    TypeDefinition[] genTypes   = new TypeDefinition[genData.Length];
                    for (int i = 0; i < genData.Length; i++)
                    {
                        string s       = genData[i];
                        string genName = s.Trim();
                        string assem   = "mscorlib";
                        if (genName.Contains('|'))
                        {
                            string[] split = genName.Split('|');
                            assem   = split[0].Trim();
                            genName = split[1].Trim();
                        }
                        TypeDefinition genType = GetType(assem, genName, patcher);
                        if (genType == null)
                        {
                            ShowMsg($"GenericType '{genName}' not found", "Missing Type", patcher);
                            return(null);
                        }
                        genTypes[i] = genType;
                    }
                    foreach (TypeDefinition type in genTypes)
                    {
                        generic.GenericArguments.Add(type);
                    }

                    typeType = generic;
                }
                Instruction = Instruction.Create(opcode, method.Module.Import(typeType));
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
            return(Instruction);
        }
コード例 #12
0
        public bool Execute(TypeDefinition type, MethodDefinition methodDefinition,
                            object parameterDefinitionOrFieldDefinition, CustomAttribute attribute, int instructionIndex)
        {
            TypeReference    targetType     = null;
            MethodDefinition selectedMethod = null;

            var parameterDefinition = parameterDefinitionOrFieldDefinition as ParameterDefinition;

            if (parameterDefinition != null)
            {
                targetType = parameterDefinition.ParameterType;
            }

            var fieldDefinition = parameterDefinitionOrFieldDefinition as FieldDefinition;

            if (fieldDefinition != null)
            {
                targetType = fieldDefinition.FieldType;
            }

            if (targetType != null)
            {
                try
                {
                    SelectMethod(_argumentTypeDefinition, targetType, out selectedMethod);
                }
                catch (Exception ex)
                {
                    var error = $"[{type.FullName}.{methodDefinition.Name}] {ex.Message}";

                    var sequencePoint = methodDefinition.GetFirstSequencePoint();
                    if (sequencePoint != null)
                    {
                        FodyEnvironment.WriteErrorPoint(error, sequencePoint);
                    }
                    else
                    {
                        FodyEnvironment.WriteError(error);
                    }

                    return(false);
                }
            }

            if (selectedMethod is null)
            {
                return(false);
            }

            var moduleDefinition = type.Module;
            var importedMethod   = moduleDefinition.ImportReference(selectedMethod);

            var instructions = new List <Instruction>();

            if (parameterDefinition != null)
            {
                BuildInstructions(moduleDefinition, type, methodDefinition, parameterDefinition, attribute, instructions);
            }

            if (fieldDefinition != null)
            {
                BuildInstructions(moduleDefinition, type, methodDefinition, fieldDefinition, attribute, instructions);
            }

            if (importedMethod.HasGenericParameters)
            {
                var genericInstanceMethod = new GenericInstanceMethod(importedMethod);
                genericInstanceMethod.GenericArguments.Add(targetType);
                instructions.Add(Instruction.Create(OpCodes.Call, genericInstanceMethod));
            }
            else
            {
                instructions.Add(Instruction.Create(OpCodes.Call, importedMethod));
            }

            methodDefinition.Body.Instructions.Insert(instructionIndex, instructions);

            return(true);
        }
コード例 #13
0
ファイル: RpcPostProcessor.cs プロジェクト: NoDogsInc/Cube
    MethodDefinition CreateDispatchRpcs(List <MethodDefinition> remoteMethods)
    {
        var method = new MethodDefinition("DispatchRpc", Mono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.Virtual, voidTypeReference);

        method.Parameters.Add(new ParameterDefinition("methodIdx", Mono.Cecil.ParameterAttributes.None, MainModule.TypeSystem.Byte));
        method.Parameters.Add(new ParameterDefinition("bs", Mono.Cecil.ParameterAttributes.None, Import(bitReaderType)));

        method.Body.InitLocals = true;

        var il = method.Body.GetILProcessor();

        var foo = new List <Instruction>();

        // switch (methodIdx)
        for (int i = 0; i < remoteMethods.Count; ++i)
        {
            var boo = il.Create(OpCodes.Nop);
            foo.Add(boo);

            il.Emit(OpCodes.Ldarg_1);
            if (i == 0)
            {
                il.Emit(OpCodes.Brfalse_S, boo);
            }
            else
            {
                il.Emit(OpCodes.Ldc_I4_S, (sbyte)i);
                il.Emit(OpCodes.Beq_S, boo);
            }
        }

        var boo2 = il.Create(OpCodes.Nop);

        foo.Add(boo2);
        il.Emit(OpCodes.Br_S, boo2);

        // T argN = bs.Read...();
        for (int i = 0; i < remoteMethods.Count; ++i)
        {
            var remoteMethod = remoteMethods[i];

            il.Append(foo[i]);

            var moo = new List <byte>();
            for (int j = 0; j < remoteMethod.Parameters.Count; ++j)
            {
                var param   = remoteMethod.Parameters[j];
                var typeDef = param.ParameterType.Resolve();

                MethodReference result          = null;
                bool            isReplica       = param.ParameterType.Name == "Replica";
                bool            isNetworkObject = TypeInheritsFrom(typeDef, "Cube.Replication.NetworkObject");
                bool            isSerializable  = typeDef.Interfaces.Any(type => type.InterfaceType.FullName == typeof(Cube.Transport.IBitSerializable).FullName);
                if (isReplica)
                {
                    result = bitStreamRead["ReplicaId"];
                }
                else if (isNetworkObject)
                {
                    result = bitStreamRead["T"];
                }
                else if (isSerializable)
                {
                    result = readSerializable;
                }
                else
                {
                    if (typeDef.IsEnum)
                    {
                        typeDef = GetEnumUnderlyingType(typeDef).Resolve();
                    }

                    result = bitStreamRead[typeDef.Name];
                }

                moo.Add((byte)(method.Body.Variables.Count));

                if (isReplica)
                {
                    method.Body.Variables.Add(new VariableDefinition(Import(replicaType)));

                    // Replica replica = base.ReplicaManager.GetReplica(bs.ReadReplicaId());
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Call, Import(replicaManagerProperty.GetMethod));

                    il.Emit(OpCodes.Ldarg_2);
                    il.Emit(OpCodes.Call, Import(result.Resolve()));
                    il.Emit(OpCodes.Callvirt, Import(replicaManagerGetReplicaMethod));

                    il.Emit(OpCodes.Stloc, method.Body.Variables.Count - 1);
                }
                else if (isNetworkObject)
                {
                    method.Body.Variables.Add(new VariableDefinition(Import(param.ParameterType.Resolve())));

                    // Replace generic arguments with some vodoo magic
                    var mmm = new GenericInstanceMethod(readNetworkObject);
                    mmm.GenericArguments.Add(Import(param.ParameterType.Resolve()));

                    var mr = MainModule.ImportReference(mmm);

                    il.Emit(OpCodes.Ldarg_2);
                    il.Emit(OpCodes.Call, mr);

                    il.Emit(OpCodes.Stloc, method.Body.Variables.Count - 1);
                }
                else if (isSerializable)
                {
                    method.Body.Variables.Add(new VariableDefinition(Import(param.ParameterType.Resolve())));

                    // default(DamageInfo).Deserialize(bs);
                    il.Emit(OpCodes.Ldloca, method.Body.Variables.Count - 1);
                    il.Emit(OpCodes.Initobj, param.ParameterType.Resolve());
                    il.Emit(OpCodes.Ldloca, method.Body.Variables.Count - 1);
                    il.Emit(OpCodes.Ldarg_2);

                    var deserialize = Import(GetMethodDefinitionByName(param.ParameterType.Resolve(), "Deserialize"));
                    il.Emit(OpCodes.Call, deserialize);
                }
                else
                {
                    method.Body.Variables.Add(new VariableDefinition(Import(param.ParameterType.Resolve())));

                    // var valN = bs.Read...();
                    il.Emit(OpCodes.Ldarg_2);
                    il.Emit(OpCodes.Callvirt, Import(result.Resolve()));

                    il.Emit(OpCodes.Stloc, method.Body.Variables.Count - 1);
                }
            }

            // Rpc(arg0, arg1, ...);
            il.Emit(OpCodes.Ldarg_0);
            for (int j = 0; j < remoteMethod.Parameters.Count; ++j)
            {
                var idx = moo.Count - remoteMethod.Parameters.Count + j;
                il.Emit(OpCodes.Ldloc_S, moo[idx]);
            }
            il.Emit(OpCodes.Call, remoteMethod);
            il.Emit(OpCodes.Ret);
        }

        // Debug.LogError((object)"Missing RPC dispatch");
        il.Append(foo[foo.Count - 1]);
        il.Emit(OpCodes.Ldstr, "Missing RPC dispatch");
        il.Emit(OpCodes.Call, debugLogErrorMethod);
        il.Emit(OpCodes.Ret);

        return(method);
    }
コード例 #14
0
        /// <summary>
        /// Rewrites the specified <see cref="MethodReference"/>.
        /// </summary>
        /// <param name="method">The method reference to rewrite.</param>
        /// <param name="module">The module definition that is being visited.</param>
        /// <returns>The rewritten method, or the original if it was not changed.</returns>
        protected MethodReference RewriteMethodReference(MethodReference method, ModuleDefinition module)
        {
            MethodReference result = method;

            TypeReference declaringType = this.RewriteDeclaringTypeReference(method);

            if (method.DeclaringType == declaringType)
            {
                // We are not rewriting this method.
                return(result);
            }

            MethodDefinition resolvedMethod        = Resolve(method);
            TypeDefinition   resolvedDeclaringType = Resolve(declaringType);

            // This is an extra initial parameter that we have when converting an instance to a static method.
            // For example, `task.GetAwaiter()` is converted to `ControlledTask.GetAwaiter(task)`.
            ParameterDefinition instanceParameter = null;
            MethodDefinition    match             = FindMatchingMethodInDeclaringType(resolvedMethod, resolvedDeclaringType);

            if (match != null)
            {
                result = module.ImportReference(match);
                if (resolvedMethod.Parameters.Count != match.Parameters.Count)
                {
                    // We are converting from an instance method to a static method, so store the instance parameter.
                    instanceParameter = result.Parameters[0];
                }
            }

            TypeReference returnType = this.RewriteTypeReference(method.ReturnType);

            // Instantiate the method reference to set its generic arguments and parameters, if any.
            result = new MethodReference(result.Name, returnType, declaringType)
            {
                HasThis           = result.HasThis,
                ExplicitThis      = result.ExplicitThis,
                CallingConvention = result.CallingConvention
            };

            if (resolvedMethod.HasGenericParameters)
            {
                // We need to instantiate the generic method.
                GenericInstanceMethod genericMethodInstance = new GenericInstanceMethod(result);

                var genericArgs      = new List <TypeReference>();
                int genericArgOffset = 0;

                if (declaringType is GenericInstanceType genericDeclaringType)
                {
                    // Populate the generic arguments with the generic declaring type arguments.
                    genericArgs.AddRange(genericDeclaringType.GenericArguments);
                    genericArgOffset = genericDeclaringType.GenericArguments.Count;
                }

                if (method is GenericInstanceMethod genericInstanceMethod)
                {
                    // Populate the generic arguments with the generic instance method arguments.
                    genericArgs.AddRange(genericInstanceMethod.GenericArguments);
                }

                for (int i = 0; i < resolvedMethod.GenericParameters.Count; i++)
                {
                    var p = resolvedMethod.GenericParameters[i];
                    var j = p.Position + genericArgOffset;
                    if (j > genericArgs.Count)
                    {
                        throw new InvalidOperationException(string.Format("Not enough generic arguments to instantiate method {0}", method));
                    }

                    GenericParameter parameter = new GenericParameter(p.Name, genericMethodInstance);
                    result.GenericParameters.Add(parameter);
                    genericMethodInstance.GenericParameters.Add(parameter);
                    genericMethodInstance.GenericArguments.Add(this.RewriteTypeReference(genericArgs[j]));
                }

                result = genericMethodInstance;
            }

            // Set the instance parameter of the method, if any.
            if (instanceParameter != null)
            {
                result.Parameters.Add(instanceParameter);
            }

            // Set the remaining parameters of the method, if any.
            foreach (var parameter in method.Parameters)
            {
                result.Parameters.Add(this.RewriteParameterDefinition(parameter));
            }

            return(module.ImportReference(result));
        }
コード例 #15
0
        private static TypeReference GetQueryCallExtent(Instruction queryInvocation)
        {
            GenericInstanceMethod method = (GenericInstanceMethod)queryInvocation.Operand;

            return(method.GenericArguments[0]);
        }
コード例 #16
0
        protected MethodDefinition GetOrCreateMethodProxy(MethodReference ifaceMethod)
        {
            var methodName = $"{ifaceMethod.DeclaringType.FullName}.{ifaceMethod.Name}";

            var proxy = _target.Methods.FirstOrDefault(m => m.IsExplicitImplementationOf(ifaceMethod));

            if (proxy == null)
            {
                proxy = new MethodDefinition(methodName,
                                             MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual,
                                             ifaceMethod.ReturnType);

                _target.Methods.Add(proxy);

                var ifaceMethodDef = ifaceMethod.Resolve();

                foreach (var gp in ifaceMethodDef.GenericParameters)
                {
                    proxy.GenericParameters.Add(gp.Clone(proxy));
                }

                TypeReference mayBeGeneric(TypeReference tr) => tr is GenericParameter gpr && gpr.Type == GenericParameterType.Method ? proxy.GenericParameters[gpr.Position] : tr;

                proxy.Mark(WellKnownTypes.DebuggerHiddenAttribute);
                //proxy.ReturnType = _target.Module.ImportReference(mayBeGeneric(ifaceMethod.ReturnType));

                if (ifaceMethod.Resolve().IsSpecialName)
                {
                    proxy.IsSpecialName = true;
                }

                foreach (var parameter in ifaceMethod.Parameters)
                {
                    proxy.Parameters.Add(new ParameterDefinition(parameter.Name, parameter.Attributes, parameter.ParameterType));
                }

                proxy.Overrides.Add(ifaceMethod);

                if (proxy.HasGenericParameters)
                {
                    //var ifaceRef = ifaceMethod.Resolve().DeclaringType.MakeReference();

                    var gref = new GenericInstanceMethod(ifaceMethod);
                    foreach (var gpar in proxy.GenericParameters)
                    {
                        gref.GenericArguments.Add(gpar);
                    }

                    ifaceMethod = gref;
                }

                proxy.Body.Instead(
                    e => e
                    .LoadAspect(_aspect)
                    .Call(ifaceMethod, args =>
                {
                    foreach (var pp in proxy.Parameters)
                    {
                        args = args.Load(pp);
                    }
                    return(args);
                })
                    .Return()
                    );
            }

            return(proxy);
        }
コード例 #17
0
        /// <summary>
        /// [SyncVar] GameObject/NetworkIdentity?
        /// </summary>
        /// <param name="syncVar"></param>
        /// <param name="serWorker"></param>
        /// <param name="deserialize"></param>
        /// <param name="initialState"></param>
        /// <param name="hookResult"></param>
        void DeserializeNetworkIdentityField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefinition deserialize, MethodDefinition hookMethod)
        {
            /*
             * Generates code like:
             * uint oldNetId = ___qNetId;
             * // returns GetSyncVarGameObject(___qNetId)
             * GameObject oldSyncVar = syncvar.getter;
             * ___qNetId = reader.ReadPackedUInt32();
             * if (!SyncVarEqual(oldNetId, ref ___goNetId))
             * {
             *     // getter returns GetSyncVarGameObject(___qNetId)
             *     OnSetQ(oldSyncVar, syncvar.getter);
             * }
             */

            // GameObject/NetworkIdentity SyncVar:
            //   OnSerialize sends writer.Write(go);
            //   OnDeserialize reads to __netId manually so we can use
            //     lookups in the getter (so it still works if objects
            //     move in and out of range repeatedly)
            FieldDefinition netIdField = syncVarNetIds[syncVar];

            // uint oldNetId = ___qNetId;
            VariableDefinition oldNetId = new VariableDefinition(Weaver.uint32Type);

            deserialize.Body.Variables.Add(oldNetId);
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
            serWorker.Append(serWorker.Create(OpCodes.Ldfld, netIdField));
            serWorker.Append(serWorker.Create(OpCodes.Stloc, oldNetId));

            // GameObject/NetworkIdentity oldSyncVar = syncvar.getter;
            VariableDefinition oldSyncVar = new VariableDefinition(syncVar.FieldType);

            deserialize.Body.Variables.Add(oldSyncVar);
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
            serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));
            serWorker.Append(serWorker.Create(OpCodes.Stloc, oldSyncVar));

            // read id and store in netId field BEFORE calling the hook
            // -> this makes way more sense. by definition, the hook is
            //    supposed to be called after it was changed. not before.
            // -> setting it BEFORE calling the hook fixes the following bug:
            //    https://github.com/vis2k/Mirror/issues/1151 in host mode
            //    where the value during the Hook call would call Cmds on
            //    the host server, and they would all happen and compare
            //    values BEFORE the hook even returned and hence BEFORE the
            //    actual value was even set.
            // put 'this.' onto stack for 'this.netId' below
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
            // reader. for 'reader.Read()' below
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
            // Read()
            serWorker.Append(serWorker.Create(OpCodes.Call, Readers.GetReadFunc(Weaver.uint32Type)));
            // netId
            serWorker.Append(serWorker.Create(OpCodes.Stfld, netIdField));

            if (hookMethod != null)
            {
                // call Hook(this.GetSyncVarGameObject/NetworkIdentity(reader.ReadPackedUInt32()))
                // because we send/receive the netID, not the GameObject/NetworkIdentity
                // but only if SyncVar changed. otherwise a client would
                // get hook calls for all initial values, even if they
                // didn't change from the default values on the client.
                // see also: https://github.com/vis2k/Mirror/issues/1278

                // IMPORTANT: for GameObjects/NetworkIdentities we usually
                //            use SyncVarGameObjectEqual to compare equality.
                //            in this case however, we can just use
                //            SyncVarEqual with the two uint netIds.
                //            => this is easier weaver code because we don't
                //               have to get the GameObject/NetworkIdentity
                //               from the uint netId
                //            => this is faster because we void one
                //               GetComponent call for GameObjects to get
                //               their NetworkIdentity when comparing.

                // Generates: if (!SyncVarEqual);
                Instruction syncVarEqualLabel = serWorker.Create(OpCodes.Nop);

                // 'this.' for 'this.SyncVarEqual'
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                // 'oldNetId'
                serWorker.Append(serWorker.Create(OpCodes.Ldloc, oldNetId));
                // 'ref this.__netId'
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldflda, netIdField));
                // call the function
                GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(Weaver.syncVarEqualReference);
                syncVarEqualGm.GenericArguments.Add(netIdField.FieldType);
                serWorker.Append(serWorker.Create(OpCodes.Call, syncVarEqualGm));
                serWorker.Append(serWorker.Create(OpCodes.Brtrue, syncVarEqualLabel));

                // call the hook
                // Generates: OnValueChanged(oldValue, this.syncVar);
                SyncVarProcessor.WriteCallHookMethodUsingField(serWorker, hookMethod, oldSyncVar, syncVar);

                // Generates: end if (!SyncVarEqual);
                serWorker.Append(syncVarEqualLabel);
            }
        }
コード例 #18
0
        public static MethodDefinition ProcessSyncVarSet(TypeDefinition td, FieldDefinition fd, string originalName, long dirtyBit, FieldDefinition netFieldId)
        {
            //Create the set method
            MethodDefinition set = new MethodDefinition("set_Network" + originalName, MethodAttributes.Public |
                                                        MethodAttributes.SpecialName |
                                                        MethodAttributes.HideBySig,
                                                        WeaverTypes.voidType);

            ILProcessor worker = set.Body.GetILProcessor();

            // if (!SyncVarEqual(value, ref playerData))
            Instruction endOfMethod = worker.Create(OpCodes.Nop);

            // this
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            // new value to set
            worker.Append(worker.Create(OpCodes.Ldarg_1));
            // reference to field to set
            // make generic version of SetSyncVar with field type
            if (fd.FieldType.FullName == WeaverTypes.gameObjectType.FullName)
            {
                // reference to netId Field to set
                worker.Append(worker.Create(OpCodes.Ldarg_0));
                worker.Append(worker.Create(OpCodes.Ldfld, netFieldId));

                worker.Append(worker.Create(OpCodes.Call, WeaverTypes.syncVarGameObjectEqualReference));
            }
            else if (fd.FieldType.FullName == WeaverTypes.NetworkIdentityType.FullName)
            {
                // reference to netId Field to set
                worker.Append(worker.Create(OpCodes.Ldarg_0));
                worker.Append(worker.Create(OpCodes.Ldfld, netFieldId));

                worker.Append(worker.Create(OpCodes.Call, WeaverTypes.syncVarNetworkIdentityEqualReference));
            }
            else
            {
                worker.Append(worker.Create(OpCodes.Ldarg_0));
                worker.Append(worker.Create(OpCodes.Ldflda, fd));

                GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(WeaverTypes.syncVarEqualReference);
                syncVarEqualGm.GenericArguments.Add(fd.FieldType);
                worker.Append(worker.Create(OpCodes.Call, syncVarEqualGm));
            }

            worker.Append(worker.Create(OpCodes.Brtrue, endOfMethod));

            // T oldValue = value;
            // TODO for GO/NI we need to backup the netId don't we?
            VariableDefinition oldValue = new VariableDefinition(fd.FieldType);

            set.Body.Variables.Add(oldValue);
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Ldfld, fd));
            worker.Append(worker.Create(OpCodes.Stloc, oldValue));

            // this
            worker.Append(worker.Create(OpCodes.Ldarg_0));

            // new value to set
            worker.Append(worker.Create(OpCodes.Ldarg_1));

            // reference to field to set
            worker.Append(worker.Create(OpCodes.Ldarg_0));
            worker.Append(worker.Create(OpCodes.Ldflda, fd));

            // dirty bit
            // 8 byte integer aka long
            worker.Append(worker.Create(OpCodes.Ldc_I8, dirtyBit));

            if (fd.FieldType.FullName == WeaverTypes.gameObjectType.FullName)
            {
                // reference to netId Field to set
                worker.Append(worker.Create(OpCodes.Ldarg_0));
                worker.Append(worker.Create(OpCodes.Ldflda, netFieldId));

                worker.Append(worker.Create(OpCodes.Call, WeaverTypes.setSyncVarGameObjectReference));
            }
            else if (fd.FieldType.FullName == WeaverTypes.NetworkIdentityType.FullName)
            {
                // reference to netId Field to set
                worker.Append(worker.Create(OpCodes.Ldarg_0));
                worker.Append(worker.Create(OpCodes.Ldflda, netFieldId));

                worker.Append(worker.Create(OpCodes.Call, WeaverTypes.setSyncVarNetworkIdentityReference));
            }
            else
            {
                // make generic version of SetSyncVar with field type
                GenericInstanceMethod gm = new GenericInstanceMethod(WeaverTypes.setSyncVarReference);
                gm.GenericArguments.Add(fd.FieldType);

                // invoke SetSyncVar
                worker.Append(worker.Create(OpCodes.Call, gm));
            }

            MethodDefinition hookMethod = GetHookMethod(td, fd);

            if (hookMethod != null)
            {
                //if (NetworkServer.localClientActive && !getSyncVarHookGuard(dirtyBit))
                Instruction label = worker.Create(OpCodes.Nop);
                worker.Append(worker.Create(OpCodes.Call, WeaverTypes.NetworkServerGetLocalClientActive));
                worker.Append(worker.Create(OpCodes.Brfalse, label));
                worker.Append(worker.Create(OpCodes.Ldarg_0));
                worker.Append(worker.Create(OpCodes.Ldc_I8, dirtyBit));
                worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getSyncVarHookGuard));
                worker.Append(worker.Create(OpCodes.Brtrue, label));

                // setSyncVarHookGuard(dirtyBit, true);
                worker.Append(worker.Create(OpCodes.Ldarg_0));
                worker.Append(worker.Create(OpCodes.Ldc_I8, dirtyBit));
                worker.Append(worker.Create(OpCodes.Ldc_I4_1));
                worker.Append(worker.Create(OpCodes.Call, WeaverTypes.setSyncVarHookGuard));

                // call hook (oldValue, newValue)
                // Generates: OnValueChanged(oldValue, value);
                WriteCallHookMethodUsingArgument(worker, hookMethod, oldValue);

                // setSyncVarHookGuard(dirtyBit, false);
                worker.Append(worker.Create(OpCodes.Ldarg_0));
                worker.Append(worker.Create(OpCodes.Ldc_I8, dirtyBit));
                worker.Append(worker.Create(OpCodes.Ldc_I4_0));
                worker.Append(worker.Create(OpCodes.Call, WeaverTypes.setSyncVarHookGuard));

                worker.Append(label);
            }

            worker.Append(endOfMethod);

            worker.Append(worker.Create(OpCodes.Ret));

            set.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.In, fd.FieldType));
            set.SemanticsAttributes = MethodSemanticsAttributes.Setter;

            return(set);
        }
コード例 #19
0
        /// <summary>
        /// [SyncVar] int/float/struct/etc.?
        /// </summary>
        /// <param name="syncVar"></param>
        /// <param name="serWorker"></param>
        /// <param name="deserialize"></param>
        /// <param name="initialState"></param>
        /// <param name="hookResult"></param>
        void DeserializeNormalField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefinition deserialize, MethodDefinition hookMethod)
        {
            /*
             * Generates code like:
             *  // for hook
             *  int oldValue = a;
             *  Networka = reader.ReadPackedInt32();
             *  if (!SyncVarEqual(oldValue, ref a))
             *  {
             *      OnSetA(oldValue, Networka);
             *  }
             */

            MethodReference readFunc = Readers.GetReadFunc(syncVar.FieldType);

            if (readFunc == null)
            {
                Weaver.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar);
                return;
            }

            // T oldValue = value;
            VariableDefinition oldValue = new VariableDefinition(syncVar.FieldType);

            deserialize.Body.Variables.Add(oldValue);
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
            serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));
            serWorker.Append(serWorker.Create(OpCodes.Stloc, oldValue));

            // read value and store in syncvar BEFORE calling the hook
            // -> this makes way more sense. by definition, the hook is
            //    supposed to be called after it was changed. not before.
            // -> setting it BEFORE calling the hook fixes the following bug:
            //    https://github.com/vis2k/Mirror/issues/1151 in host mode
            //    where the value during the Hook call would call Cmds on
            //    the host server, and they would all happen and compare
            //    values BEFORE the hook even returned and hence BEFORE the
            //    actual value was even set.
            // put 'this.' onto stack for 'this.syncvar' below
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
            // reader. for 'reader.Read()' below
            serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
            // reader.Read()
            serWorker.Append(serWorker.Create(OpCodes.Call, readFunc));
            // syncvar
            serWorker.Append(serWorker.Create(OpCodes.Stfld, syncVar));

            if (hookMethod != null)
            {
                // call hook
                // but only if SyncVar changed. otherwise a client would
                // get hook calls for all initial values, even if they
                // didn't change from the default values on the client.
                // see also: https://github.com/vis2k/Mirror/issues/1278

                // Generates: if (!SyncVarEqual);
                Instruction syncVarEqualLabel = serWorker.Create(OpCodes.Nop);

                // 'this.' for 'this.SyncVarEqual'
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                // 'oldValue'
                serWorker.Append(serWorker.Create(OpCodes.Ldloc, oldValue));
                // 'ref this.syncVar'
                serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
                serWorker.Append(serWorker.Create(OpCodes.Ldflda, syncVar));
                // call the function
                GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(Weaver.syncVarEqualReference);
                syncVarEqualGm.GenericArguments.Add(syncVar.FieldType);
                serWorker.Append(serWorker.Create(OpCodes.Call, syncVarEqualGm));
                serWorker.Append(serWorker.Create(OpCodes.Brtrue, syncVarEqualLabel));

                // call the hook
                // Generates: OnValueChanged(oldValue, this.syncVar);
                SyncVarProcessor.WriteCallHookMethodUsingField(serWorker, hookMethod, oldValue, syncVar);

                // Generates: end if (!SyncVarEqual);
                serWorker.Append(syncVarEqualLabel);
            }
        }
コード例 #20
0
        /// <summary>
        /// Get method signature of invoked method. It will be resolved with
        /// generic arguments while the method is invoked.
        /// </summary>
        /// <param name="method">Method to get resolved signature.</param>
        /// <returns>
        /// Method signature with generic parameters resolved, e.g.,
        /// List&lt;string&gt;.Add(string).
        /// Generic parameters are resolved to argument values.
        /// </returns>
        public static string GetResolvedMethodSignature(this MethodReference method)
        {
            string typeSignature = method.DeclaringType.GetResolvedTypeSignature();
            string methodSignature;

            if (method.Name.StartsWith(GetPrefix))
            {
                methodSignature = $"{method.Name.Substring(GetPrefix.Length)}.get";
            }
            else if (method.Name.StartsWith(SetPrefix))
            {
                methodSignature = $"{method.Name.Substring(SetPrefix.Length)}.set";
            }
            else
            {
                methodSignature = method.Name;
            }

            if (method.IsGenericInstance)
            {
                GenericInstanceMethod genericInstance = (GenericInstanceMethod)method;
                var genericParameters = genericInstance.GenericArguments.Select(genericArgument => genericArgument.GetResolvedTypeSignature());
                methodSignature = genericParameters.Count() != 0 ? $"{methodSignature}<{string.Join(",", genericParameters)}>" : methodSignature;
            }

            IEnumerable <string> parameters;

            if (method.IsGenericInstance)
            {
                GenericInstanceMethod genericInstanceMethod = (GenericInstanceMethod)method;
                parameters = method.Parameters.Select(parameter =>
                {
                    TypeReference resolvedParameterType = parameter.GetTypeWithGenericResolved(genericInstanceMethod);
                    if (resolvedParameterType.IsByReference)
                    {
                        ByReferenceType byReference = resolvedParameterType as ByReferenceType;
                        string prefix;
                        if (parameter.IsOut)
                        {
                            prefix = "out";
                        }
                        else if (parameter.IsIn)
                        {
                            prefix = "in";
                        }
                        else
                        {
                            prefix = "ref";
                        }

                        return($"{prefix}{byReference.ElementType.GetResolvedTypeSignature()}");
                    }

                    if (parameter.IsParams())
                    {
                        return($"params{resolvedParameterType.GetResolvedTypeSignature()}");
                    }

                    return(resolvedParameterType.GetResolvedTypeSignature());
                });
            }
            else
            {
                parameters = method.Parameters.Select(parameter =>
                {
                    TypeReference resolvedParameterType = parameter.GetTypeWithGenericResolved();
                    if (resolvedParameterType.IsByReference)
                    {
                        ByReferenceType byReference = resolvedParameterType as ByReferenceType;
                        string prefix;
                        if (parameter.IsOut)
                        {
                            prefix = "out";
                        }
                        else if (parameter.IsIn)
                        {
                            prefix = "in";
                        }
                        else
                        {
                            prefix = "ref";
                        }

                        return($"{prefix}{byReference.ElementType.GetResolvedTypeSignature()}");
                    }

                    if (parameter.IsParams())
                    {
                        return($"params{resolvedParameterType.GetResolvedTypeSignature()}");
                    }

                    return(resolvedParameterType.GetResolvedTypeSignature());
                });
            }

            return($"{typeSignature}.{methodSignature}({string.Join(",", parameters)})");
        }
コード例 #21
0
        public static void Patch(AssemblyDefinition ass)
        {
            var hardpatched = ass.MainModule.Resources.Any(r => string.Equals(r.Name, "ILRepack.List‎", StringComparison.InvariantCultureIgnoreCase));

            if (hardpatched)
            {
                Console.WriteLine("Could not patch PHMoreSlotID because the assembly is already hardpatched. Restore the original Assembly-CSharp and try again.");
                return;
            }

            foreach (var subdir in new[]
            {
                @"abdata\list\accessory",
                @"abdata\list\custommaterial",
                @"abdata\list\customtexture",
                @"abdata\list\hair",
                @"abdata\list\wear",
                @"abdata\thumnbnail_R",
            })
            {
                // Make sure the directories exist to mimic how the original was distributed, and to prevent crashes later on
                Directory.CreateDirectory(Path.Combine(Paths.GameRootPath, subdir));
            }

            var hookAss = AssemblyDefinition.ReadAssembly(Path.Combine(BepInEx.Paths.PatcherPluginPath, "PHMoreSlotIDPatchContainer.dll"));

            var customDataSetupLoader       = ass.MainModule.GetType("CustomDataSetupLoader`1") ?? throw new EntryPointNotFoundException("CustomDataSetupLoader`1");
            var customDataSetupLoaderAction = customDataSetupLoader.Fields.FirstOrDefault(m => m.Name == "action") ?? throw new EntryPointNotFoundException("action");

            {
                var targetMethod = customDataSetupLoader.Methods.FirstOrDefault(m => m.Name == "Setup") ?? throw new EntryPointNotFoundException("Setup");

                var hookMethod = hookAss.MainModule.GetType("PHMoreSlotIDPatchContainer.CustomDataSetupLoader`1").Methods.FirstOrDefault(m => m.Name == "Setup");
                var hookRef    = ass.MainModule.ImportReference(hookMethod);

                var il  = targetMethod.Body.GetILProcessor();
                var ins = targetMethod.Body.Instructions.First();

                il.InsertBefore(ins, il.Create(OpCodes.Ldarg_1));
                il.InsertBefore(ins, il.Create(OpCodes.Ldarg_2));
                il.InsertBefore(ins, il.Create(OpCodes.Ldarg_0));
                il.InsertBefore(ins, il.Create(OpCodes.Ldfld, customDataSetupLoaderAction));
                il.InsertBefore(ins, il.Create(OpCodes.Call, hookRef));
                il.InsertBefore(ins, il.Create(OpCodes.Ret));
            }

            {
                var targetMethod = customDataSetupLoader.Methods.FirstOrDefault(m => m.Name == "Setup_Search") ?? throw new EntryPointNotFoundException("Setup_Search");

                var hookMethod = hookAss.MainModule.GetType("PHMoreSlotIDPatchContainer.CustomDataSetupLoader`1").Methods.FirstOrDefault(m => m.Name == "Setup_Search");
                var hookRef    = ass.MainModule.ImportReference(hookMethod);

                var il  = targetMethod.Body.GetILProcessor();
                var ins = targetMethod.Body.Instructions.First();

                il.InsertBefore(ins, il.Create(OpCodes.Ldarg_1));
                il.InsertBefore(ins, il.Create(OpCodes.Ldarg_2));
                il.InsertBefore(ins, il.Create(OpCodes.Ldarg_0));
                il.InsertBefore(ins, il.Create(OpCodes.Ldfld, customDataSetupLoaderAction));
                il.InsertBefore(ins, il.Create(OpCodes.Call, hookRef));
                il.InsertBefore(ins, il.Create(OpCodes.Ret));
            }

            {
                var targetType   = ass.MainModule.GetType("AssetBundleController");
                var targetMethod = targetType.Methods.FirstOrDefault(m => m.Name == "LoadAsset") ?? throw new EntryPointNotFoundException("LoadAsset");

                var hookMethod     = hookAss.MainModule.GetType("PHMoreSlotIDPatchContainer.AssetBundleController").Methods.FirstOrDefault(m => m.Name == "LoadAsset");
                var hookRef        = ass.MainModule.ImportReference(hookMethod);
                var hookGenericRef = new GenericInstanceMethod(hookRef);
                hookGenericRef.GenericArguments.Add(targetMethod.GenericParameters[0]);

                var assetBundle     = targetType.Fields.FirstOrDefault(m => m.Name == "assetBundle") ?? throw new EntryPointNotFoundException("assetBundle");
                var directory       = targetType.Properties.FirstOrDefault(m => m.Name == "directory")?.GetMethod ?? throw new EntryPointNotFoundException("directory");
                var assetBundleName = targetType.Properties.FirstOrDefault(m => m.Name == "assetBundleName")?.GetMethod ?? throw new EntryPointNotFoundException("assetBundleName");

                var il  = targetMethod.Body.GetILProcessor();
                var ins = targetMethod.Body.Instructions.First();

                il.InsertBefore(ins, il.Create(OpCodes.Ldarg_1));
                il.InsertBefore(ins, il.Create(OpCodes.Ldarg_0));
                il.InsertBefore(ins, il.Create(OpCodes.Ldfld, assetBundle));
                il.InsertBefore(ins, il.Create(OpCodes.Ldarg_0));
                il.InsertBefore(ins, il.Create(OpCodes.Callvirt, directory));
                il.InsertBefore(ins, il.Create(OpCodes.Ldarg_0));
                il.InsertBefore(ins, il.Create(OpCodes.Callvirt, assetBundleName));
                il.InsertBefore(ins, il.Create(OpCodes.Call, hookGenericRef));
                il.InsertBefore(ins, il.Create(OpCodes.Ret));
            }

            {
                var targetType   = ass.MainModule.GetType("ItemDataBase");
                var targetMethod = targetType.Methods.FirstOrDefault(m => m.Name == ".ctor" && m.Parameters.Count == 5) ?? throw new EntryPointNotFoundException("ItemDataBase.ctor");

                var hookMethod = hookAss.MainModule.GetType("PHMoreSlotIDPatchContainer.ItemDataBase").Methods.FirstOrDefault(m => m.Name == "CtorPostfix");
                var hookRef    = ass.MainModule.ImportReference(hookMethod);

                var id = targetType.Fields.FirstOrDefault(m => m.Name == "id") ?? throw new EntryPointNotFoundException("id");

                var il  = targetMethod.Body.GetILProcessor();
                var ins = targetMethod.Body.Instructions.Last();

                il.InsertBefore(ins, il.Create(OpCodes.Ldarg_0));
                il.InsertBefore(ins, il.Create(OpCodes.Ldflda, id));
                il.InsertBefore(ins, il.Create(OpCodes.Ldarg_1));
                il.InsertBefore(ins, il.Create(OpCodes.Call, hookRef));
            }
        }
コード例 #22
0
        public static TypeReference GetTypeWithGenericResolved(this ParameterDefinition definition, GenericInstanceMethod genericInstanceMethod)
        {
            var  typeWithGenericResolved = definition.ParameterType;
            bool isByReference           = false;
            bool isArray   = false;
            int  arrayRank = 0;

            if (typeWithGenericResolved.IsByReference)
            {
                isByReference = true;
                ByReferenceType byReferenceType = (ByReferenceType)typeWithGenericResolved;
                typeWithGenericResolved = byReferenceType.ElementType;
            }

            if (typeWithGenericResolved.IsArray)
            {
                isArray = true;
                ArrayType arrayType = (ArrayType)typeWithGenericResolved;
                arrayRank = arrayType.Rank;
                typeWithGenericResolved = arrayType.ElementType;
            }

            if (typeWithGenericResolved.IsGenericInstance)
            {
                GenericInstanceType genericInstanceType = (GenericInstanceType)typeWithGenericResolved;
                typeWithGenericResolved = genericInstanceType.GetTypeWithGenericResolved(((MethodReference)definition.Method).DeclaringType as GenericInstanceType, genericInstanceMethod);
            }

            if (typeWithGenericResolved.IsGenericParameter)
            {
                GenericParameter genericParam = typeWithGenericResolved as GenericParameter;
                var declaringMethod           = (MethodReference)definition.Method;
                if (genericParam.DeclaringType != null && declaringMethod.DeclaringType is GenericInstanceType genericInstanceTypeOfParam)
                {
                    var position = genericInstanceTypeOfParam.ElementType.GenericParameters.GetIndexByName(typeWithGenericResolved.Name);
                    if (position != -1)
                    {
                        typeWithGenericResolved = genericInstanceTypeOfParam.GenericArguments[position];
                    }
                }
                else if (genericParam.DeclaringMethod != null && genericInstanceMethod != null)
                {
                    var position = declaringMethod.GetElementMethod().GenericParameters.GetIndexByName(typeWithGenericResolved.Name);
                    if (position != -1)
                    {
                        typeWithGenericResolved = genericInstanceMethod.GenericArguments[position];
                    }
                }
            }

            if (isArray)
            {
                typeWithGenericResolved = new ArrayType(typeWithGenericResolved, arrayRank);
            }

            if (isByReference)
            {
                typeWithGenericResolved = new ByReferenceType(typeWithGenericResolved);
            }

            return(typeWithGenericResolved);
        }
コード例 #23
0
ファイル: HookGenerator.cs プロジェクト: opl-/MonoMod
        public bool GenerateFor(TypeDefinition hookType, TypeDefinition hookILType, MethodDefinition method)
        {
            if (method.HasGenericParameters ||
                method.IsAbstract ||
                (method.IsSpecialName && !method.IsConstructor))
            {
                return(false);
            }

            if (!HookOrig && method.Name.StartsWith("orig_"))
            {
                return(false);
            }
            if (!HookPrivate && method.IsPrivate)
            {
                return(false);
            }

            string suffix = null;

            if (method.Parameters.Count == 0)
            {
                suffix = "";
            }

            IEnumerable <MethodDefinition> overloads = null;

            if (suffix == null)
            {
                overloads = method.DeclaringType.Methods.Where(other => !other.HasGenericParameters && other.Name == method.Name && other != method);
                if (overloads.Count() == 0)
                {
                    suffix = "";
                }
            }

            if (suffix == null)
            {
                StringBuilder builder = new StringBuilder();
                for (int parami = 0; parami < method.Parameters.Count; parami++)
                {
                    ParameterDefinition param = method.Parameters[parami];
                    if (!TypeNameMap.TryGetValue(param.ParameterType.FullName, out string typeName))
                    {
                        typeName = GetFriendlyName(param.ParameterType, false);
                    }

                    if (overloads.Any(other => {
                        ParameterDefinition otherParam = other.Parameters.ElementAtOrDefault(parami);
                        return
                        (otherParam != null &&
                         GetFriendlyName(otherParam.ParameterType, false) == typeName &&
                         otherParam.ParameterType.Namespace != param.ParameterType.Namespace);
                    }))
                    {
                        typeName = GetFriendlyName(param.ParameterType, true);
                    }

                    builder.Append("_");
                    builder.Append(typeName.Replace(".", "").Replace("`", ""));
                }
                suffix = builder.ToString();
            }

            string name = method.Name;

            if (name.StartsWith("."))
            {
                name = name.Substring(1);
            }
            name = name + suffix;

            if (hookType.FindEvent(name) != null)
            {
                string nameTmp;
                for (
                    int i = 1;
                    hookType.FindEvent(nameTmp = name + "_" + i) != null;
                    i++
                    )
                {
                    ;
                }
                name = nameTmp;
            }

            // TODO: Fix possible conflict when other members with the same names exist.

            TypeDefinition delOrig = GenerateDelegateFor(method);

            delOrig.Name = "orig_" + name;
            delOrig.CustomAttributes.Add(GenerateEditorBrowsable(EditorBrowsableState.Never));
            hookType.NestedTypes.Add(delOrig);

            TypeDefinition delHook = GenerateDelegateFor(method);

            delHook.Name = "hook_" + name;
            MethodDefinition delHookInvoke = delHook.FindMethod("Invoke");

            delHookInvoke.Parameters.Insert(0, new ParameterDefinition("orig", ParameterAttributes.None, delOrig));
            MethodDefinition delHookBeginInvoke = delHook.FindMethod("BeginInvoke");

            delHookBeginInvoke.Parameters.Insert(0, new ParameterDefinition("orig", ParameterAttributes.None, delOrig));
            delHook.CustomAttributes.Add(GenerateEditorBrowsable(EditorBrowsableState.Never));
            hookType.NestedTypes.Add(delHook);

            ILProcessor           il;
            GenericInstanceMethod endpointMethod;

            MethodReference methodRef = OutputModule.ImportReference(method);

            #region Hook

            MethodDefinition addHook = new MethodDefinition(
                "add_" + name,
                MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Static,
                OutputModule.TypeSystem.Void
                );
            addHook.Parameters.Add(new ParameterDefinition(null, ParameterAttributes.None, delHook));
            addHook.Body = new MethodBody(addHook);
            il           = addHook.Body.GetILProcessor();
            il.Emit(OpCodes.Ldtoken, methodRef);
            il.Emit(OpCodes.Call, m_GetMethodFromHandle);
            il.Emit(OpCodes.Ldarg_0);
            endpointMethod = new GenericInstanceMethod(m_Add);
            endpointMethod.GenericArguments.Add(delHook);
            il.Emit(OpCodes.Call, endpointMethod);
            il.Emit(OpCodes.Ret);
            hookType.Methods.Add(addHook);

            MethodDefinition removeHook = new MethodDefinition(
                "remove_" + name,
                MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Static,
                OutputModule.TypeSystem.Void
                );
            removeHook.Parameters.Add(new ParameterDefinition(null, ParameterAttributes.None, delHook));
            removeHook.Body = new MethodBody(removeHook);
            il = removeHook.Body.GetILProcessor();
            il.Emit(OpCodes.Ldtoken, methodRef);
            il.Emit(OpCodes.Call, m_GetMethodFromHandle);
            il.Emit(OpCodes.Ldarg_0);
            endpointMethod = new GenericInstanceMethod(m_Remove);
            endpointMethod.GenericArguments.Add(delHook);
            il.Emit(OpCodes.Call, endpointMethod);
            il.Emit(OpCodes.Ret);
            hookType.Methods.Add(removeHook);

            EventDefinition evHook = new EventDefinition(name, EventAttributes.None, delHook)
            {
                AddMethod    = addHook,
                RemoveMethod = removeHook
            };
            hookType.Events.Add(evHook);

            #endregion

            #region Hook IL

            MethodDefinition addIL = new MethodDefinition(
                "add_" + name,
                MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Static,
                OutputModule.TypeSystem.Void
                );
            addIL.Parameters.Add(new ParameterDefinition(null, ParameterAttributes.None, t_ILManipulator));
            addIL.Body = new MethodBody(addIL);
            il         = addIL.Body.GetILProcessor();
            il.Emit(OpCodes.Ldtoken, methodRef);
            il.Emit(OpCodes.Call, m_GetMethodFromHandle);
            il.Emit(OpCodes.Ldarg_0);
            endpointMethod = new GenericInstanceMethod(m_Modify);
            endpointMethod.GenericArguments.Add(delHook);
            il.Emit(OpCodes.Call, endpointMethod);
            il.Emit(OpCodes.Ret);
            hookILType.Methods.Add(addIL);

            MethodDefinition removeIL = new MethodDefinition(
                "remove_" + name,
                MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Static,
                OutputModule.TypeSystem.Void
                );
            removeIL.Parameters.Add(new ParameterDefinition(null, ParameterAttributes.None, t_ILManipulator));
            removeIL.Body = new MethodBody(removeIL);
            il            = removeIL.Body.GetILProcessor();
            il.Emit(OpCodes.Ldtoken, methodRef);
            il.Emit(OpCodes.Call, m_GetMethodFromHandle);
            il.Emit(OpCodes.Ldarg_0);
            endpointMethod = new GenericInstanceMethod(m_Unmodify);
            endpointMethod.GenericArguments.Add(delHook);
            il.Emit(OpCodes.Call, endpointMethod);
            il.Emit(OpCodes.Ret);
            hookILType.Methods.Add(removeIL);

            EventDefinition evIL = new EventDefinition(name, EventAttributes.None, t_ILManipulator)
            {
                AddMethod    = addIL,
                RemoveMethod = removeIL
            };
            hookILType.Events.Add(evIL);

            #endregion

            return(true);
        }
コード例 #24
0
        public void Inject()
        {
            var from = def.GetTypeRef(@params.FromClass);

            if (from == null)
            {
                from = self.GetTypeRef(@params.FromClass, true);
            }

            if (from == null)
            {
                Logging.DebugLogs("[{0}] Unable to find from type", GetType().Name);
                Logging.DebugLogs("\t{0} {1}", @params.FromClass, @params.ToClass);
                return;
            }

            var to = def.GetTypeRef(@params.ToClass);

            if (to == null)
            {
                to = self.GetTypeRef(@params.ToClass, true);
            }

            if (to == null)
            {
                Logging.DebugLogs("[{0}] Unable to find to type", GetType().Name);
                Logging.DebugLogs("\t{0} {1}", @params.FromClass, @params.ToClass);
                return;
            }

            var methods = def.Modules.SelectMany(m => m.Types).SelectMany(t => t.Methods).Where(m => m.HasBody).ToList();

            foreach (var method in methods)
            {
                var body         = method.Body;
                var instructions = body.Instructions;
                var processor    = body.GetILProcessor();

                for (int i = 0; i < instructions.Count; i++)
                {
                    var ins = instructions[i];
                    if (ins.OpCode == OpCodes.Call || ins.OpCode == OpCodes.Callvirt)
                    {
                        var @ref = (MethodReference)ins.Operand;
                        if (@ref.DeclaringType.FullName.Equals(@params.FromClass))
                        {
                            var redirect = to.Resolve().Methods.Where(m => m.Name.Equals(@ref.Name) && (@ref.Parameters.Count + 1) == m.Parameters.Count).FirstOrDefault();
                            if (redirect != null)
                            {
                                var call = def.Import(redirect);
                                if (@ref is GenericInstanceMethod)
                                {
                                    GenericInstanceMethod genericCall = new GenericInstanceMethod(def.Import(redirect));
                                    var gim = (GenericInstanceMethod)@ref;
                                    foreach (var arg in gim.GenericArguments)
                                    {
                                        genericCall.GenericArguments.Add(arg);
                                    }
                                    call = genericCall;
                                }

                                processor.Replace(ins, processor.Create(OpCodes.Call, call));
                            }
                        }
                    }
                }
            }
        }
コード例 #25
0
ファイル: ModuleWeaver.cs プロジェクト: sandboxorg/Ionad
    private void ReplaceCalls(MethodBody body, Dictionary <TypeDefinition, TypeDefinition> replacements)
    {
        body.SimplifyMacros();

        var calls = body.Instructions.Where(i => i.OpCode == OpCodes.Call);

        foreach (var call in calls)
        {
            var originalMethodReference  = (MethodReference)call.Operand;
            var originalMethodDefinition = originalMethodReference.Resolve();
            var declaringTypeReference   = originalMethodReference.DeclaringType;
            var declaringTypeDefinition  = declaringTypeReference.Resolve();

            if (!originalMethodDefinition.IsStatic || !replacements.ContainsKey(declaringTypeDefinition))
            {
                continue;
            }

            var replacementTypeReference = ModuleDefinition.ImportReference(replacements[declaringTypeDefinition]);
            if (declaringTypeReference.IsGenericInstance)
            {
                var declaringGenericType = (GenericInstanceType)declaringTypeReference;
                var genericType          = new GenericInstanceType(replacementTypeReference);
                foreach (var arg in declaringGenericType.GenericArguments)
                {
                    genericType.GenericArguments.Add(arg);
                }
                replacementTypeReference = ModuleDefinition.ImportReference(genericType);
            }

            var replacementMethod = replacementTypeReference.ReferenceMethod(originalMethodDefinition.Name);

            if (replacementMethod == null)
            {
                LogError($"Missing '{declaringTypeDefinition.FullName}.{originalMethodDefinition.Name}()' in '{replacementTypeReference.FullName}'");
                continue;
            }

            if (!replacementMethod.Resolve().IsStatic)
            {
                LogError($"Replacement method '{replacementMethod.FullName}' is not static");
                continue;
            }

            if (originalMethodReference.IsGenericInstance)
            {
                var originalGenericInstanceMethod = (GenericInstanceMethod)originalMethodReference;
                var genericInstanceMethod         = new GenericInstanceMethod(replacementMethod);
                foreach (var arg in originalGenericInstanceMethod.GenericArguments)
                {
                    genericInstanceMethod.GenericArguments.Add(arg);
                }

                call.Operand = ModuleDefinition.ImportReference(genericInstanceMethod);
            }
            else
            {
                call.Operand = replacementMethod;
            }
        }

        body.InitLocals = true;
        body.OptimizeMacros();
    }
コード例 #26
0
 public void Add(GenericInstanceMethod genericInstanceMethod)
 {
     this.Add(TypeResolver.ElementTypeFor(genericInstanceMethod).FullName, genericInstanceMethod);
 }
コード例 #27
0
        Expression ConvertCall(InvocationExpression invocation)
        {
            if (invocation.Arguments.Count < 2)
            {
                return(NotSupported(invocation));
            }

            Expression target;
            int        firstArgumentPosition;

            Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(0));

            if (m.Success)
            {
                target = null;
                firstArgumentPosition = 1;
            }
            else
            {
                m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1));
                if (!m.Success)
                {
                    return(NotSupported(invocation));
                }
                target = invocation.Arguments.ElementAt(0);
                firstArgumentPosition = 2;
            }

            MethodReference mr = m.Get <AstNode>("method").Single().Annotation <MethodReference>();

            if (mr == null)
            {
                return(null);
            }

            Expression convertedTarget;

            if (target == null || target is NullReferenceExpression)
            {
                // static method
                if (m.Has("declaringType"))
                {
                    convertedTarget = new TypeReferenceExpression(m.Get <AstType>("declaringType").Single().Clone());
                }
                else
                {
                    convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(mr.DeclaringType));
                }
            }
            else
            {
                convertedTarget = Convert(target);
                if (convertedTarget == null)
                {
                    return(null);
                }
            }

            MemberReferenceExpression mre = convertedTarget.Member(mr.Name);
            GenericInstanceMethod     gim = mr as GenericInstanceMethod;

            if (gim != null)
            {
                foreach (TypeReference tr in gim.GenericArguments)
                {
                    mre.TypeArguments.Add(AstBuilder.ConvertType(tr));
                }
            }
            IList <Expression> arguments = null;

            if (invocation.Arguments.Count == firstArgumentPosition + 1)
            {
                Expression argumentArray = invocation.Arguments.ElementAt(firstArgumentPosition);
                arguments = ConvertExpressionsArray(argumentArray);
            }
            if (arguments == null)
            {
                arguments = new List <Expression>();
                foreach (Expression argument in invocation.Arguments.Skip(firstArgumentPosition))
                {
                    Expression convertedArgument = Convert(argument);
                    if (convertedArgument == null)
                    {
                        return(null);
                    }
                    arguments.Add(convertedArgument);
                }
            }
            MethodDefinition methodDef = mr.Resolve();

            if (methodDef != null && methodDef.IsGetter)
            {
                PropertyDefinition indexer = AstMethodBodyBuilder.GetIndexer(methodDef);
                if (indexer != null)
                {
                    return(new IndexerExpression(mre.Target.Detach(), arguments).WithAnnotation(indexer));
                }
            }
            return(new InvocationExpression(mre, arguments).WithAnnotation(mr));
        }
コード例 #28
0
        static private void Manage(this MethodDefinition method)
        {
            var _metadata     = method.Metadata();
            var _machine      = method.CustomAttributes.SingleOrDefault(_Attribute => _Attribute.AttributeType.Resolve() == method.Module.Import(typeof(AsyncStateMachineAttribute)).Resolve());
            var _authentic    = method.Authentic();
            var _intermediate = method.Intermediate(_authentic);

            method.Body = new MethodBody(method);
            for (var _index = 0; _index < _authentic.Parameters.Count; _index++)
            {
                switch (_index)
                {
                case 0: method.Body.Emit(OpCodes.Ldarg_0); break;

                case 1: method.Body.Emit(OpCodes.Ldarg_1); break;

                case 2: method.Body.Emit(OpCodes.Ldarg_2); break;

                case 3: method.Body.Emit(OpCodes.Ldarg_3); break;

                default: method.Body.Emit(OpCodes.Ldarg_S, method.Parameters[method.IsStatic ? _index : _index - 1]); break;
                }
            }
            if (method.GenericParameters.Count == 0)
            {
                method.Body.Emit(OpCodes.Ldsfld, _intermediate);
                method.Body.Emit(OpCodes.Calli, method.ReturnType, _authentic.Parameters);
            }
            else
            {
                var _type = new GenericInstanceType(_intermediate.DeclaringType);
                foreach (var _parameter in method.GenericParameters)
                {
                    _type.GenericArguments.Add(_parameter);
                }
                method.Body.Emit(OpCodes.Ldsfld, new FieldReference(_intermediate.Name, _intermediate.FieldType, _type));
                var _method = new GenericInstanceMethod(_authentic);
                foreach (var _parameter in method.GenericParameters)
                {
                    _method.GenericArguments.Add(_parameter);
                }
                method.Body.Emit(OpCodes.Calli, _method.ReturnType, _method.Parameters);
            }
            method.Body.Emit(OpCodes.Ret);
            method.Body.OptimizeMacros();
            if (_machine != null)
            {
                var _type     = _machine.ConstructorArguments[0].Value as TypeDefinition;
                var _factory  = _type.Field <Advice.Boundary.IFactory>("<Factory>", FieldAttributes.Public | FieldAttributes.Static);
                var _boundary = _type.Field <Advice.IBoundary>("<Boundary>", FieldAttributes.Public);
                _type.IsBeforeFieldInit = true;
                var _intializer = _type.Initializer();
                _intializer.Body.Emit(OpCodes.Newobj, System.Reflection.Metadata.Constructor(() => new Advice.Boundary.Factory()));
                _intializer.Body.Emit(OpCodes.Stsfld, _factory.Relative());
                _intializer.Body.Emit(OpCodes.Ret);
                var _constructor = _type.Methods.Single(m => m.IsConstructor && !m.IsStatic);
                _constructor.Body = new MethodBody(_constructor);
                _constructor.Body.Emit(OpCodes.Ldarg_0);
                _constructor.Body.Emit(OpCodes.Call, System.Reflection.Metadata.Constructor(() => new object()));
                _constructor.Body.Emit(OpCodes.Ldarg_0);
                _constructor.Body.Emit(OpCodes.Ldsfld, _constructor.Module.Import(_factory.Relative()));
                _constructor.Body.Emit(OpCodes.Callvirt, System.Reflection.Metadata <Advice.Boundary.IFactory> .Method(_Factory => _Factory.Create()));
                _constructor.Body.Emit(OpCodes.Stfld, _boundary.Relative());
                _constructor.Body.Emit(OpCodes.Ret);
                var _move     = _type.Methods.Single(_Method => _Method.Name == "MoveNext");
                var _instance = method.IsStatic ? null : _type.Fields.Single(_Field => _Field.Name == "<>4__this").Relative();
                var _state    = _type.Fields.Single(_Field => _Field.Name == "<>1__state").Relative();
                var _builder  = _type.Fields.Single(_Field => _Field.Name == "<>t__builder").Relative();
                var _offset   = 0;
                var _begin    = _move.Body.Instructions[_offset];
                var _resume   = Instruction.Create(OpCodes.Ldarg_0);
                _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldarg_0));
                _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldfld, _state));
                _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldc_I4_0));
                _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Bge, _resume));
                if (_instance != null)
                {
                    _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldarg_0));
                    _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldfld, _boundary.Relative()));
                    _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldarg_0));
                    _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldfld, _instance));
                    _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Callvirt, _move.Module.Import(_move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Instance <object>(System.Reflection.Argument <object> .Value)).GetGenericMethodDefinition()).MakeGenericMethod(method.DeclaringType))));
                }
                foreach (var _parameter in method.Parameters)
                {
                    _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldarg_0));
                    _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldfld, _boundary.Relative()));
                    _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldc_I4, _parameter.Index));
                    _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldarg_0));
                    _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldflda, _type.Fields.First(_Field => _Field.Name == _parameter.Name).Relative()));
                    _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Callvirt, _move.Module.Import(_move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Argument <object>(System.Reflection.Argument <int> .Value, ref System.Reflection.Argument <object> .Value)).GetGenericMethodDefinition()).MakeGenericMethod(_parameter.ParameterType.IsGenericParameter ? _type.GenericParameters.First(_Type => _Type.Name == _parameter.ParameterType.Name) : _parameter.ParameterType))));
                }
                _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldarg_0));
                _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldfld, _boundary.Relative()));
                _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Callvirt, _move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Invoke()))));
                _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Br_S, _begin));
                _move.Body.Instructions.Insert(_offset++, _resume);
                _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldfld, _boundary.Relative()));
                _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Callvirt, _move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Resume()))));
                while (_offset < _move.Body.Instructions.Count)
                {
                    var _instruction = _move.Body.Instructions[_offset];
                    if (_instruction.OpCode == OpCodes.Call)
                    {
                        if (_instruction.Operand is MethodReference)
                        {
                            var _operand = _instruction.Operand as MethodReference;
                            if (_operand.Name == "AwaitUnsafeOnCompleted")
                            {
                                _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldarg_0));
                                _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Ldfld, _boundary.Relative()));
                                _move.Body.Instructions.Insert(_offset++, Instruction.Create(OpCodes.Callvirt, _move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Yield()))));
                            }
                            else if (_operand.Name == "SetResult")
                            {
                                var _return = _type.Method("<Return>", MethodAttributes.Public);
                                if (_operand.HasParameters)
                                {
                                    var _parameter = new ParameterDefinition("<Value>", ParameterAttributes.None, (_builder.FieldType as GenericInstanceType).GenericArguments[0]);
                                    _return.Parameters.Add(_parameter);
                                    var _exception = _return.Body.Variable <Exception>("<Exception>");
                                    var _disposed  = _return.Body.Variable <bool>("<Invoked>");
                                    var _end       = Instruction.Create(OpCodes.Ret);
                                    _return.Body.Emit(OpCodes.Ldarg_0);
                                    _return.Body.Emit(OpCodes.Ldfld, _boundary.Relative());
                                    _return.Body.Emit(OpCodes.Ldarga_S, _parameter);
                                    _return.Body.Emit(OpCodes.Callvirt, _move.Module.Import(_move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Return <object>(ref System.Reflection.Argument <object> .Value)).GetGenericMethodDefinition()).MakeGenericMethod(_parameter.ParameterType)));
                                    _return.Body.Emit(OpCodes.Ldc_I4_1);
                                    _return.Body.Emit(OpCodes.Stloc_1);
                                    _return.Body.Emit(OpCodes.Ldarg_0);
                                    _return.Body.Emit(OpCodes.Ldfld, _boundary.Relative());
                                    _return.Body.Emit(OpCodes.Callvirt, _move.Module.Import(_move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Dispose()))));
                                    _return.Body.Emit(OpCodes.Ldarg_0);
                                    _return.Body.Emit(OpCodes.Ldflda, _builder);
                                    _return.Body.Emit(OpCodes.Ldarg_1);
                                    _return.Body.Emit(OpCodes.Call, _operand);
                                    _return.Body.Emit(OpCodes.Ret);
                                    var _catch = _return.Body.Emit(OpCodes.Stloc_0);
                                    _return.Body.Emit(OpCodes.Ldloc_1);
                                    using (_return.Body.False())
                                    {
                                        _return.Body.Emit(OpCodes.Ldarg_0);
                                        _return.Body.Emit(OpCodes.Ldfld, _boundary.Relative());
                                        _return.Body.Emit(OpCodes.Callvirt, _move.Module.Import(_move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Dispose()))));
                                    }
                                    _return.Body.Emit(OpCodes.Ldarg_0);
                                    _return.Body.Emit(OpCodes.Ldflda, _builder);
                                    _return.Body.Emit(OpCodes.Ldloc_0);
                                    var _method = _move.Module.Import(_builder.FieldType.Resolve().Methods.Single(_Method => _Method.Name == "SetException"));
                                    _method.DeclaringType = _builder.FieldType;
                                    _return.Body.Emit(OpCodes.Call, _method);
                                    _return.Body.Emit(OpCodes.Ret);
                                    _return.Body.ExceptionHandlers.Add(new ExceptionHandler(ExceptionHandlerType.Catch)
                                    {
                                        TryStart     = _return.Body.Instructions[0],
                                        TryEnd       = _return.Body.Instructions[_catch],
                                        HandlerStart = _return.Body.Instructions[_catch],
                                        HandlerEnd   = _return.Body.Instructions[_return.Body.Instructions.Count - 1],
                                        CatchType    = _exception.VariableType
                                    });
                                    _return.Body.OptimizeMacros();
                                    _instruction.Operand = _type.HasGenericParameters ? _return.MakeHostInstanceGeneric(_type.GenericParameters.ToArray()) : _return;
                                    _move.Body.Instructions[_offset - 2].OpCode = OpCodes.Nop;
                                }
                                else
                                {
                                    var _exception = _return.Body.Variable <Exception>("<Exception>");
                                    var _disposed  = _return.Body.Variable <bool>("<Invoked>");
                                    var _end       = Instruction.Create(OpCodes.Ret);
                                    _return.Body.Emit(OpCodes.Ldarg_0);
                                    _return.Body.Emit(OpCodes.Ldfld, _boundary.Relative());
                                    _return.Body.Emit(OpCodes.Callvirt, _move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Return())));
                                    _return.Body.Emit(OpCodes.Ldc_I4_1);
                                    _return.Body.Emit(OpCodes.Stloc_1);
                                    _return.Body.Emit(OpCodes.Ldarg_0);
                                    _return.Body.Emit(OpCodes.Ldfld, _boundary.Relative());
                                    _return.Body.Emit(OpCodes.Callvirt, _move.Module.Import(_move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Dispose()))));
                                    _return.Body.Emit(OpCodes.Ldarg_0);
                                    _return.Body.Emit(OpCodes.Ldflda, _builder);
                                    _return.Body.Emit(OpCodes.Call, _operand);
                                    _return.Body.Emit(OpCodes.Ret);
                                    var _catch = _return.Body.Emit(OpCodes.Stloc_0);
                                    _return.Body.Emit(OpCodes.Ldloc_1);
                                    using (_return.Body.False())
                                    {
                                        _return.Body.Emit(OpCodes.Ldarg_0);
                                        _return.Body.Emit(OpCodes.Ldfld, _boundary.Relative());
                                        _return.Body.Emit(OpCodes.Callvirt, _move.Module.Import(_move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Dispose()))));
                                    }
                                    _return.Body.Emit(OpCodes.Ldarg_0);
                                    _return.Body.Emit(OpCodes.Ldflda, _builder);
                                    _return.Body.Emit(OpCodes.Ldloc_0);
                                    var _method = _move.Module.Import(_builder.FieldType.Resolve().Methods.Single(_Method => _Method.Name == "SetException"));
                                    _method.DeclaringType = _builder.FieldType;
                                    _return.Body.Emit(OpCodes.Call, _method);
                                    _return.Body.Emit(OpCodes.Ret);
                                    _return.Body.ExceptionHandlers.Add(new ExceptionHandler(ExceptionHandlerType.Catch)
                                    {
                                        TryStart     = _return.Body.Instructions[0],
                                        TryEnd       = _return.Body.Instructions[_catch],
                                        HandlerStart = _return.Body.Instructions[_catch],
                                        HandlerEnd   = _return.Body.Instructions[_return.Body.Instructions.Count - 1],
                                        CatchType    = _exception.VariableType,
                                    });
                                    _return.Body.OptimizeMacros();
                                    _instruction.Operand = _type.HasGenericParameters ? _return.MakeHostInstanceGeneric(_type.GenericParameters.ToArray()) : _return;
                                    _move.Body.Instructions[_offset - 1].OpCode = OpCodes.Nop;
                                }
                            }
                            else if (_operand.Name == "SetException")
                            {
                                var _throw     = _type.Method("<Throw>", MethodAttributes.Public);
                                var _parameter = new ParameterDefinition("<Exception>", ParameterAttributes.None, _throw.Module.Import(typeof(Exception)));
                                _throw.Parameters.Add(_parameter);
                                if (_builder.FieldType.IsGenericInstance)
                                {
                                    var _value = new VariableDefinition("<Value>", (_builder.FieldType as GenericInstanceType).GenericArguments[0]);
                                    _throw.Body.Variables.Add(_value);
                                    var _disposed = _throw.Body.Variable <bool>("<Invoked>");
                                    _throw.Body.Emit(OpCodes.Ldarg_0);
                                    _throw.Body.Emit(OpCodes.Ldfld, _boundary.Relative());
                                    _throw.Body.Emit(OpCodes.Ldarg_S, _parameter);
                                    _throw.Body.Emit(OpCodes.Ldloca_S, _value);
                                    _throw.Body.Emit(OpCodes.Callvirt, _move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Throw <object>(ref System.Reflection.Argument <Exception> .Value, ref System.Reflection.Argument <object> .Value)).GetGenericMethodDefinition()).MakeGenericMethod(_value.VariableType));
                                    _throw.Body.Emit(OpCodes.Ldc_I4_1);
                                    _throw.Body.Emit(OpCodes.Stloc_1);
                                    _throw.Body.Emit(OpCodes.Ldarg_0);
                                    _throw.Body.Emit(OpCodes.Ldfld, _boundary.Relative());
                                    _throw.Body.Emit(OpCodes.Callvirt, _move.Module.Import(_move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Dispose()))));
                                    _throw.Body.Emit(OpCodes.Ldarg_1);
                                    using (_throw.Body.True())
                                    {
                                        _throw.Body.Emit(OpCodes.Ldarg_0);
                                        _throw.Body.Emit(OpCodes.Ldflda, _builder);
                                        _throw.Body.Emit(OpCodes.Ldarg_1);
                                        _throw.Body.Emit(OpCodes.Call, _operand);
                                        _throw.Body.Emit(OpCodes.Ret);
                                    }
                                    _throw.Body.Emit(OpCodes.Ldarg_0);
                                    _throw.Body.Emit(OpCodes.Ldflda, _builder);
                                    _throw.Body.Emit(OpCodes.Ldloc_0);
                                    var _method = _move.Module.Import(_move.Module.Import(_builder.FieldType.Resolve().Methods.Single(_Method => _Method.Name == "SetResult" && _Method.Parameters[0].ParameterType.IsGenericParameter)));
                                    _method.DeclaringType = _builder.FieldType;
                                    _throw.Body.Emit(OpCodes.Call, _method);
                                    _throw.Body.Emit(OpCodes.Ret);
                                    var _catch = _throw.Body.Emit(OpCodes.Starg, _parameter);
                                    _throw.Body.Emit(OpCodes.Ldloc_1);
                                    using (_throw.Body.False())
                                    {
                                        _throw.Body.Emit(OpCodes.Ldarg_0);
                                        _throw.Body.Emit(OpCodes.Ldfld, _boundary.Relative());
                                        _throw.Body.Emit(OpCodes.Callvirt, _move.Module.Import(_move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Dispose()))));
                                    }
                                    _throw.Body.Emit(OpCodes.Ldarg_0);
                                    _throw.Body.Emit(OpCodes.Ldflda, _builder);
                                    _throw.Body.Emit(OpCodes.Ldarg_1);
                                    _throw.Body.Emit(OpCodes.Call, _operand);
                                    _throw.Body.Emit(OpCodes.Ret);
                                    _throw.Body.ExceptionHandlers.Add(new ExceptionHandler(ExceptionHandlerType.Catch)
                                    {
                                        TryStart     = _throw.Body.Instructions[0],
                                        TryEnd       = _throw.Body.Instructions[_catch],
                                        HandlerStart = _throw.Body.Instructions[_catch],
                                        HandlerEnd   = _throw.Body.Instructions[_throw.Body.Instructions.Count - 1],
                                        CatchType    = _parameter.ParameterType,
                                    });
                                }
                                else
                                {
                                    var _disposed = _throw.Body.Variable <bool>("<Invoked>");
                                    _throw.Body.Emit(OpCodes.Ldarg_0);
                                    _throw.Body.Emit(OpCodes.Ldfld, _boundary.Relative());
                                    _throw.Body.Emit(OpCodes.Ldarga_S, _parameter);
                                    _throw.Body.Emit(OpCodes.Callvirt, _move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Throw(ref System.Reflection.Argument <Exception> .Value))));
                                    _throw.Body.Emit(OpCodes.Ldc_I4_1);
                                    _throw.Body.Emit(OpCodes.Stloc_0);
                                    _throw.Body.Emit(OpCodes.Ldarg_0);
                                    _throw.Body.Emit(OpCodes.Ldfld, _boundary.Relative());
                                    _throw.Body.Emit(OpCodes.Callvirt, _move.Module.Import(_move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Dispose()))));
                                    _throw.Body.Emit(OpCodes.Ldarg_1);
                                    using (_throw.Body.True())
                                    {
                                        _throw.Body.Emit(OpCodes.Ldarg_0);
                                        _throw.Body.Emit(OpCodes.Ldflda, _builder);
                                        _throw.Body.Emit(OpCodes.Ldarg_1);
                                        _throw.Body.Emit(OpCodes.Call, _operand);
                                        _throw.Body.Emit(OpCodes.Ret);
                                    }
                                    _throw.Body.Emit(OpCodes.Ldarg_0);
                                    _throw.Body.Emit(OpCodes.Ldflda, _builder);
                                    var _method = _move.Module.Import(_builder.FieldType.Resolve().Methods.Single(_Method => _Method.Name == "SetResult" && _Method.Parameters.Count == 0));
                                    _method.DeclaringType = _builder.FieldType;
                                    _throw.Body.Emit(OpCodes.Call, _method);
                                    _throw.Body.Emit(OpCodes.Ret);
                                    var _catch = _throw.Body.Emit(OpCodes.Starg, _parameter);
                                    _throw.Body.Emit(OpCodes.Ldloc_0);
                                    using (_throw.Body.False())
                                    {
                                        _throw.Body.Emit(OpCodes.Ldarg_0);
                                        _throw.Body.Emit(OpCodes.Ldfld, _boundary.Relative());
                                        _throw.Body.Emit(OpCodes.Callvirt, _move.Module.Import(_move.Module.Import(System.Reflection.Metadata <Advice.IBoundary> .Method(_Boundary => _Boundary.Dispose()))));
                                    }
                                    _throw.Body.Emit(OpCodes.Ldarg_0);
                                    _throw.Body.Emit(OpCodes.Ldflda, _builder);
                                    _throw.Body.Emit(OpCodes.Ldarg_1);
                                    _throw.Body.Emit(OpCodes.Call, _operand);
                                    _throw.Body.Emit(OpCodes.Ret);
                                    _throw.Body.ExceptionHandlers.Add(new ExceptionHandler(ExceptionHandlerType.Catch)
                                    {
                                        TryStart     = _throw.Body.Instructions[0],
                                        TryEnd       = _throw.Body.Instructions[_catch],
                                        HandlerStart = _throw.Body.Instructions[_catch],
                                        HandlerEnd   = _throw.Body.Instructions[_throw.Body.Instructions.Count - 1],
                                        CatchType    = _parameter.ParameterType,
                                    });
                                }
                                _throw.Body.OptimizeMacros();
                                _instruction.Operand = _type.HasGenericParameters ? _throw.MakeHostInstanceGeneric(_type.GenericParameters.ToArray()) : _throw;
                                _move.Body.Instructions[_offset - 2].OpCode = OpCodes.Nop;
                            }
                        }
                    }
                    _offset++;
                }
                _move.Body.OptimizeMacros();
            }
        }
コード例 #29
0
        public static MethodDefinition ProcessSyncVarSet(TypeDefinition td, FieldDefinition fd, string originalName, long dirtyBit, FieldDefinition netFieldId)
        {
            //Create the set method
            var set = new MethodDefinition("set_Network" + originalName, MethodAttributes.Public |
                                           MethodAttributes.SpecialName |
                                           MethodAttributes.HideBySig,
                                           Weaver.voidType);

            ILProcessor setWorker = set.Body.GetILProcessor();

            // if (!SyncVarEqual(value, ref playerData))
            Instruction endOfMethod = setWorker.Create(OpCodes.Nop);

            // this
            setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
            // new value to set
            setWorker.Append(setWorker.Create(OpCodes.Ldarg_1));
            // reference to field to set
            // make generic version of SetSyncVar with field type
            if (fd.FieldType.FullName == Weaver.gameObjectType.FullName)
            {
                // reference to netId Field to set
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldfld, netFieldId));

                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.syncVarGameObjectEqualReference));
            }
            else if (fd.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
            {
                // reference to netId Field to set
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldfld, netFieldId));

                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.syncVarNetworkIdentityEqualReference));
            }
            else
            {
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldflda, fd));

                var syncVarEqualGm = new GenericInstanceMethod(Weaver.syncVarEqualReference);
                syncVarEqualGm.GenericArguments.Add(fd.FieldType);
                setWorker.Append(setWorker.Create(OpCodes.Call, syncVarEqualGm));
            }

            setWorker.Append(setWorker.Create(OpCodes.Brtrue, endOfMethod));

            // T oldValue = value;
            // TODO for GO/NI we need to backup the netId don't we?
            var oldValue = new VariableDefinition(fd.FieldType);

            set.Body.Variables.Add(oldValue);
            setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
            setWorker.Append(setWorker.Create(OpCodes.Ldfld, fd));
            setWorker.Append(setWorker.Create(OpCodes.Stloc, oldValue));

            // this
            setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));

            // new value to set
            setWorker.Append(setWorker.Create(OpCodes.Ldarg_1));

            // reference to field to set
            setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
            setWorker.Append(setWorker.Create(OpCodes.Ldflda, fd));

            // dirty bit
            // 8 byte integer aka long
            setWorker.Append(setWorker.Create(OpCodes.Ldc_I8, dirtyBit));

            if (fd.FieldType.FullName == Weaver.gameObjectType.FullName)
            {
                // reference to netId Field to set
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldflda, netFieldId));

                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarGameObjectReference));
            }
            else if (fd.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
            {
                // reference to netId Field to set
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldflda, netFieldId));

                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarNetworkIdentityReference));
            }
            else
            {
                // make generic version of SetSyncVar with field type
                var gm = new GenericInstanceMethod(Weaver.setSyncVarReference);
                gm.GenericArguments.Add(fd.FieldType);

                // invoke SetSyncVar
                setWorker.Append(setWorker.Create(OpCodes.Call, gm));
            }

            MethodDefinition hookFunctionMethod = GetHookMethod(td, fd);

            if (hookFunctionMethod != null)
            {
                //if (base.isLocalClient && !getSyncVarHookGuard(dirtyBit))
                Instruction label = setWorker.Create(OpCodes.Nop);
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.NetworkBehaviourIsLocalClient));
                setWorker.Append(setWorker.Create(OpCodes.Brfalse, label));
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldc_I8, dirtyBit));
                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.getSyncVarHookGuard));
                setWorker.Append(setWorker.Create(OpCodes.Brtrue, label));

                // setSyncVarHookGuard(dirtyBit, true);
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldc_I8, dirtyBit));
                setWorker.Append(setWorker.Create(OpCodes.Ldc_I4_1));
                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarHookGuard));

                // call hook (oldValue, newValue)
                // dont add this (Ldarg_0) if method is static
                if (!hookFunctionMethod.IsStatic)
                {
                    setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                }
                setWorker.Append(setWorker.Create(OpCodes.Ldloc, oldValue));
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_1));
                setWorker.Append(setWorker.Create(OpCodes.Callvirt, hookFunctionMethod));

                // setSyncVarHookGuard(dirtyBit, false);
                setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
                setWorker.Append(setWorker.Create(OpCodes.Ldc_I8, dirtyBit));
                setWorker.Append(setWorker.Create(OpCodes.Ldc_I4_0));
                setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarHookGuard));

                setWorker.Append(label);
            }

            setWorker.Append(endOfMethod);

            setWorker.Append(setWorker.Create(OpCodes.Ret));

            set.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.In, fd.FieldType));
            set.SemanticsAttributes = MethodSemanticsAttributes.Setter;

            return(set);
        }
コード例 #30
0
        /// <summary>
        ///     Inject the call of the injection method into the target.
        /// </summary>
        /// <param name="startCode">The instruction from which to start injecting.</param>
        /// <param name="token">
        ///     If <see cref="InjectFlags.PassTag" /> is specified, the value of this parameter will be passed as a
        ///     parameter to the injection method.
        /// </param>
        /// <param name="direction">The direction in which to insert the call: either above the start code or below it.</param>
        public void Inject(Instruction startCode, int token = 0, InjectDirection direction = InjectDirection.Before)
        {
            InjectValues flags = Flags.ToValues();

#if DEBUG
            Logger.LogLine(LogMask.Inject, "##### INJECTION START #####");
            Logger.LogLine(
            LogMask.Inject,
            $"Injecting a call to {InjectMethod.Module.Name}.{InjectMethod.Name} into {InjectTarget.Module.Name}.{InjectTarget.Name}.");
            Logger.LogLine(LogMask.Inject, "Patch parameters:");
            Logger.LogLine(LogMask.Inject, $"Pass tag: {flags.PassTag}");
            Logger.LogLine(LogMask.Inject, $"Modify return value: {flags.ModifyReturn}");
            Logger.LogLine(LogMask.Inject, $"Pass THIS: {flags.PassInvokingInstance}");
            Logger.LogLine(LogMask.Inject, $"Pass method locals: {flags.PassLocals}");
            Logger.LogLine(LogMask.Inject, $"Pass member fields: {flags.PassFields}");
            Logger.LogLine(LogMask.Inject, $"Pass member parameters: {flags.PassParameters}");
            if (flags.PassParameters)
            {
                Logger.LogLine(
                LogMask.Inject,
                $"Member parameters are passed by {(flags.PassParametersByRef ? "reference" : "value")}");
            }
#endif

            bool isVoid = InjectTarget.ReturnType.FullName == "System.Void";

            MethodReference hookRef = InjectTarget.Module.Import(InjectMethod);

            // If the hook is generic but not instantiated fully, attempt to fill in the generic arguments with the ones specified in the target method/class
            if (hookRef.HasGenericParameters && (!hookRef.IsGenericInstance || hookRef.IsGenericInstance && ((GenericInstanceMethod)hookRef).GenericArguments.Count < hookRef.GenericParameters.Count))
            {
                GenericInstanceMethod genericInjectMethod = new GenericInstanceMethod(hookRef);
                foreach (GenericParameter genericParameter in InjectMethod.GenericParameters)
                {
                    List<GenericParameter> @params = new List<GenericParameter>();
                    @params.AddRange(InjectTarget.GenericParameters);
                    @params.AddRange(InjectTarget.DeclaringType.GenericParameters);
                    GenericParameter param = @params.FirstOrDefault(p => p.Name == genericParameter.Name);
                    if (param == null)
                        throw new Exception("Could not find a suitable type to bind to the generic injection method. Try to manually instantiate the generic injection method before injecting.");
                    genericInjectMethod.GenericArguments.Add(param);
                }
                hookRef = genericInjectMethod;
            }

            MethodBody targetBody = InjectTarget.Body;
            ILProcessor il = targetBody.GetILProcessor();
            int startIndex = targetBody.Instructions.IndexOf(startCode);
            if (startIndex == -1)
                throw new ArgumentOutOfRangeException(nameof(startCode));
            Instruction startInstruction = startCode;

            if (direction == InjectDirection.Before && startIndex != 0)
            {
                Instruction oldIns = ILUtils.CopyInstruction(startCode);
                ILUtils.ReplaceInstruction(startCode, il.Create(OpCodes.Nop));
                Instruction ins = targetBody.Instructions[startIndex];
                il.InsertAfter(ins, oldIns);
                startInstruction = targetBody.Instructions[startIndex + 1];
            }
            else if (direction == InjectDirection.After)
            {
                il.InsertAfter(startCode, il.Create(OpCodes.Nop));
                startInstruction = targetBody.Instructions[startIndex + 1];
            }

            VariableDefinition returnDef = null;
            if (flags.ModifyReturn && !isVoid)
            {
                targetBody.InitLocals = true;
                returnDef = new VariableDefinition(
                InjectMethod.Name + "_return",
                InjectTarget.ReturnType);
                targetBody.Variables.Add(returnDef);
            }


            if (flags.PassTag)
            {
                Logger.LogLine(LogMask.Inject, $"Passing custom token value: {token}");
                il.InsertBefore(startInstruction, il.Create(OpCodes.Ldc_I4, token));
            }
            if (flags.PassInvokingInstance)
            {
                Logger.LogLine(LogMask.Inject, "Passing THIS argument");
                il.InsertBefore(startInstruction, il.Create(OpCodes.Ldarg_0));
            }
            if (flags.ModifyReturn && !isVoid)
            {
                Logger.LogLine(LogMask.Inject, "Passing return reference");
                il.InsertBefore(startInstruction, il.Create(OpCodes.Ldloca_S, returnDef));
            }
            if (flags.PassLocals)
            {
                Logger.LogLine(LogMask.Inject, "Passing local variable references");
                foreach (int i in LocalVarIDs)
                {
                    Logger.LogLine(LogMask.Inject, $"Passing local variable index: {i}");
                    il.InsertBefore(startInstruction, il.Create(OpCodes.Ldloca_S, (byte) i));
                }
            }
            if (flags.PassFields)
            {
                Logger.LogLine(LogMask.Inject, "Passing member field references");
                IEnumerable<FieldReference> memberRefs = MemberReferences.Select(t => t.Module.Import(t));
                foreach (FieldReference t in memberRefs)
                {
                    Logger.LogLine(LogMask.Inject, $"Passing member field {t.FullName}");
                    il.InsertBefore(startInstruction, il.Create(OpCodes.Ldarg_0));
                    il.InsertBefore(startInstruction, il.Create(OpCodes.Ldflda, t));
                }
            }
            if (flags.PassParameters)
            {
                Logger.LogLine(
                LogMask.Inject,
                $"Passing member parameters by {(flags.PassParametersByRef ? "reference" : "value")}");
                int icr = Convert.ToInt32(!InjectTarget.IsStatic);
                for (int i = 0; i < _ParameterCount; i++)
                {
                    Logger.LogLine(LogMask.Inject, $"Passing parameter of index {(i + icr)}");
                    il.InsertBefore(
                    startInstruction,
                    flags.PassParametersByRef
                    ? il.Create(OpCodes.Ldarga_S, (byte) (i + icr)) : il.Create(OpCodes.Ldarg_S, (byte) (i + icr)));
                }
            }
            Logger.LogLine(LogMask.Inject, "Injecting the call to the method");
            il.InsertBefore(startInstruction, il.Create(OpCodes.Call, hookRef));
            if (flags.ModifyReturn)
            {
                Logger.LogLine(LogMask.Inject, "Inserting return check");
                il.InsertBefore(startInstruction, il.Create(OpCodes.Brfalse_S, startInstruction));
                if (!isVoid)
                {
                    Logger.LogLine(LogMask.Inject, "Inserting return value");
                    il.InsertBefore(startInstruction, il.Create(OpCodes.Ldloc_S, returnDef));
                }
                Logger.LogLine(LogMask.Inject, "Inserting return command");
                il.InsertBefore(startInstruction, il.Create(OpCodes.Ret));
            }
            // If we don't use the return value of InjectMethod, pop it from the ES
            else if (InjectMethod.ReturnType.FullName != "System.Void")
                il.InsertBefore(startInstruction, il.Create(OpCodes.Pop));
            if (direction == InjectDirection.After)
                il.Remove(startInstruction);
            Logger.LogLine(LogMask.Inject, "Injection complete");
            Logger.LogLine(LogMask.Inject, "##### INJECTION END #####");
        }
コード例 #31
0
ファイル: AssemblyRewriter.cs プロジェクト: husains/coyote
        /// <summary>
        /// Rewrites the specified <see cref="MethodReference"/>.
        /// </summary>
        /// <param name="method">The method reference to rewrite.</param>
        /// <param name="module">The module definition that is being visited.</param>
        /// <param name="matchName">Optional method name to match.</param>
        /// <returns>The rewritten method, or the original if it was not changed.</returns>
        protected MethodReference RewriteMethodReference(MethodReference method, ModuleDefinition module, string matchName = null)
        {
            MethodReference result = method;

            if (!this.TryResolve(method, out MethodDefinition resolvedMethod))
            {
                // Can't rewrite external method reference since we are not rewriting this external assembly.
                return(method);
            }

            TypeReference declaringType = this.RewriteDeclaringTypeReference(method);
            var           resolvedType  = Resolve(declaringType);

            if (resolvedMethod == null)
            {
                // Check if this method signature has been rewritten, find the method by same name,
                // but with newly rewritten parameter types (note: signature does not include return type
                // according to C# rules, but the return type may have also been rewritten which is why
                // it is imperative here that we find the correct new MethodDefinition.
                List <TypeReference> parameterTypes = new List <TypeReference>();
                for (int i = 0; i < method.Parameters.Count; i++)
                {
                    var p = method.Parameters[i];
                    parameterTypes.Add(this.RewriteTypeReference(p.ParameterType));
                }

                var newMethod = FindMatchingMethodInDeclaringType(resolvedType, method.Name, parameterTypes.ToArray());
                if (newMethod != null)
                {
                    if (!this.TryResolve(newMethod, out resolvedMethod))
                    {
                        return(newMethod);
                    }
                }
            }

            if (method.DeclaringType == declaringType && result.Resolve() == resolvedMethod)
            {
                // We are not rewriting this method.
                return(result);
            }

            if (resolvedMethod == null)
            {
                // print warning
                this.TryResolve(method, out resolvedMethod);
                // try and continue...
                return(method);
            }

            MethodDefinition match = FindMatchingMethodInDeclaringType(resolvedType, resolvedMethod, matchName);

            if (match != null)
            {
                result = module.ImportReference(match);
            }

            if (match != null && !result.HasThis && !declaringType.IsGenericInstance &&
                method.HasThis && method.DeclaringType.IsGenericInstance)
            {
                // We are converting from a generic type to a non generic static type, and from a non-generic
                // method to a generic method, so we need to instantiate the generic method.
                GenericInstanceMethod genericMethodInstance = new GenericInstanceMethod(result);

                var genericArgs = new List <TypeReference>();
                if (method.DeclaringType is GenericInstanceType genericDeclaringType)
                {
                    // Populate the generic arguments with the generic declaring type arguments.
                    genericArgs.AddRange(genericDeclaringType.GenericArguments);
                    foreach (var genericArg in genericArgs)
                    {
                        genericMethodInstance.GenericArguments.Add(genericArg);
                    }
                }

                result = genericMethodInstance;
            }
            else
            {
                // This is an extra initial parameter that we have when converting an instance to a static method.
                // For example, `task.GetAwaiter()` is converted to `ControlledTask.GetAwaiter(task)`.
                ParameterDefinition instanceParameter = null;
                if (match != null && resolvedMethod.Parameters.Count != match.Parameters.Count)
                {
                    // We are converting from an instance method to a static method, so store the instance parameter.
                    instanceParameter = result.Parameters[0];
                }

                TypeReference returnType = this.RewriteTypeReference(method.ReturnType);

                // Instantiate the method reference to set its generic arguments and parameters, if any.
                result = new MethodReference(result.Name, returnType, declaringType)
                {
                    HasThis           = result.HasThis,
                    ExplicitThis      = result.ExplicitThis,
                    CallingConvention = result.CallingConvention
                };

                if (resolvedMethod.HasGenericParameters)
                {
                    // We need to instantiate the generic method.
                    GenericInstanceMethod genericMethodInstance = new GenericInstanceMethod(result);

                    var genericArgs      = new List <TypeReference>();
                    int genericArgOffset = 0;

                    if (declaringType is GenericInstanceType genericDeclaringType)
                    {
                        // Populate the generic arguments with the generic declaring type arguments.
                        genericArgs.AddRange(genericDeclaringType.GenericArguments);
                        genericArgOffset = genericDeclaringType.GenericArguments.Count;
                    }

                    if (method is GenericInstanceMethod genericInstanceMethod)
                    {
                        // Populate the generic arguments with the generic instance method arguments.
                        genericArgs.AddRange(genericInstanceMethod.GenericArguments);
                    }

                    for (int i = 0; i < resolvedMethod.GenericParameters.Count; i++)
                    {
                        var p = resolvedMethod.GenericParameters[i];
                        var j = p.Position + genericArgOffset;
                        if (j > genericArgs.Count)
                        {
                            throw new InvalidOperationException($"Not enough generic arguments to instantiate method {method}");
                        }

                        GenericParameter parameter = new GenericParameter(p.Name, genericMethodInstance);
                        result.GenericParameters.Add(parameter);
                        genericMethodInstance.GenericParameters.Add(parameter);
                        genericMethodInstance.GenericArguments.Add(this.RewriteTypeReference(genericArgs[j]));
                    }

                    result = genericMethodInstance;
                }

                // Set the instance parameter of the method, if any.
                if (instanceParameter != null)
                {
                    result.Parameters.Add(instanceParameter);
                }

                // Set the remaining parameters of the method, if any.
                foreach (var parameter in method.Parameters)
                {
                    result.Parameters.Add(this.RewriteParameterDefinition(parameter));
                }
            }

            return(module.ImportReference(result));
        }