void Replace(MethodDefinition?methodDefinition)
    {
        if (methodDefinition == null)
        {
            return;
        }
        if (methodDefinition.IsAbstract)
        {
            return;
        }
        //for delegates
        if (methodDefinition.Body == null)
        {
            return;
        }
        foreach (var instruction in methodDefinition.Body.Instructions)
        {
            if (instruction.OpCode != OpCodes.Call)
            {
                continue;
            }

            foreach (var method in MethodCache)
            {
                if (instruction.Operand == method)
                {
                    instruction.OpCode = OpCodes.Callvirt;
                }
            }
        }
    }
Beispiel #2
0
        public static bool GetEqualityOperator(this TypeDefinition type, out MethodDefinition?method)
        {
            method = type.TryFindMethod("op_Equality", type, type);

            return(method?.IsStatic == true &&
                   method.ReturnType?.FullName == typeof(bool).FullName && method.IsStatic);
        }
        public GlobalMethodRefToConstantAction(MethodAnalysis context, Instruction instruction) : base(context, instruction)
        {
            var globalAddress = instruction.GetRipBasedInstructionMemoryAddress();

            MethodData = LibCpp2IlMain.GetMethodDefinitionByGlobalAddress(globalAddress);
            var(type, genericParams) = Utils.TryLookupTypeDefByName(MethodData !.DeclaringType.FullName);

            if (type == null)
            {
                Console.WriteLine("Failed to lookup managed type for declaring type of " + MethodData.GlobalKey + ", which is " + MethodData.DeclaringType.FullName);
                return;
            }

            ResolvedMethod = type.Methods.FirstOrDefault(m => m.Name == MethodData.Name);

            if (ResolvedMethod == null)
            {
                return;
            }

            var destReg = instruction.Op0Kind == OpKind.Register ? Utils.GetRegisterNameNew(instruction.Op0Register) : null;
            var name    = ResolvedMethod.Name;

            ConstantWritten = context.MakeConstant(typeof(MethodDefinition), ResolvedMethod, name, destReg);
        }
Beispiel #4
0
            public Interceptors(PropertyAccessorWeaver weaver, TypeReference classDefinition, Interceptors?baseTypeInterceptors)
            {
                _weaver               = weaver;
                ClassDefinition       = classDefinition.Resolve();
                _baseTypeInterceptors = baseTypeInterceptors;

                var allMethods = ClassDefinition.Methods;

                if (allMethods == null)
                {
                    return;
                }

                var getInterceptors = allMethods.Where(m => m?.CustomAttributes?.GetAttribute(AttributeNames.GetInterceptor) != null).ToArray();

                if (getInterceptors.Length > 1)
                {
                    throw new WeavingException($"Multiple [GetInterceptor] attributed methods found in class {classDefinition}.", getInterceptors[1]);
                }

                _getInterceptor = getInterceptors.FirstOrDefault();

                var setInterceptors = allMethods.Where(m => m?.CustomAttributes?.GetAttribute(AttributeNames.SetInterceptor) != null).ToArray();

                if (setInterceptors.Length > 1)
                {
                    throw new WeavingException($"Multiple [SetInterceptor] attributed methods found in class {classDefinition}.", setInterceptors[1]);
                }

                _setInterceptor = setInterceptors.FirstOrDefault();

                VerifyInterceptors();
            }
Beispiel #5
0
        public LoadVirtualFunctionPointerAction(MethodAnalysis context, Instruction instruction) : base(context, instruction)
        {
            regReadFrom = Utils.GetRegisterNameNew(instruction.MemoryBase);
            var inReg = context.GetOperandInRegister(regReadFrom);

            if (!(inReg is ConstantDefinition cons) || !(cons.Value is Il2CppClassIdentifier klass))
            {
                return;
            }

            classReadFrom = klass.backingType;

            var readOffset = instruction.MemoryDisplacement;

            methodPointerRead = Utils.GetMethodFromReadKlassOffset((int)readOffset);

            if (methodPointerRead == null)
            {
                return;
            }

            var regPutInto = Utils.GetRegisterNameNew(instruction.Op0Register);

            if (regPutInto == "rsp")
            {
                //todo how do we handle this kind of instruction - does it even exist?
                // var stackOffset = Utils.GetOperandMemoryOffset(instruction.Operands[0]);
                // context.PushToStack(context.MakeConstant(typeof(MethodDefinition), methodPointerRead), stackOffset);
            }
            else
            {
                destinationConstant = context.MakeConstant(typeof(MethodDefinition), methodPointerRead, reg: regPutInto);
            }
        }
