/// <summary>
        /// Subset of <see cref="Scan(ref DependencyList, NodeFactory, MethodIL)"/> that only deals with Marshal.SizeOf.
        /// </summary>
        public static void ScanMarshalOnly(ref DependencyList list, NodeFactory factory, MethodIL methodIL)
        {
            ILReader reader = new ILReader(methodIL.GetILBytes());

            Tracker tracker = new Tracker(methodIL);

            while (reader.HasNext)
            {
                ILOpcode opcode = reader.ReadILOpcode();
                switch (opcode)
                {
                case ILOpcode.ldtoken:
                    tracker.TrackLdTokenToken(reader.ReadILToken());
                    break;

                case ILOpcode.call:
                    var method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc;
                    if (method != null && method.Name == "SizeOf" && IsMarshalSizeOf(method))
                    {
                        TypeDesc type = tracker.GetLastType();
                        if (IsTypeEligibleForMarshalSizeOfTracking(type))
                        {
                            list = list ?? new DependencyList();

                            list.Add(factory.StructMarshallingData((DefType)type), "Marshal.SizeOf");
                        }
                    }
                    break;

                default:
                    reader.Skip(opcode);
                    break;
                }
            }
        }
        public bool TryReadLdtoken(out int token)
        {
            if (_reader.PeekILOpcode() != ILOpcode.ldtoken)
            {
                token = 0;
                return(false);
            }

            _reader.ReadILOpcode();
            token = _reader.ReadILToken();
            return(true);
        }
        public static void Scan(ref DependencyList list, NodeFactory factory, MethodIL methodIL)
        {
            ILReader reader = new ILReader(methodIL.GetILBytes());

            Tracker tracker = new Tracker(methodIL);

            // The algorithm here is really primitive: we scan the IL forward in a single pass, remembering
            // the last type/string/token we saw.
            //
            // We then intrinsically recognize a couple methods that consume this information.
            //
            // This has obvious problems since we don't have exact knowledge of the parameters passed
            // (something being in front of a call doesn't mean it's a parameter to the call). But since
            // this is a heuristic, it's okay. We want this to be as fast as possible.
            //
            // The main purposes of this scanner is to make following patterns work:
            //
            // * Enum.GetValues(typeof(Foo)) - this is very common and we need to make sure Foo[] is compiled.
            // * Type.GetType("Foo, Bar").GetMethod("Blah") - framework uses this to work around layering problems.
            // * typeof(Foo<>).MakeGenericType(arg).GetMethod("Blah") - used in e.g. LINQ expressions implementation
            // * Marshal.SizeOf(typeof(Foo)) - very common and we need to make sure interop data is generated

            while (reader.HasNext)
            {
                ILOpcode opcode = reader.ReadILOpcode();
                switch (opcode)
                {
                case ILOpcode.ldstr:
                    tracker.TrackStringToken(reader.ReadILToken());
                    break;

                case ILOpcode.ldtoken:
                    tracker.TrackLdTokenToken(reader.ReadILToken());
                    break;

                case ILOpcode.call:
                case ILOpcode.callvirt:
                    var method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc;
                    if (method != null)
                    {
                        HandleCall(ref list, factory, methodIL, method, ref tracker);
                    }
                    break;

                default:
                    reader.Skip(opcode);
                    break;
                }
            }
        }
Beispiel #4
0
        public void TestMDArrayFunctionReading()
        {
            MetadataType mdArrayFunctionResolutionType = _testModule.GetType("", "MDArrayFunctionResolution");
            MethodDesc   methodWithMDArrayUsage        = mdArrayFunctionResolutionType.GetMethods().Single(m => string.Equals(m.Name, "MethodWithUseOfMDArrayFunctions"));
            MethodIL     methodIL  = EcmaMethodIL.Create((EcmaMethod)methodWithMDArrayUsage);
            ILReader     ilReader  = new ILReader(methodIL.GetILBytes());
            int          failures  = 0;
            int          successes = 0;

            while (ilReader.HasNext)
            {
                ILOpcode opcode = ilReader.ReadILOpcode();
                switch (opcode)
                {
                case ILOpcode.call:
                case ILOpcode.newobj:
                    int    token = ilReader.ReadILToken();
                    object tokenReferenceResult = methodIL.GetObject(token, NotFoundBehavior.ReturnNull);
                    if (tokenReferenceResult == null)
                    {
                        failures++;
                        tokenReferenceResult = "null";
                    }
                    else
                    {
                        successes++;
                    }
                    _output.WriteLine($"call {tokenReferenceResult.ToString()}");
                    break;
                }
            }

            Assert.Equal(0, failures);
            Assert.Equal(4, successes);
        }
Beispiel #5
0
        /// <summary>
        /// Skips over a "foo == typeof(Bar)" or "typeof(Foo) == typeof(Bar)" sequence.
        /// </summary>
        private static bool IsTypeEqualityTest(MethodIL methodIL, ILReader reader, out ILReader afterTest)
        {
            afterTest = default;

            if (reader.ReadILOpcode() != ILOpcode.call)
            {
                return(false);
            }
            MethodDesc method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc;

            if (method == null || method.Name != "GetTypeFromHandle" && !method.OwningType.IsSystemType())
            {
                return(false);
            }

            ILOpcode opcode = reader.ReadILOpcode();

            if (opcode == ILOpcode.ldtoken)
            {
                reader.ReadILToken();
                opcode = reader.ReadILOpcode();
                if (opcode != ILOpcode.call)
                {
                    return(false);
                }
                method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc;
                if (method == null || method.Name != "GetTypeFromHandle" && !method.OwningType.IsSystemType())
                {
                    return(false);
                }
                opcode = reader.ReadILOpcode();
            }
            if (opcode != ILOpcode.call)
            {
                return(false);
            }
            method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc;
            if (method == null || method.Name != "op_Equality" && !method.OwningType.IsSystemType())
            {
                return(false);
            }

            afterTest = reader;
            return(true);
        }