Beispiel #6
0
 internal MetadataMethodInfo(
     MetadataType type,
     MethodDefinitionHandle handle,
     MethodDefinition definition,
     string name)
 {
     _type       = type;
     Handle      = handle;
     _metadata   = ((MetadataAssembly)type.Assembly).Metadata;
     _definition = definition;
     _name       = name;
 }
Beispiel #7
0
    void ReplaceUnmanaged(MethodDefinition?method)
    {
        if (method == null)
        {
            return;
        }
        if (method.IsAbstract)
        {
            return;
        }
        //for delegates
        if (method.Body == null)
        {
            return;
        }
        method.Body.SimplifyMacros();
        var instructions       = method.Body.Instructions;
        var foundUsageInMethod = false;

        for (var index = 0; index < instructions.Count; index++)
        {
            var instruction = instructions[index];
            if (instruction.OpCode != OpCodes.Ldftn)
            {
                continue;
            }

            var methodToLdvirtfn = DetermineMethodTo_Ldvirtftn(instruction.Operand);
            if (methodToLdvirtfn == null)
            {
                continue;
            }

            if (!foundUsageInMethod)
            {
                method.Body.SimplifyMacros();
                foundUsageInMethod = true;
            }

            index++;
            instructions.Insert(index, Instruction.Create(OpCodes.Ldvirtftn, methodToLdvirtfn));
            instruction.OpCode  = OpCodes.Dup;
            instruction.Operand = null;
        }

        if (foundUsageInMethod)
        {
            method.Body.OptimizeMacros();
        }
    }
        public static bool RequiresReflectionMethodBodyScannerForCallSite(LinkContext context, MethodReference calledMethod)
        {
            MethodDefinition?methodDefinition = context.TryResolve(calledMethod);

            if (methodDefinition == null)
            {
                return(false);
            }

            return(Intrinsics.GetIntrinsicIdForMethod(methodDefinition) > IntrinsicId.RequiresReflectionBodyScanner_Sentinel ||
                   context.Annotations.FlowAnnotations.RequiresDataFlowAnalysis(methodDefinition) ||
                   context.Annotations.DoesMethodRequireUnreferencedCode(methodDefinition, out _) ||
                   methodDefinition.IsPInvokeImpl);
        }
        public MethodDefinition GetEnsureNotEmptyMethod()
        {
            if (this.ensureNotEmptyMethod == null)
            {
                MethodDefinition method = new MethodDefinition(
                    name: "EnsureNotEmpty",
                    attributes: MethodAttributes.Public | MethodAttributes.Static,
                    returnType: this.moduleDefinition.TypeSystem.Void);

                ParameterDefinition valueParameter = new ParameterDefinition(
                    name: "value",
                    attributes: ParameterAttributes.None,
                    parameterType: this.moduleDefinition.TypeSystem.String);

                ParameterDefinition parameterNameParameter = new ParameterDefinition(
                    name: "parameterName",
                    attributes: ParameterAttributes.None,
                    parameterType: this.moduleDefinition.TypeSystem.String);

                method.Parameters.Add(valueParameter);
                method.Parameters.Add(parameterNameParameter);

                Instruction returnInstruction = Instruction.Create(OpCodes.Ret);

                method.Body.Instructions.AddRange(new[]
                {
                    Instruction.Create(OpCodes.Ldarg, valueParameter),
                    Instruction.Create(OpCodes.Ldstr, string.Empty),
                    Instruction.Create(OpCodes.Ceq),
                    Instruction.Create(OpCodes.Brfalse, returnInstruction),

                    Instruction.Create(OpCodes.Ldstr, "Parameter '"),
                    Instruction.Create(OpCodes.Ldarg, parameterNameParameter),
                    Instruction.Create(OpCodes.Ldstr, "' is empty."),
                    Instruction.Create(OpCodes.Call, this.stringReferences.ConcatThreeStringsMethod.Value),
                    Instruction.Create(OpCodes.Ldarg, parameterNameParameter),
                    Instruction.Create(OpCodes.Newobj, this.exceptionReferences.ArgumentExceptionWithMessageConstructor.Value),
                    Instruction.Create(OpCodes.Throw),

                    returnInstruction,
                });

                method.Body.OptimizeMacros();

                this.GetArgumentGuardHelpersType().Methods.Add(method);
                this.ensureNotEmptyMethod = method;
            }

            return(this.ensureNotEmptyMethod);
        }