Beispiel #6
0
        public static MibcConfig ParseMibcConfig(TypeSystemContext tsc, PEReader pEReader)
        {
            EcmaModule mibcModule    = EcmaModule.Create(tsc, pEReader, null);
            EcmaMethod mibcConfigMth = (EcmaMethod)mibcModule.GetGlobalModuleType().GetMethod(nameof(MibcConfig), null);

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

            var ilBody   = EcmaMethodIL.Create(mibcConfigMth);
            var ilReader = new ILReader(ilBody.GetILBytes());

            // Parse:
            //
            //   ldstr "key1"
            //   ldstr "value1"
            //   pop
            //   pop
            //   ldstr "key2"
            //   ldstr "value2"
            //   pop
            //   pop
            //   ...
            //   ret
            string fieldName = null;
            Dictionary <string, string> keyValue = new();

            while (ilReader.HasNext)
            {
                ILOpcode opcode = ilReader.ReadILOpcode();
                switch (opcode)
                {
                case ILOpcode.ldstr:
                    var ldStrValue = (string)ilBody.GetObject(ilReader.ReadILToken());
                    if (fieldName != null)
                    {
                        keyValue[fieldName] = ldStrValue;
                    }
                    else
                    {
                        fieldName = ldStrValue;
                    }
                    break;

                case ILOpcode.ret:
                case ILOpcode.pop:
                    fieldName = null;
                    break;

                default:
                    throw new InvalidOperationException($"Unexpected opcode: {opcode}");
                }
            }

            return(MibcConfig.FromKeyValueMap(keyValue));
        }
Beispiel #7
0
            private static bool ScanMethodBodyForFieldAccess(MethodIL body, bool write, out FieldDesc?found)
            {
                // Tries to find the backing field for a property getter/setter.
                // Returns true if this is a method body that we can unambiguously analyze.
                // The found field could still be null if there's no backing store.
                found = null;

                ILReader ilReader = new ILReader(body.GetILBytes());

                while (ilReader.HasNext)
                {
                    ILOpcode opcode = ilReader.ReadILOpcode();
                    switch (opcode)
                    {
                    case ILOpcode.ldsfld when !write:
                    case ILOpcode.ldfld when !write:
                    case ILOpcode.stsfld when write:
                    case ILOpcode.stfld when write:
                    {
                        // This writes/reads multiple fields - can't guess which one is the backing store.
                        // Return failure.
                        if (found != null)
                        {
                            found = null;
                            return(false);
                        }
                        found = (FieldDesc)body.GetObject(ilReader.ReadILToken());
                    }
                    break;

                    default:
                        ilReader.Skip(opcode);
                        break;
                    }
                }

                if (found == null)
                {
                    // Doesn't access any fields. Could be e.g. "Type Foo => typeof(Bar);"
                    // Return success.
                    return(true);
                }

                if (found.OwningType != body.OwningMethod.OwningType ||
                    found.IsStatic != body.OwningMethod.Signature.IsStatic ||
                    !found.HasCustomAttribute("System.Runtime.CompilerServices", "CompilerGeneratedAttribute"))
                {
                    // A couple heuristics to make sure we got the right field.
                    // Return failure.
                    found = null;
                    return(false);
                }

                return(true);
            }