Beispiel #10
0
        void VerifyMethodInternal(MethodDefinition src, MethodDefinition?linked, bool expectedKept)
        {
            if (!expectedKept)
            {
                if (linked != null)
                {
                    Assert.True(false, $"Method `{src.FullName}' should have been removed");
                }

                return;
            }

            VerifyMethodKept(src, linked);
        }
Beispiel #11
0
            private MethodDefinition?WhenAccessibleInDerivedClass(MethodDefinition?baseMethodDefinition)
            {
                if (baseMethodDefinition == null)
                {
                    return(null);
                }

                if (baseMethodDefinition.IsPrivate)
                {
                    _weaver._logger.LogWarning($"{baseMethodDefinition} is not accessible from {ClassDefinition}, no properties will be intercepted.");
                    return(null);
                }

                return(baseMethodDefinition);
            }
        public static IEnumerable <MethodReference> EnumerateOverrides(this MethodDefinition?method)
        {
            if (method == null)
            {
                yield break;
            }

            if (method.HasOverrides)
            {
                // Explicit interface implementations...
                foreach (var reference in method.Overrides)
                {
                    yield return(reference);
                }
            }
        }
Beispiel #13
0
        protected override void ProcessMethod(TypeDefinition type, XPathNavigator methodNav, object?_customData)
        {
            Debug.Assert(_substitutionInfo != null);
            string signature = GetSignature(methodNav);

            if (string.IsNullOrEmpty(signature))
            {
                return;
            }

            MethodDefinition?method = FindMethod(type, signature);

            if (method == null)
            {
                LogWarning($"Could not find method '{signature}' on type '{type.GetDisplayName ()}'.", 2009, methodNav);
                return;
            }

            string action = GetAttribute(methodNav, "body");

            switch (action)
            {
            case "remove":
                _substitutionInfo.SetMethodAction(method, MethodAction.ConvertToThrow);
                return;

            case "stub":
                string value = GetAttribute(methodNav, "value");
                if (!string.IsNullOrEmpty(value))
                {
                    if (!TryConvertValue(value, method.ReturnType, out object?res))
                    {
                        LogWarning($"Invalid value for '{method.GetDisplayName ()}' stub.", 2010, methodNav);
                        return;
                    }

                    _substitutionInfo.SetMethodStubValue(method, res);
                }

                _substitutionInfo.SetMethodAction(method, MethodAction.ConvertToStub);
                return;

            default:
                LogWarning($"Unknown body modification '{action}' for '{method.GetDisplayName ()}'.", 2011, methodNav);
                return;
            }
        }
Beispiel #14
0
        protected override void ProcessMethod(TypeDefinition type, XPathNavigator methodNav, object?_customData)
        {
            Debug.Assert(_substitutionInfo != null);
            string signature = GetSignature(methodNav);

            if (string.IsNullOrEmpty(signature))
            {
                return;
            }

            MethodDefinition?method = FindMethod(type, signature);

            if (method == null)
            {
                LogWarning(methodNav, DiagnosticId.XmlCouldNotFindMethodOnType, signature, type.GetDisplayName());
                return;
            }

            string action = GetAttribute(methodNav, "body");

            switch (action)
            {
            case "remove":
                _substitutionInfo.SetMethodAction(method, MethodAction.ConvertToThrow);
                return;

            case "stub":
                string value = GetAttribute(methodNav, "value");
                if (!string.IsNullOrEmpty(value))
                {
                    if (!TryConvertValue(value, method.ReturnType, out object?res))
                    {
                        LogWarning(methodNav, DiagnosticId.XmlInvalidValueForStub, method.GetDisplayName());
                        return;
                    }

                    _substitutionInfo.SetMethodStubValue(method, res);
                }

                _substitutionInfo.SetMethodAction(method, MethodAction.ConvertToStub);
                return;

            default:
                LogWarning(methodNav, DiagnosticId.XmlUnkownBodyModification, action, method.GetDisplayName());
                return;
            }
        }
Beispiel #15
0
        protected virtual void VerifyMethodKept(MethodDefinition src, MethodDefinition?linked)
        {
            if (linked == null)
            {
                Assert.True(false, $"Method `{src.FullName}' should have been kept");
                return;
            }

            VerifyPseudoAttributes(src, linked);
            VerifyGenericParameters(src, linked);
            VerifyCustomAttributes(src, linked);
            VerifyCustomAttributes(src.MethodReturnType, linked.MethodReturnType);
            VerifyParameters(src, linked);
            VerifySecurityAttributes(src, linked);
            VerifyArrayInitializers(src, linked);
            VerifyMethodBody(src, linked);
        }
Beispiel #16
0
    public MethodEditContext(MethodDefinition method)
    {
        if (method.HasBody)
        {
            _method = method;

            var methodBody = method.Body;

            var debugInformation = method.DebugInformation;
            if (debugInformation.HasSequencePoints)
            {
                _debugInformationContext = new DebugInformationContext(methodBody, debugInformation);
            }

            methodBody.SimplifyMacros();
        }
    }
        public CallManagedFunctionAction(MethodAnalysis context, Instruction instruction) : base(context, instruction)
        {
            var jumpTarget = instruction.NearBranchTarget;
            var objectMethodBeingCalledOn = context.GetLocalInReg("rcx");
            var listOfCallableMethods     = LibCpp2IlMain.GetManagedMethodImplementationsAtAddress(jumpTarget);

            if (listOfCallableMethods == null)
            {
                return;
            }

            Il2CppMethodDefinition possibleTarget = null;

            if (objectMethodBeingCalledOn?.Type != null)
            {
                //Direct instance methods take priority
                possibleTarget = listOfCallableMethods.FirstOrDefault(m => !m.IsStatic && Utils.AreManagedAndCppTypesEqual(LibCpp2ILUtils.WrapType(m.DeclaringType !), objectMethodBeingCalledOn.Type) && CheckParameters(m, context, true));

                //todo check args and null out

                if (possibleTarget == null)
                {
                    //Base class instance methods
                    possibleTarget = listOfCallableMethods.FirstOrDefault(m => !m.IsStatic && Utils.IsManagedTypeAnInstanceOfCppOne(LibCpp2ILUtils.WrapType(m.DeclaringType !), objectMethodBeingCalledOn.Type) && CheckParameters(m, context, true));
                }

                //check args again.
            }

            //Check static methods
            if (possibleTarget == null)
            {
                possibleTarget = listOfCallableMethods.FirstOrDefault(m => m.IsStatic && CheckParameters(m, context, false));
            }


            if (possibleTarget != null)
            {
                target = SharedState.UnmanagedToManagedMethods[possibleTarget];
                return;
            }

            // SharedState.MethodsByAddress.TryGetValue(jumpTarget, out target);
        }
        private void VerifyCustomEqualsSignature(TypeDefinition classDefinition, MethodDefinition?customEquals)
        {
            if (customEquals != null)
            {
                if (customEquals.ReturnType.FullName != typeof(bool).FullName)
                {
                    throw new WeavingException($"Custom equals method in class {classDefinition} must have a return type of {typeof(bool)}!", customEquals.GetEntryPoint());
                }

                if ((customEquals.Parameters.Count != 1) || (customEquals.Parameters[0].ParameterType.Resolve() != classDefinition))
                {
                    throw new WeavingException($"Custom equals method in class {classDefinition} must have one parameter of type {classDefinition}!", customEquals.GetEntryPoint());
                }

                if (customEquals.IsAbstract || customEquals.IsStatic)
                {
                    throw new WeavingException($"Custom equals method in class {classDefinition} must not be a non-abstract member method!", customEquals.GetEntryPoint());
                }
            }
        }