Beispiel #8
0
        private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[] flags, int offset, int argIndex, out int constant)
        {
            if ((flags[offset] & OpcodeFlags.BasicBlockStart) != 0)
            {
                constant = 0;
                return(false);
            }

            for (int currentOffset = offset - 1; currentOffset >= 0; currentOffset--)
            {
                if ((flags[currentOffset] & OpcodeFlags.InstructionStart) == 0)
                {
                    continue;
                }

                ILReader reader = new ILReader(body, currentOffset);
                ILOpcode opcode = reader.ReadILOpcode();
                if (opcode == ILOpcode.call || opcode == ILOpcode.callvirt)
                {
                    MethodDesc method = (MethodDesc)methodIL.GetObject(reader.ReadILToken());
                    if (argIndex == 0)
                    {
                        BodySubstitution substitution = GetSubstitution(method);
                        if (substitution != null && substitution.Value is int &&
                            (opcode != ILOpcode.callvirt || !method.IsVirtual))
                        {
                            constant = (int)substitution.Value;
                            return(true);
                        }
                        else
                        {
                            constant = 0;
                            return(false);
                        }
                    }

                    argIndex--;

                    if (method.Signature.Length > 0 || !method.Signature.IsStatic)
                    {
                        // We don't know how to skip over the parameters
                        break;
                    }
                }
                else if (opcode == ILOpcode.ldsfld)
                {
                    FieldDesc field = (FieldDesc)methodIL.GetObject(reader.ReadILToken());
                    if (argIndex == 0)
                    {
                        object substitution = GetSubstitution(field);
                        if (substitution is int)
                        {
                            constant = (int)substitution;
                            return(true);
                        }
                        else
                        {
                            constant = 0;
                            return(false);
                        }
                    }

                    argIndex--;
                }
                else if (opcode >= ILOpcode.ldc_i4_0 && opcode <= ILOpcode.ldc_i4_8)
                {
                    if (argIndex == 0)
                    {
                        constant = opcode - ILOpcode.ldc_i4_0;
                        return(true);
                    }

                    argIndex--;
                }
                else if (opcode == ILOpcode.ldc_i4)
                {
                    if (argIndex == 0)
                    {
                        constant = (int)reader.ReadILUInt32();
                        return(true);
                    }

                    argIndex--;
                }
                else if (opcode == ILOpcode.ldc_i4_s)
                {
                    if (argIndex == 0)
                    {
                        constant = (int)(sbyte)reader.ReadILByte();
                        return(true);
                    }

                    argIndex--;
                }
                else if ((opcode == ILOpcode.ldloc || opcode == ILOpcode.ldloc_s ||
                          (opcode >= ILOpcode.ldloc_0 && opcode <= ILOpcode.ldloc_3)) &&
                         ((flags[currentOffset] & OpcodeFlags.BasicBlockStart) == 0))
                {
                    // Paired stloc/ldloc that the C# compiler generates in debug code?
                    int locIndex = opcode switch
                    {
                        ILOpcode.ldloc => reader.ReadILUInt16(),
                        ILOpcode.ldloc_s => reader.ReadILByte(),
                        _ => opcode - ILOpcode.ldloc_0,
                    };

                    for (int potentialStlocOffset = currentOffset - 1; potentialStlocOffset >= 0; potentialStlocOffset--)
                    {
                        if ((flags[potentialStlocOffset] & OpcodeFlags.InstructionStart) == 0)
                        {
                            continue;
                        }

                        ILReader nestedReader = new ILReader(body, potentialStlocOffset);
                        ILOpcode otherOpcode  = nestedReader.ReadILOpcode();
                        if ((otherOpcode == ILOpcode.stloc || otherOpcode == ILOpcode.stloc_s ||
                             (otherOpcode >= ILOpcode.stloc_0 && otherOpcode <= ILOpcode.stloc_3)) &&
                            otherOpcode switch
                        {
                            ILOpcode.stloc => nestedReader.ReadILUInt16(),
                            ILOpcode.stloc_s => nestedReader.ReadILByte(),
                            _ => otherOpcode - ILOpcode.stloc_0,
                        } == locIndex)
Beispiel #9
0
            private void WalkMethod(EcmaMethod method)
            {
                Instantiation typeContext   = method.OwningType.Instantiation;
                Instantiation methodContext = method.Instantiation;

                MethodSignature methodSig = method.Signature;

                ProcessTypeReference(methodSig.ReturnType, typeContext, methodContext);
                foreach (TypeDesc parameterType in methodSig)
                {
                    ProcessTypeReference(parameterType, typeContext, methodContext);
                }

                if (method.IsAbstract)
                {
                    return;
                }

                var methodIL = EcmaMethodIL.Create(method);

                if (methodIL == null)
                {
                    return;
                }

                // If this is a generic virtual method, add an edge from each of the generic parameters
                // of the implementation to the generic parameters of the declaration - any call to the
                // declaration will be modeled as if the declaration was calling into the implementation.
                if (method.IsVirtual && method.HasInstantiation)
                {
                    var decl = (EcmaMethod)MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method).GetTypicalMethodDefinition();
                    if (decl != method)
                    {
                        Instantiation declInstantiation = decl.Instantiation;
                        Instantiation implInstantiation = method.Instantiation;
                        for (int i = 0; i < declInstantiation.Length; i++)
                        {
                            RecordBinding(
                                (EcmaGenericParameter)implInstantiation[i],
                                (EcmaGenericParameter)declInstantiation[i],
                                isProperEmbedding: false);
                        }
                    }
                }

                // Walk the method body looking at referenced things that have some genericness.
                // Nongeneric things cannot be forming cycles.
                // In particular, we don't care about MemberRefs to non-generic things, TypeDefs/MethodDefs/FieldDefs.
                // Avoid the work to even materialize type system entities for those.

                ILReader reader = new ILReader(methodIL.GetILBytes());

                while (reader.HasNext)
                {
                    ILOpcode opcode = reader.ReadILOpcode();
                    switch (opcode)
                    {
                    case ILOpcode.sizeof_:
                    case ILOpcode.newarr:
                    case ILOpcode.initobj:
                    case ILOpcode.stelem:
                    case ILOpcode.ldelem:
                    case ILOpcode.ldelema:
                    case ILOpcode.box:
                    case ILOpcode.unbox:
                    case ILOpcode.unbox_any:
                    case ILOpcode.cpobj:
                    case ILOpcode.ldobj:
                    case ILOpcode.castclass:
                    case ILOpcode.isinst:
                    case ILOpcode.stobj:
                    case ILOpcode.refanyval:
                    case ILOpcode.mkrefany:
                    case ILOpcode.constrained:
                        EntityHandle accessedType = MetadataTokens.EntityHandle(reader.ReadILToken());
typeCase:
                        if (accessedType.Kind == HandleKind.TypeSpecification)
                        {
                            var t = methodIL.GetObject(MetadataTokens.GetToken(accessedType), NotFoundBehavior.ReturnNull) as TypeDesc;
                            if (t != null)
                            {
                                ProcessTypeReference(t, typeContext, methodContext);
                            }
                        }
                        break;

                    case ILOpcode.stsfld:
                    case ILOpcode.ldsfld:
                    case ILOpcode.ldsflda:
                    case ILOpcode.stfld:
                    case ILOpcode.ldfld:
                    case ILOpcode.ldflda:
                        EntityHandle accessedField = MetadataTokens.EntityHandle(reader.ReadILToken());
fieldCase:
                        if (accessedField.Kind == HandleKind.MemberReference)
                        {
                            accessedType = _metadataReader.GetMemberReference((MemberReferenceHandle)accessedField).Parent;
                            goto typeCase;
                        }
                        break;

                    case ILOpcode.call:
                    case ILOpcode.callvirt:
                    case ILOpcode.newobj:
                    case ILOpcode.ldftn:
                    case ILOpcode.ldvirtftn:
                    case ILOpcode.jmp:
                        EntityHandle accessedMethod = MetadataTokens.EntityHandle(reader.ReadILToken());
methodCase:
                        if (accessedMethod.Kind == HandleKind.MethodSpecification ||
                            (accessedMethod.Kind == HandleKind.MemberReference &&
                             _metadataReader.GetMemberReference((MemberReferenceHandle)accessedMethod).Parent.Kind == HandleKind.TypeSpecification))
                        {
                            var m = methodIL.GetObject(MetadataTokens.GetToken(accessedMethod), NotFoundBehavior.ReturnNull) as MethodDesc;
                            ProcessTypeReference(m.OwningType, typeContext, methodContext);
                            ProcessMethodCall(m, typeContext, methodContext);
                        }
                        break;

                    case ILOpcode.ldtoken:
                        EntityHandle accessedEntity = MetadataTokens.EntityHandle(reader.ReadILToken());
                        if (accessedEntity.Kind == HandleKind.MethodSpecification ||
                            (accessedEntity.Kind == HandleKind.MemberReference && _metadataReader.GetMemberReference((MemberReferenceHandle)accessedEntity).GetKind() == MemberReferenceKind.Method))
                        {
                            accessedMethod = accessedEntity;
                            goto methodCase;
                        }
                        else if (accessedEntity.Kind == HandleKind.MemberReference)
                        {
                            accessedField = accessedEntity;
                            goto fieldCase;
                        }
                        else if (accessedEntity.Kind == HandleKind.TypeSpecification)
                        {
                            accessedType = accessedEntity;
                            goto typeCase;
                        }
                        break;

                    default:
                        reader.Skip(opcode);
                        break;
                    }
                }
            }
Beispiel #10
0
            internal TypeCache(MetadataType type, Logger?logger, ILProvider ilProvider)
            {
                Debug.Assert(type == type.GetTypeDefinition());
                Debug.Assert(!CompilerGeneratedNames.IsGeneratedMemberName(type.Name));

                Type = type;

                var callGraph          = new CompilerGeneratedCallGraph();
                var userDefinedMethods = new HashSet <MethodDesc>();

                void ProcessMethod(MethodDesc method)
                {
                    Debug.Assert(method == method.GetTypicalMethodDefinition());

                    bool isStateMachineMember = CompilerGeneratedNames.IsStateMachineType(((MetadataType)method.OwningType).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 = userDefinedMethods.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).
                    var methodBody = ilProvider.GetMethodIL(method);

                    if (methodBody != null)
                    {
                        ILReader reader = new ILReader(methodBody.GetILBytes());
                        while (reader.HasNext)
                        {
                            ILOpcode opcode = reader.ReadILOpcode();
                            switch (opcode)
                            {
                            case ILOpcode.ldftn:
                            case ILOpcode.ldtoken:
                            case ILOpcode.call:
                            case ILOpcode.callvirt:
                            case ILOpcode.newobj:
                            {
                                MethodDesc?referencedMethod = methodBody.GetObject(reader.ReadILToken(), NotFoundBehavior.ReturnNull) as MethodDesc;
                                if (referencedMethod == null)
                                {
                                    continue;
                                }

                                referencedMethod = referencedMethod.GetTypicalMethodDefinition();

                                if (referencedMethod.IsConstructor &&
                                    referencedMethod.OwningType is MetadataType generatedType &&
                                    // Don't consider calls in the same type, like inside a static constructor
                                    method.OwningType != generatedType &&
                                    CompilerGeneratedNames.IsLambdaDisplayClass(generatedType.Name))
                                {
                                    Debug.Assert(generatedType.IsTypeDefinition);

                                    // fill in null for now, attribute providers will be filled in later
                                    _generatedTypeToTypeArgumentInfo ??= new Dictionary <MetadataType, TypeArgumentInfo>();

                                    if (!_generatedTypeToTypeArgumentInfo.TryAdd(generatedType, new TypeArgumentInfo(method, null)))
                                    {
                                        var alreadyAssociatedMethod = _generatedTypeToTypeArgumentInfo[generatedType].CreatingMethod;
                                        logger?.LogWarning(new MessageOrigin(method), DiagnosticId.MethodsAreAssociatedWithUserMethod, method.GetDisplayName(), alreadyAssociatedMethod.GetDisplayName(), generatedType.GetDisplayName());
                                    }
                                    continue;
                                }

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

                                if (isStateMachineMember)
                                {
                                    callGraph.TrackCall((MetadataType)method.OwningType, referencedMethod);
                                }
                                else
                                {
                                    callGraph.TrackCall(method, referencedMethod);
                                }
                            }
                            break;

                            case ILOpcode.stsfld:
                            {
                                // Same as above, but stsfld instead of a call to the constructor
                                FieldDesc?field = methodBody.GetObject(reader.ReadILToken()) as FieldDesc;
                                if (field == null)
                                {
                                    continue;
                                }

                                field = field.GetTypicalFieldDefinition();

                                if (field.OwningType is MetadataType generatedType &&
                                    // Don't consider field accesses in the same type, like inside a static constructor
                                    method.OwningType != generatedType &&
                                    CompilerGeneratedNames.IsLambdaDisplayClass(generatedType.Name))
                                {
                                    Debug.Assert(generatedType.IsTypeDefinition);

                                    _generatedTypeToTypeArgumentInfo ??= new Dictionary <MetadataType, TypeArgumentInfo>();

                                    if (!_generatedTypeToTypeArgumentInfo.TryAdd(generatedType, new TypeArgumentInfo(method, null)))
                                    {
                                        // It's expected that there may be multiple methods associated with the same static closure environment.
                                        // All of these methods will substitute the same type arguments into the closure environment
                                        // (if it is generic). Don't warn.
                                    }
                                    continue;
                                }
                            }
                            break;

                            default:
                                reader.Skip(opcode);
                                break;
                            }
                        }
                    }

                    if (TryGetStateMachineType(method, out MetadataType? stateMachineType))
                    {
                        Debug.Assert(stateMachineType.ContainingType == type ||
                                     (CompilerGeneratedNames.IsGeneratedMemberName(stateMachineType.ContainingType.Name) &&
                                      stateMachineType.ContainingType.ContainingType == type));
                        Debug.Assert(stateMachineType == stateMachineType.GetTypeDefinition());

                        callGraph.TrackCall(method, stateMachineType);

                        _compilerGeneratedTypeToUserCodeMethod ??= new Dictionary <MetadataType, MethodDesc>();
                        if (!_compilerGeneratedTypeToUserCodeMethod.TryAdd(stateMachineType, method))
                        {
                            var alreadyAssociatedMethod = _compilerGeneratedTypeToUserCodeMethod[stateMachineType];
                            logger?.LogWarning(new MessageOrigin(method), DiagnosticId.MethodsAreAssociatedWithStateMachine, method.GetDisplayName(), alreadyAssociatedMethod.GetDisplayName(), stateMachineType.GetDisplayName());
                        }
                        // Already warned above if multiple methods map to the same type
                        // Fill in null for argument providers now, the real providers will be filled in later
                        _generatedTypeToTypeArgumentInfo ??= new Dictionary <MetadataType, TypeArgumentInfo>();
                        _generatedTypeToTypeArgumentInfo[stateMachineType] = new TypeArgumentInfo(method, null);
                    }
                }

                // Look for state machine methods, and methods which call local functions.
                foreach (MethodDesc method in type.GetMethods())
                {
                    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.GetMethods())
                    {
                        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 userDefinedMethods)
                {
                    var callees = callGraph.GetReachableMembers(userDefinedMethod);
                    if (!callees.Any())
                    {
                        continue;
                    }

                    _compilerGeneratedMembers ??= new Dictionary <MethodDesc, List <TypeSystemEntity> >();
                    _compilerGeneratedMembers.Add(userDefinedMethod, new List <TypeSystemEntity>(callees));

                    foreach (var compilerGeneratedMember in callees)
                    {
                        switch (compilerGeneratedMember)
                        {
                        case MethodDesc nestedFunction:
                            Debug.Assert(CompilerGeneratedNames.IsLambdaOrLocalFunction(nestedFunction.Name));
                            // Nested functions get suppressions from the user method only.
                            _compilerGeneratedMethodToUserCodeMethod ??= new Dictionary <MethodDesc, MethodDesc>();
                            if (!_compilerGeneratedMethodToUserCodeMethod.TryAdd(nestedFunction, userDefinedMethod))
                            {
                                var alreadyAssociatedMethod = _compilerGeneratedMethodToUserCodeMethod[nestedFunction];
                                logger?.LogWarning(new MessageOrigin(userDefinedMethod), DiagnosticId.MethodsAreAssociatedWithUserMethod, userDefinedMethod.GetDisplayName(), alreadyAssociatedMethod.GetDisplayName(), nestedFunction.GetDisplayName());
                            }
                            break;

                        case MetadataType 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();
                        }
                    }
                }

                // Now that we have instantiating methods fully filled out, walk the generated types and fill in the attribute
                // providers
                if (_generatedTypeToTypeArgumentInfo != null)
                {
                    foreach (var generatedType in _generatedTypeToTypeArgumentInfo.Keys)
                    {
                        Debug.Assert(generatedType == generatedType.GetTypeDefinition());

                        if (HasGenericParameters(generatedType))
                        {
                            MapGeneratedTypeTypeParameters(generatedType);
                        }
                    }
                }
Beispiel #11
0
            private void WalkMethod(EcmaMethod method)
            {
                Instantiation typeContext   = method.OwningType.Instantiation;
                Instantiation methodContext = method.Instantiation;

                MethodSignature methodSig = method.Signature;

                ProcessTypeReference(methodSig.ReturnType, typeContext, methodContext);
                foreach (TypeDesc parameterType in methodSig)
                {
                    ProcessTypeReference(parameterType, typeContext, methodContext);
                }

                if (method.IsAbstract)
                {
                    return;
                }

                var methodIL = EcmaMethodIL.Create(method);

                if (methodIL == null)
                {
                    return;
                }

                // Walk the method body looking at referenced things that have some genericness.
                // Nongeneric things cannot be forming cycles.
                // In particular, we don't care about MemberRefs to non-generic things, TypeDefs/MethodDefs/FieldDefs.
                // Avoid the work to even materialize type system entities for those.

                ILReader reader = new ILReader(methodIL.GetILBytes());

                while (reader.HasNext)
                {
                    ILOpcode opcode = reader.ReadILOpcode();
                    switch (opcode)
                    {
                    case ILOpcode.sizeof_:
                    case ILOpcode.newarr:
                    case ILOpcode.initobj:
                    case ILOpcode.stelem:
                    case ILOpcode.ldelem:
                    case ILOpcode.ldelema:
                    case ILOpcode.box:
                    case ILOpcode.unbox:
                    case ILOpcode.unbox_any:
                    case ILOpcode.cpobj:
                    case ILOpcode.ldobj:
                    case ILOpcode.castclass:
                    case ILOpcode.isinst:
                    case ILOpcode.stobj:
                    case ILOpcode.refanyval:
                    case ILOpcode.mkrefany:
                    case ILOpcode.constrained:
                        EntityHandle accessedType = MetadataTokens.EntityHandle(reader.ReadILToken());
typeCase:
                        if (accessedType.Kind == HandleKind.TypeSpecification)
                        {
                            var t = methodIL.GetObject(MetadataTokens.GetToken(accessedType), NotFoundBehavior.ReturnNull) as TypeDesc;
                            if (t != null)
                            {
                                ProcessTypeReference(t, typeContext, methodContext);
                            }
                        }
                        break;

                    case ILOpcode.stsfld:
                    case ILOpcode.ldsfld:
                    case ILOpcode.ldsflda:
                    case ILOpcode.stfld:
                    case ILOpcode.ldfld:
                    case ILOpcode.ldflda:
                        EntityHandle accessedField = MetadataTokens.EntityHandle(reader.ReadILToken());
fieldCase:
                        if (accessedField.Kind == HandleKind.MemberReference)
                        {
                            accessedType = _metadataReader.GetMemberReference((MemberReferenceHandle)accessedField).Parent;
                            goto typeCase;
                        }
                        break;

                    case ILOpcode.call:
                    case ILOpcode.callvirt:
                    case ILOpcode.newobj:
                    case ILOpcode.ldftn:
                    case ILOpcode.ldvirtftn:
                    case ILOpcode.jmp:
                        EntityHandle accessedMethod = MetadataTokens.EntityHandle(reader.ReadILToken());
methodCase:
                        if (accessedMethod.Kind == HandleKind.MethodSpecification ||
                            (accessedMethod.Kind == HandleKind.MemberReference &&
                             _metadataReader.GetMemberReference((MemberReferenceHandle)accessedMethod).Parent.Kind == HandleKind.TypeSpecification))
                        {
                            var m = methodIL.GetObject(MetadataTokens.GetToken(accessedMethod), NotFoundBehavior.ReturnNull) as MethodDesc;
                            if (m != null)
                            {
                                ProcessTypeReference(m.OwningType, typeContext, methodContext);
                                ProcessMethodCall(m, typeContext, methodContext);
                            }
                        }
                        break;

                    case ILOpcode.ldtoken:
                        EntityHandle accessedEntity = MetadataTokens.EntityHandle(reader.ReadILToken());
                        if (accessedEntity.Kind == HandleKind.MethodSpecification ||
                            (accessedEntity.Kind == HandleKind.MemberReference && _metadataReader.GetMemberReference((MemberReferenceHandle)accessedEntity).GetKind() == MemberReferenceKind.Method))
                        {
                            accessedMethod = accessedEntity;
                            goto methodCase;
                        }
                        else if (accessedEntity.Kind == HandleKind.MemberReference)
                        {
                            accessedField = accessedEntity;
                            goto fieldCase;
                        }
                        else if (accessedEntity.Kind == HandleKind.TypeSpecification)
                        {
                            accessedType = accessedEntity;
                            goto typeCase;
                        }
                        break;

                    default:
                        reader.Skip(opcode);
                        break;
                    }
                }
            }
Beispiel #12
0
        /// <summary>
        /// Parse MIbcGroup method and return enumerable of MethodProfileData
        ///
        /// Like the AssemblyDictionary method, data is encoded via IL instructions. The format is
        ///
        /// ldtoken methodInProfileData
        /// Any series of instructions that does not include pop. Expansion data is encoded via ldstr "id"
        /// followed by a expansion specific sequence of il opcodes.
        /// pop
        /// {Repeat N times for N methods described}
        ///
        /// Extensions supported with current parser:
        ///
        /// ldstr "ExclusiveWeight"
        /// Any ldc.i4 or ldc.r4 or ldc.r8 instruction to indicate the exclusive weight
        ///
        /// ldstr "WeightedCallData"
        /// ldc.i4 <Count of methods called>
        /// Repeat <Count of methods called times>
        ///  ldtoken <Method called from this method>
        ///  ldc.i4 <Weight associated with calling the <Method called from this method>>
        ///
        /// This format is designed to be extensible to hold more data as we add new per method profile data without breaking existing parsers.
        /// </summary>
        static IEnumerable <MethodProfileData> ReadMIbcGroup(TypeSystemContext tsc, EcmaMethod method)
        {
            EcmaMethodIL             ilBody           = EcmaMethodIL.Create(method);
            MetadataLoaderForPgoData metadataLoader   = new MetadataLoaderForPgoData(ilBody);
            ILReader            ilReader              = new ILReader(ilBody.GetILBytes());
            object              methodInProgress      = null;
            object              metadataNotResolvable = new object();
            object              metadataObject        = null;
            MibcGroupParseState state            = MibcGroupParseState.LookingForNextMethod;
            int    intValue                      = 0;
            int    weightedCallGraphSize         = 0;
            int    profileEntryFound             = 0;
            double exclusiveWeight               = 0;
            Dictionary <MethodDesc, int> weights = null;
            bool        processIntValue          = false;
            List <long> instrumentationDataLongs = null;

            PgoSchemaElem[] pgoSchemaData = null;

            while (ilReader.HasNext)
            {
                ILOpcode opcode = ilReader.ReadILOpcode();
                processIntValue = false;
                switch (opcode)
                {
                case ILOpcode.ldtoken:
                {
                    int token = ilReader.ReadILToken();
                    if (state == MibcGroupParseState.ProcessingInstrumentationData)
                    {
                        instrumentationDataLongs.Add(token);
                    }
                    else
                    {
                        metadataObject = null;
                        try
                        {
                            metadataObject = ilBody.GetObject(token);
                        }
                        catch (TypeSystemException)
                        {
                            // The method being referred to may be missing. In that situation,
                            // use the metadataNotResolvable sentinel to indicate that this record should be ignored
                            metadataObject = metadataNotResolvable;
                        }
                        switch (state)
                        {
                        case MibcGroupParseState.ProcessingCallgraphToken:
                            state = MibcGroupParseState.ProcessingCallgraphWeight;
                            break;

                        case MibcGroupParseState.LookingForNextMethod:
                            methodInProgress = metadataObject;
                            state            = MibcGroupParseState.LookingForOptionalData;
                            break;

                        default:
                            state = MibcGroupParseState.LookingForOptionalData;
                            break;
                        }
                    }
                }
                break;

                case ILOpcode.ldc_r4:
                {
                    float fltValue = ilReader.ReadILFloat();

                    switch (state)
                    {
                    case MibcGroupParseState.ProcessingExclusiveWeight:
                        exclusiveWeight = fltValue;
                        state           = MibcGroupParseState.LookingForOptionalData;
                        break;

                    default:
                        state = MibcGroupParseState.LookingForOptionalData;
                        break;
                    }

                    break;
                }

                case ILOpcode.ldc_r8:
                {
                    double dblValue = ilReader.ReadILDouble();

                    switch (state)
                    {
                    case MibcGroupParseState.ProcessingExclusiveWeight:
                        exclusiveWeight = dblValue;
                        state           = MibcGroupParseState.LookingForOptionalData;
                        break;

                    default:
                        state = MibcGroupParseState.LookingForOptionalData;
                        break;
                    }
                    break;
                }

                case ILOpcode.ldc_i4_0:
                    intValue        = 0;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_1:
                    intValue        = 1;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_2:
                    intValue        = 2;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_3:
                    intValue        = 3;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_4:
                    intValue        = 4;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_5:
                    intValue        = 5;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_6:
                    intValue        = 6;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_7:
                    intValue        = 7;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_8:
                    intValue        = 8;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_m1:
                    intValue        = -1;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_s:
                    intValue        = (sbyte)ilReader.ReadILByte();
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4:
                    intValue        = (int)ilReader.ReadILUInt32();
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i8:
                    if (state == MibcGroupParseState.ProcessingInstrumentationData)
                    {
                        instrumentationDataLongs.Add((long)ilReader.ReadILUInt64());
                    }
                    break;

                case ILOpcode.ldstr:
                {
                    int    userStringToken  = ilReader.ReadILToken();
                    string optionalDataName = (string)ilBody.GetObject(userStringToken);
                    switch (optionalDataName)
                    {
                    case "ExclusiveWeight":
                        state = MibcGroupParseState.ProcessingExclusiveWeight;
                        break;

                    case "WeightedCallData":
                        state = MibcGroupParseState.ProcessingCallgraphCount;
                        break;

                    case "InstrumentationDataStart":
                        state = MibcGroupParseState.ProcessingInstrumentationData;
                        instrumentationDataLongs = new List <long>();
                        break;

                    case "InstrumentationDataEnd":
                        if (instrumentationDataLongs != null)
                        {
                            instrumentationDataLongs.Add(2);             // MarshalMask 2 (Type)
                            instrumentationDataLongs.Add(0);             // PgoInstrumentationKind.Done (0)
                            pgoSchemaData = PgoProcessor.ParsePgoData <TypeSystemEntityOrUnknown>(metadataLoader, instrumentationDataLongs, false).ToArray();
                        }
                        state = MibcGroupParseState.LookingForOptionalData;
                        break;

                    default:
                        state = MibcGroupParseState.LookingForOptionalData;
                        break;
                    }
                }
                break;

                case ILOpcode.pop:
                    if (methodInProgress != metadataNotResolvable)
                    {
                        profileEntryFound++;
                        if (exclusiveWeight == 0)
                        {
                            // If no exclusive weight is found assign a non zero value that assumes the order in the pgo file is significant.
                            exclusiveWeight = Math.Min(1000000.0 - profileEntryFound, 0.0) / 1000000.0;
                        }
                        MethodProfileData mibcData = new MethodProfileData((MethodDesc)methodInProgress, MethodProfilingDataFlags.ReadMethodCode, exclusiveWeight, weights, 0xFFFFFFFF, pgoSchemaData);
                        state                    = MibcGroupParseState.LookingForNextMethod;
                        exclusiveWeight          = 0;
                        weights                  = null;
                        instrumentationDataLongs = null;
                        pgoSchemaData            = null;
                        yield return(mibcData);
                    }
                    methodInProgress = null;
                    break;

                default:
                    state = MibcGroupParseState.LookingForOptionalData;
                    ilReader.Skip(opcode);
                    break;
                }

                if (processIntValue)
                {
                    switch (state)
                    {
                    case MibcGroupParseState.ProcessingExclusiveWeight:
                        exclusiveWeight = intValue;
                        state           = MibcGroupParseState.LookingForOptionalData;
                        break;

                    case MibcGroupParseState.ProcessingCallgraphCount:
                        weightedCallGraphSize = intValue;
                        weights = new Dictionary <MethodDesc, int>();
                        if (weightedCallGraphSize > 0)
                        {
                            state = MibcGroupParseState.ProcessingCallgraphToken;
                        }
                        else
                        {
                            state = MibcGroupParseState.LookingForOptionalData;
                        }
                        break;

                    case MibcGroupParseState.ProcessingCallgraphWeight:
                        if (metadataObject != metadataNotResolvable)
                        {
                            weights.Add((MethodDesc)metadataObject, intValue);
                        }
                        weightedCallGraphSize--;
                        if (weightedCallGraphSize > 0)
                        {
                            state = MibcGroupParseState.ProcessingCallgraphToken;
                        }
                        else
                        {
                            state = MibcGroupParseState.LookingForOptionalData;
                        }
                        break;

                    case MibcGroupParseState.ProcessingInstrumentationData:
                        instrumentationDataLongs.Add(intValue);
                        break;

                    default:
                        state = MibcGroupParseState.LookingForOptionalData;
                        instrumentationDataLongs = null;
                        break;
                    }
                }
            }
        }
Beispiel #13
0
        /// <summary>
        /// Parse an MIBC file for the methods that are interesting.
        /// The version bubble must be specified and will describe the restrict the set of methods parsed to those relevant to the compilation
        /// The onlyDefinedInAssembly parameter is used to restrict the set of types parsed to include only those which are defined in a specific module. Specify null to allow definitions from all modules.
        /// This limited parsing is not necessarily an exact set of prevention, so detailed algorithms that work at the individual method level are still necessary, but this allows avoiding excessive parsing.
        ///
        /// The format of the Mibc file is that of a .NET dll, with a global method named "AssemblyDictionary". Inside of that file are a series of references that are broken up by which assemblies define the individual methods.
        /// These references are encoded as IL code that represents the details.
        /// The format of these IL instruction is as follows.
        ///
        /// ldstr mibcGroupName
        /// ldtoken mibcGroupMethod
        /// pop
        /// {Repeat the above pattern N times, once per Mibc group}
        ///
        /// See comment above ReadMIbcGroup for details of the group format
        ///
        /// The mibcGroupName is in the following format "Assembly_{definingAssemblyName};{OtherAssemblyName};{OtherAssemblyName};...; (OtherAssemblyName is ; delimited)
        ///
        /// </summary>
        /// <returns></returns>
        public static ProfileData ParseMIbcFile(TypeSystemContext tsc, PEReader peReader, HashSet <string> assemblyNamesInVersionBubble, string onlyDefinedInAssembly)
        {
            var mibcModule = EcmaModule.Create(tsc, peReader, null, null, new CustomCanonResolver(tsc));

            var assemblyDictionary = (EcmaMethod)mibcModule.GetGlobalModuleType().GetMethod("AssemblyDictionary", null);
            IEnumerable <MethodProfileData> loadedMethodProfileData = Enumerable.Empty <MethodProfileData>();

            EcmaMethodIL ilBody   = EcmaMethodIL.Create(assemblyDictionary);
            ILReader     ilReader = new ILReader(ilBody.GetILBytes());

            string mibcGroupName = "";

            while (ilReader.HasNext)
            {
                ILOpcode opcode = ilReader.ReadILOpcode();
                switch (opcode)
                {
                case ILOpcode.ldstr:
                    int userStringToken = ilReader.ReadILToken();
                    Debug.Assert(mibcGroupName == "");
                    if (mibcGroupName == "")
                    {
                        mibcGroupName = (string)ilBody.GetObject(userStringToken);
                    }
                    break;

                case ILOpcode.ldtoken:
                    int token = ilReader.ReadILToken();

                    if (String.IsNullOrEmpty(mibcGroupName))
                    {
                        break;
                    }

                    string[] assembliesByName = mibcGroupName.Split(';');

                    bool hasMatchingDefinition = (onlyDefinedInAssembly == null) || assembliesByName[0].Equals(onlyDefinedInAssembly);

                    if (!hasMatchingDefinition)
                    {
                        break;
                    }

                    if (assemblyNamesInVersionBubble != null)
                    {
                        bool areAllEntriesInVersionBubble = true;
                        foreach (string s in assembliesByName)
                        {
                            if (string.IsNullOrEmpty(s))
                            {
                                continue;
                            }

                            if (!assemblyNamesInVersionBubble.Contains(s))
                            {
                                areAllEntriesInVersionBubble = false;
                                break;
                            }
                        }

                        if (!areAllEntriesInVersionBubble)
                        {
                            break;
                        }
                    }

                    loadedMethodProfileData = loadedMethodProfileData.Concat(ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject(token)));
                    break;

                case ILOpcode.pop:
                    mibcGroupName = "";
                    break;

                default:
                    ilReader.Skip(opcode);
                    break;
                }
            }

            return(new IBCProfileData(false, loadedMethodProfileData));
        }
Beispiel #14
0
        private bool IsNonVersionableWithILTokensThatDoNotNeedTranslationUncached(EcmaMethod method)
        {
            bool result = false;

            try
            {
                // Validate that there are no tokens in the IL other than tokens associated with the following
                // instructions with the
                // 1. ldfld, ldflda, and stfld to instance fields of NonVersionable structs and NonVersionable classes
                // 2. cpobj, initobj, ldobj, stobj, ldelem, ldelema or sizeof, to NonVersionable structures, signature variables, pointers, function pointers, byrefs, classes, or arrays
                // 3. stelem, to NonVersionable structures
                // In addition, the method must not have any EH.
                // The method may only have locals which are NonVersionable structures, or classes

                MethodIL methodIL = new ReadyToRunILProvider().GetMethodIL(method);
                if (methodIL.GetExceptionRegions().Length > 0)
                {
                    return(false);
                }

                foreach (var local in methodIL.GetLocals())
                {
                    if (local.Type.IsPrimitive)
                    {
                        continue;
                    }

                    if (local.Type.IsArray)
                    {
                        continue;
                    }

                    if (local.Type.IsSignatureVariable)
                    {
                        continue;
                    }
                    MetadataType metadataType = local.Type as MetadataType;

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

                    if (metadataType.IsValueType)
                    {
                        if (metadataType.IsNonVersionable())
                        {
                            continue;
                        }
                        else
                        {
                            return(false);
                        }
                    }
                }

                ILReader ilReader = new ILReader(methodIL.GetILBytes());
                while (ilReader.HasNext)
                {
                    ILOpcode opcode = ilReader.ReadILOpcode();
                    switch (opcode)
                    {
                    case ILOpcode.ldfld:
                    case ILOpcode.ldflda:
                    case ILOpcode.stfld:
                    {
                        int       token = ilReader.ReadILToken();
                        FieldDesc field = methodIL.GetObject(token) as FieldDesc;
                        if (field == null)
                        {
                            return(false);
                        }
                        if (field.IsStatic)
                        {
                            return(false);
                        }
                        MetadataType owningMetadataType = (MetadataType)field.OwningType;
                        if (!owningMetadataType.IsNonVersionable())
                        {
                            return(false);
                        }
                        break;
                    }

                    case ILOpcode.ldelem:
                    case ILOpcode.ldelema:
                    case ILOpcode.stobj:
                    case ILOpcode.ldobj:
                    case ILOpcode.initobj:
                    case ILOpcode.cpobj:
                    case ILOpcode.sizeof_:
                    {
                        int      token = ilReader.ReadILToken();
                        TypeDesc type  = methodIL.GetObject(token) as TypeDesc;
                        if (type == null)
                        {
                            return(false);
                        }

                        MetadataType metadataType = type as MetadataType;
                        if (metadataType == null)
                        {
                            continue;         // Types which are not metadata types are all well defined in size
                        }
                        if (!metadataType.IsValueType)
                        {
                            continue;         // Reference types are all well defined in size for the sizeof instruction
                        }
                        if (metadataType.IsNonVersionable())
                        {
                            continue;
                        }
                        return(false);
                    }

                    case ILOpcode.stelem:
                    {
                        int          token = ilReader.ReadILToken();
                        MetadataType type  = methodIL.GetObject(token) as MetadataType;
                        if (type == null)
                        {
                            return(false);
                        }

                        if (!type.IsValueType)
                        {
                            return(false);
                        }
                        if (!type.IsNonVersionable())
                        {
                            return(false);
                        }
                        break;
                    }

                    // IL instructions which refer to tokens which are not safe for NonVersionable methods
                    case ILOpcode.box:
                    case ILOpcode.call:
                    case ILOpcode.calli:
                    case ILOpcode.callvirt:
                    case ILOpcode.castclass:
                    case ILOpcode.jmp:
                    case ILOpcode.isinst:
                    case ILOpcode.ldstr:
                    case ILOpcode.ldsfld:
                    case ILOpcode.ldsflda:
                    case ILOpcode.ldtoken:
                    case ILOpcode.ldvirtftn:
                    case ILOpcode.ldftn:
                    case ILOpcode.mkrefany:
                    case ILOpcode.newarr:
                    case ILOpcode.newobj:
                    case ILOpcode.refanyval:
                    case ILOpcode.stsfld:
                    case ILOpcode.unbox:
                    case ILOpcode.unbox_any:
                    case ILOpcode.constrained:
                        return(false);

                    default:
                        // Unless its a opcode known to be permitted with a
                        ilReader.Skip(opcode);
                        break;
                    }
                }

                result = true;
            }
            catch (TypeSystemException)
            {
                return(false);
            }

            return(result);
        }
Beispiel #15
0
        public static ProfileData ParseMIbcFile(TypeSystemContext tsc, PEReader peReader, HashSet <string> assemblyNamesInVersionBubble, string onlyDefinedInAssembly, MibcGroupParseRules parseRule = MibcGroupParseRules.VersionBubble, HashSet <string> crossModuleInlineModules = null)
        {
            if (parseRule == MibcGroupParseRules.VersionBubble)
            {
                crossModuleInlineModules = s_EmptyHash;
            }

            if (parseRule == MibcGroupParseRules.AllGroups)
            {
                assemblyNamesInVersionBubble = null;
            }

            if (crossModuleInlineModules == null)
            {
                crossModuleInlineModules = s_EmptyHash;
            }

            var mibcModule = EcmaModule.Create(tsc, peReader, null, null, new CustomCanonResolver(tsc));

            var assemblyDictionary = (EcmaMethod)mibcModule.GetGlobalModuleType().GetMethod("AssemblyDictionary", null);
            IEnumerable <MethodProfileData> loadedMethodProfileData = Enumerable.Empty <MethodProfileData>();

            EcmaMethodIL ilBody   = EcmaMethodIL.Create(assemblyDictionary);
            ILReader     ilReader = new ILReader(ilBody.GetILBytes());

            string mibcGroupName = "";

            while (ilReader.HasNext)
            {
                ILOpcode opcode = ilReader.ReadILOpcode();
                switch (opcode)
                {
                case ILOpcode.ldstr:
                    int userStringToken = ilReader.ReadILToken();
                    Debug.Assert(mibcGroupName == "");
                    if (mibcGroupName == "")
                    {
                        mibcGroupName = (string)ilBody.GetObject(userStringToken);
                    }
                    break;

                case ILOpcode.ldtoken:
                    int token = ilReader.ReadILToken();

                    if (String.IsNullOrEmpty(mibcGroupName))
                    {
                        break;
                    }

                    string[] assembliesByName = mibcGroupName.Split(';');

                    bool hasMatchingDefinition = (onlyDefinedInAssembly == null) || assembliesByName[0].Equals(onlyDefinedInAssembly);

                    if (!hasMatchingDefinition)
                    {
                        break;
                    }

                    if (assemblyNamesInVersionBubble != null)
                    {
                        bool mibcGroupUseable         = true;
                        bool someEntryInVersionBubble = false;
                        foreach (string s in assembliesByName)
                        {
                            if (string.IsNullOrEmpty(s))
                            {
                                continue;
                            }

                            bool entryInVersionBubble = assemblyNamesInVersionBubble.Contains(s);
                            someEntryInVersionBubble = someEntryInVersionBubble || entryInVersionBubble;

                            if (!entryInVersionBubble && !crossModuleInlineModules.Contains(s))
                            {
                                // If the group references a module that isn't in the version bubble and isn't cross module inlineable, its not useful.
                                mibcGroupUseable = false;
                                break;
                            }
                        }

                        if (!someEntryInVersionBubble && (parseRule == MibcGroupParseRules.VersionBubbleWithCrossModule1))
                        {
                            mibcGroupUseable = false;
                        }

                        if (!mibcGroupUseable)
                        {
                            break;
                        }
                    }

                    loadedMethodProfileData = loadedMethodProfileData.Concat(ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject(token)));
                    break;

                case ILOpcode.pop:
                    mibcGroupName = "";
                    break;

                default:
                    ilReader.Skip(opcode);
                    break;
                }
            }

            return(new IBCProfileData(ParseMibcConfig(tsc, peReader), false, loadedMethodProfileData));
        }