Beispiel #19
0
        public CallVirtualMethodAction(MethodAnalysis context, Instruction instruction) : base(context, instruction)
        {
            var inReg = context.GetOperandInRegister(Utils.GetRegisterNameNew(instruction.MemoryBase));

            if (!(inReg is ConstantDefinition cons) || !(cons.Value is Il2CppClassIdentifier klass))
            {
                return;
            }

            var classReadFrom = klass.backingType;

            var readOffset = instruction.MemoryDisplacement;

            Called = Utils.GetMethodFromReadKlassOffset((int)readOffset);

            if (Called == null)
            {
                return;
            }

            CalledOn = context.GetLocalInReg("rcx");
        }
    void ProcessMethod(MethodDefinition?method)
    {
        if (method == null)
        {
            return;
        }

        if (method.IsFinal && method.IsVirtual)
        {
            method.IsFinal = false;
            AddMethodToCache(method);
            return;
        }
        if (method.IsFinal)
        {
            return;
        }
        if (method.IsVirtual)
        {
            return;
        }
        if (method.IsStatic)
        {
            return;
        }
        if (method.IsPrivate)
        {
            return;
        }

        if (MethodIsSerializationCallback(method))
        {
            return;
        }

        AddMethodToCache(method);
        method.IsVirtual = true;
        method.IsNewSlot = true;
    }
        public DocMatch(string cref, MethodDefinition m, MethodDefinition?bm = null) : this(cref)
        {
            if (m.HasParameters)
            {
                var pm = new Dictionary <string, string>();
                foreach (var pp in m.Parameters)
                {
                    pm.Add(bm?.Parameters[pp.Index].Name ?? pp.Name, pp.Name);
                }

                ParamMap = pm;
            }

            if (m.HasGenericParameters)
            {
                var tpm = new Dictionary <string, string>();
                foreach (var tp in m.GenericParameters)
                {
                    tpm.Add(bm?.GenericParameters[tp.Position].Name ?? tp.Name, tp.Name);
                }

                TypeParamMap = tpm;
            }
        }
Beispiel #22
0
    void Replace(MethodDefinition?methodDefinition, List <MethodDefinition> baseMethods)
    {
        if (methodDefinition == null)
        {
            return;
        }
        if (methodDefinition.IsAbstract)
        {
            return;
        }
        //for delegates
        if (methodDefinition.Body == null)
        {
            return;
        }
        var definition = baseMethods.FirstOrDefault(baseMethod =>
                                                    HaveSameMethodSignature(methodDefinition, baseMethod));

        if (definition == null)
        {
            return;
        }
        methodDefinition.IsNewSlot = false;
    }
        private (MethodDefinition?method, bool isStaticConstructor) FindBestEntryPointCandidate(AssemblyDefinition assembly)
        {
            // First priority -- explicit [<EntryPoint>]
            // Second priority -- top level code (gets compiled into a static ctor)

            MethodDefinition?startup = null;

            foreach (var type in assembly.MainModule.Types)
            {
                if (type.Namespace == "<StartupCode$_>" && type.Name == "$_" && type.HasMethods)
                {
                    foreach (var method in type.Methods)
                    {
                        if (method.IsConstructor && method.IsStatic)
                        {
                            startup = method;
                            break;
                        }
                    }
                    continue;
                }

                if (type.Namespace == "" && type.Name == "_" && type.HasMethods)
                {
                    foreach (var method in type.Methods)
                    {
                        if (HasEntryPointAttribute(method))
                        {
                            return(method, false);
                        }
                    }
                }
            }

            return(startup, startup != null);
        }
        public bool IsSuppressed(int id, MessageOrigin warningOrigin, out SuppressMessageInfo info)
        {
            // Check for suppressions on both the suppression context as well as the original member
            // (if they're different). This is to correctly handle compiler generated code
            // which needs to use suppressions from both the compiler generated scope
            // as well as the original user defined method.
            info = default;

            ICustomAttributeProvider?provider = warningOrigin.Provider;

            if (provider == null)
            {
                return(false);
            }

            if (IsSuppressed(id, provider, out info))
            {
                return(true);
            }

            if (provider is not IMemberDefinition member)
            {
                return(false);
            }

            MethodDefinition?userDefinedMethod = _context.CompilerGeneratedState.GetUserDefinedMethodForCompilerGeneratedMember(member);

            if (userDefinedMethod == null)
            {
                return(false);
            }

            Debug.Assert(userDefinedMethod != provider);

            return(IsSuppressed(id, userDefinedMethod, out info));
        }
Beispiel #25
0
 public GenericStructSerializationInfo(TypeDefinition definition, CustomFormatterTypeInfo customFormatter, MethodDefinition?serializationConstructorDefinition, GenericInstanceType[] definitionVariations)
Beispiel #26
0
 public GenericStructSerializationInfo(TypeDefinition definition, FieldSerializationInfo[] fieldInfos, PropertySerializationInfo[] propertyInfos, int minIntKey, int maxIntKey, MethodDefinition?serializationConstructorDefinition, GenericInstanceType[] definitionVariations)
Beispiel #27
0
        // For state machine types/members, maps back to the state machine method.
        // For local functions and lambdas, maps back to the owning method in user code (not the declaring
        // lambda or local function, because the IL doesn't contain enough information to figure this out).
        public bool TryGetOwningMethodForCompilerGeneratedMember(IMemberDefinition sourceMember, [NotNullWhen(true)] out MethodDefinition?owningMethod)
        {
            owningMethod = null;
            if (sourceMember == null)
            {
                return(false);
            }

            MethodDefinition?compilerGeneratedMethod = sourceMember as MethodDefinition;

            if (compilerGeneratedMethod != null)
            {
                if (_compilerGeneratedMethodToUserCodeMethod.TryGetValue(compilerGeneratedMethod, out owningMethod))
                {
                    return(true);
                }
            }

            TypeDefinition sourceType = (sourceMember as TypeDefinition) ?? sourceMember.DeclaringType;

            if (_compilerGeneratedTypeToUserCodeMethod.TryGetValue(sourceType, out owningMethod))
            {
                return(true);
            }

            if (!CompilerGeneratedNames.IsGeneratedMemberName(sourceMember.Name) && !CompilerGeneratedNames.IsGeneratedMemberName(sourceType.Name))
            {
                return(false);
            }

            // sourceType is a state machine type, or the type containing a lambda or local function.
            var typeToCache = sourceType;

            // Look in the declaring type if this is a compiler-generated type (state machine or display class).
            // State machines can be emitted into display classes, so we may also need to go one more level up.
            // To avoid depending on implementation details, we go up until we see a non-compiler-generated type.
            // This is the counterpart to GetCompilerGeneratedNestedTypes.
            while (typeToCache != null && CompilerGeneratedNames.IsGeneratedMemberName(typeToCache.Name))
            {
                typeToCache = typeToCache.DeclaringType;
            }

            if (typeToCache == null)
            {
                return(false);
            }

            // Search all methods to find the one which points to the type as its
            // state machine implementation.
            PopulateCacheForType(typeToCache);
            if (compilerGeneratedMethod != null)
            {
                if (_compilerGeneratedMethodToUserCodeMethod.TryGetValue(compilerGeneratedMethod, out owningMethod))
                {
                    return(true);
                }
            }

            if (_compilerGeneratedTypeToUserCodeMethod.TryGetValue(sourceType, out owningMethod))
            {
                return(true);
            }

            return(false);
        }
Beispiel #28
0
        private void EnsureBypassNGenAttribute(ModuleDefinition targetModule)
        {
            Debug.Assert(coreLibAssembly != null);
            if (bypassNGenAttribute != null)
            {
                return;
            }
            ModuleDefinition corelibMainModule      = coreLibAssembly.MainModule;
            TypeReference    bypassNGenAttributeRef = new TypeReference("System.Runtime", "BypassNGenAttribute", corelibMainModule, targetModule.TypeSystem.CoreLibrary);
            TypeDefinition   bypassNGenAttributeDef = corelibMainModule.MetadataResolver.Resolve(bypassNGenAttributeRef);
            MethodDefinition?bypassNGenAttributeDefaultConstructor = null;

            if (bypassNGenAttributeDef == null)
            {
                // System.Runtime.BypassNGenAttribute is not found in corelib. Add it.
                TypeReference systemAttributeRef = new TypeReference("System", "Attribute", corelibMainModule, targetModule.TypeSystem.CoreLibrary);
                TypeReference systemAttribute    = corelibMainModule.MetadataResolver.Resolve(systemAttributeRef);
                systemAttribute = corelibMainModule.ImportReference(systemAttribute);

                if (systemAttribute == null)
                {
                    throw new System.ApplicationException("System.Attribute is not found in " + targetModule.TypeSystem.CoreLibrary.Name);
                }

                MethodReference systemAttributeDefaultConstructorRef = new MethodReference(".ctor", corelibMainModule.TypeSystem.Void, systemAttributeRef);
                MethodReference systemAttributeDefaultConstructor    = corelibMainModule.MetadataResolver.Resolve(systemAttributeDefaultConstructorRef);
                systemAttributeDefaultConstructor = corelibMainModule.ImportReference(systemAttributeDefaultConstructor);

                if (systemAttributeDefaultConstructor == null)
                {
                    throw new System.ApplicationException("System.Attribute has no default constructor");
                }

                bypassNGenAttributeDef = new TypeDefinition("System.Runtime", "BypassNGenAttribute", TypeAttributes.NotPublic | TypeAttributes.Sealed, systemAttribute);

                coreLibAssembly.MainModule.Types.Add(bypassNGenAttributeDef);

                if (Annotations.GetAction(coreLibAssembly) == AssemblyAction.Copy)
                {
                    Annotations.SetAction(coreLibAssembly, AssemblyAction.Save);
                }

                const MethodAttributes ctorAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName;
                bypassNGenAttributeDefaultConstructor = new MethodDefinition(".ctor", ctorAttributes, coreLibAssembly.MainModule.TypeSystem.Void);
                var instructions = bypassNGenAttributeDefaultConstructor.Body.Instructions;
                instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
                instructions.Add(Instruction.Create(OpCodes.Call, systemAttributeDefaultConstructor));
                instructions.Add(Instruction.Create(OpCodes.Ret));

                bypassNGenAttributeDef.Methods.Add(bypassNGenAttributeDefaultConstructor);
            }
            else
            {
                foreach (MethodDefinition method in bypassNGenAttributeDef.Methods)
                {
                    if (method.IsConstructor && !method.IsStatic && !method.HasParameters)
                    {
                        bypassNGenAttributeDefaultConstructor = method;
                        break;
                    }
                }

                if (bypassNGenAttributeDefaultConstructor == null)
                {
                    throw new System.ApplicationException("System.Runtime.BypassNGenAttribute has no default constructor");
                }
            }

            MethodReference defaultConstructorReference = targetModule.ImportReference(bypassNGenAttributeDefaultConstructor);

            bypassNGenAttribute = new CustomAttribute(defaultConstructorReference);
        }
Beispiel #29
0
        void PopulateCacheForType(TypeDefinition type)
        {
            // Avoid repeat scans of the same type
            if (!_typesWithPopulatedCache.Add(type))
            {
                return;
            }

            var callGraph      = new CompilerGeneratedCallGraph();
            var callingMethods = new HashSet <MethodDefinition> ();

            void ProcessMethod(MethodDefinition method)
            {
                bool isStateMachineMember = CompilerGeneratedNames.IsStateMachineType(method.DeclaringType.Name);

                if (!CompilerGeneratedNames.IsLambdaOrLocalFunction(method.Name))
                {
                    if (!isStateMachineMember)
                    {
                        // If it's not a nested function, track as an entry point to the call graph.
                        var added = callingMethods.Add(method);
                        Debug.Assert(added);
                    }
                }
                else
                {
                    // We don't expect lambdas or local functions to be emitted directly into
                    // state machine types.
                    Debug.Assert(!isStateMachineMember);
                }

                // Discover calls or references to lambdas or local functions. This includes
                // calls to local functions, and lambda assignments (which use ldftn).
                if (method.Body != null)
                {
                    foreach (var instruction in method.Body.Instructions)
                    {
                        if (instruction.OpCode.OperandType != OperandType.InlineMethod)
                        {
                            continue;
                        }

                        MethodDefinition?lambdaOrLocalFunction = _context.TryResolve((MethodReference)instruction.Operand);
                        if (lambdaOrLocalFunction == null)
                        {
                            continue;
                        }

                        if (!CompilerGeneratedNames.IsLambdaOrLocalFunction(lambdaOrLocalFunction.Name))
                        {
                            continue;
                        }

                        if (isStateMachineMember)
                        {
                            callGraph.TrackCall(method.DeclaringType, lambdaOrLocalFunction);
                        }
                        else
                        {
                            callGraph.TrackCall(method, lambdaOrLocalFunction);
                        }
                    }
                }

                // Discover state machine methods.
                if (!method.HasCustomAttributes)
                {
                    return;
                }

                foreach (var attribute in method.CustomAttributes)
                {
                    if (attribute.AttributeType.Namespace != "System.Runtime.CompilerServices")
                    {
                        continue;
                    }

                    switch (attribute.AttributeType.Name)
                    {
                    case "AsyncIteratorStateMachineAttribute":
                    case "AsyncStateMachineAttribute":
                    case "IteratorStateMachineAttribute":
                        TypeDefinition?stateMachineType = GetFirstConstructorArgumentAsType(attribute);
                        if (stateMachineType == null)
                        {
                            break;
                        }
                        Debug.Assert(stateMachineType.DeclaringType == type ||
                                     (CompilerGeneratedNames.IsGeneratedMemberName(stateMachineType.DeclaringType.Name) &&
                                      stateMachineType.DeclaringType.DeclaringType == type));
                        callGraph.TrackCall(method, stateMachineType);
                        if (!_compilerGeneratedTypeToUserCodeMethod.TryAdd(stateMachineType, method))
                        {
                            var alreadyAssociatedMethod = _compilerGeneratedTypeToUserCodeMethod[stateMachineType];
                            _context.LogWarning(new MessageOrigin(method), DiagnosticId.MethodsAreAssociatedWithStateMachine, method.GetDisplayName(), alreadyAssociatedMethod.GetDisplayName(), stateMachineType.GetDisplayName());
                        }

                        break;
                    }
                }
            }

            // Look for state machine methods, and methods which call local functions.
            foreach (MethodDefinition method in type.Methods)
            {
                ProcessMethod(method);
            }

            // Also scan compiler-generated state machine methods (in case they have calls to nested functions),
            // and nested functions inside compiler-generated closures (in case they call other nested functions).

            // State machines can be emitted into lambda display classes, so we need to go down at least two
            // levels to find calls from iterator nested functions to other nested functions. We just recurse into
            // all compiler-generated nested types to avoid depending on implementation details.

            foreach (var nestedType in GetCompilerGeneratedNestedTypes(type))
            {
                foreach (var method in nestedType.Methods)
                {
                    ProcessMethod(method);
                }
            }

            // Now we've discovered the call graphs for calls to nested functions.
            // Use this to map back from nested functions to the declaring user methods.

            // Note: This maps all nested functions back to the user code, not to the immediately
            // declaring local function. The IL doesn't contain enough information in general for
            // us to determine the nesting of local functions and lambdas.

            // Note: this only discovers nested functions which are referenced from the user
            // code or its referenced nested functions. There is no reliable way to determine from
            // IL which user code an unused nested function belongs to.
            foreach (var userDefinedMethod in callingMethods)
            {
                foreach (var compilerGeneratedMember in callGraph.GetReachableMembers(userDefinedMethod))
                {
                    switch (compilerGeneratedMember)
                    {
                    case MethodDefinition nestedFunction:
                        Debug.Assert(CompilerGeneratedNames.IsLambdaOrLocalFunction(nestedFunction.Name));
                        // Nested functions get suppressions from the user method only.
                        if (!_compilerGeneratedMethodToUserCodeMethod.TryAdd(nestedFunction, userDefinedMethod))
                        {
                            var alreadyAssociatedMethod = _compilerGeneratedMethodToUserCodeMethod[nestedFunction];
                            _context.LogWarning(new MessageOrigin(userDefinedMethod), DiagnosticId.MethodsAreAssociatedWithUserMethod, userDefinedMethod.GetDisplayName(), alreadyAssociatedMethod.GetDisplayName(), nestedFunction.GetDisplayName());
                        }
                        break;

                    case TypeDefinition stateMachineType:
                        // Types in the call graph are always state machine types
                        // For those all their methods are not tracked explicitly in the call graph; instead, they
                        // are represented by the state machine type itself.
                        // We are already tracking the association of the state machine type to the user code method
                        // above, so no need to track it here.
                        Debug.Assert(CompilerGeneratedNames.IsStateMachineType(stateMachineType.Name));
                        break;

                    default:
                        throw new InvalidOperationException();
                    }
                }
            }
        }
Beispiel #30
0
        void VerifyMethod(MethodDefinition src, MethodDefinition?linked)
        {
            bool expectedKept = ShouldMethodBeKept(src);

            VerifyMethodInternal(src, linked, expectedKept);
        }