Beispiel #1
0
        static IEnumerable <MIbcData> ReadMIbcGroup(TypeSystemContext tsc, EcmaMethod method)
        {
            EcmaMethodIL ilBody = EcmaMethodIL.Create((EcmaMethod)method);

            byte[] ilBytes        = ilBody.GetILBytes();
            int    currentOffset  = 0;
            object metadataObject = null;

            while (currentOffset < ilBytes.Length)
            {
                ILOpcode opcode = (ILOpcode)ilBytes[currentOffset];
                if (opcode == ILOpcode.prefix1)
                {
                    opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1];
                }
                switch (opcode)
                {
                case ILOpcode.ldtoken:
                    UInt32 token = (UInt32)(ilBytes[currentOffset + 1] + (ilBytes[currentOffset + 2] << 8) + (ilBytes[currentOffset + 3] << 16) + (ilBytes[currentOffset + 4] << 24));
                    metadataObject = ilBody.GetObject((int)token);
                    break;

                case ILOpcode.pop:
                    MIbcData mibcData = new MIbcData();
                    mibcData.MetadataObject = metadataObject;
                    yield return(mibcData);

                    break;
                }

                // This isn't correct if there is a switch opcode, but since we won't do that, its ok
                currentOffset += opcode.GetSize();
            }
        }
Beispiel #2
0
        private void VerifyModule(EcmaModule module)
        {
            foreach (var methodHandle in module.MetadataReader.MethodDefinitions)
            {
                var method = (EcmaMethod)module.GetMethod(methodHandle);

                var methodIL = EcmaMethodIL.Create(method);
                if (methodIL == null)
                {
                    continue;
                }

                var methodName = method.ToString();
                if (_includePatterns.Count > 0 && !_includePatterns.Any(p => p.IsMatch(methodName)))
                {
                    continue;
                }
                if (_excludePatterns.Any(p => p.IsMatch(methodName)))
                {
                    continue;
                }

                VerifyMethod(method, methodIL);
            }
        }
Beispiel #3
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 #4
0
        private ILImporter ConstructILImporter(TestCase testCase)
        {
            var module   = TestDataLoader.GetModuleForTestAssembly(testCase.ModuleName);
            var method   = (EcmaMethod)module.GetMethod(MetadataTokens.EntityHandle(testCase.MetadataToken));
            var methodIL = EcmaMethodIL.Create(method);

            return(new ILImporter(method, methodIL));
        }
Beispiel #5
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 #6
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
        /// pop
        /// {Repeat N times for N methods described}
        ///
        /// 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);

            byte[] ilBytes             = ilBody.GetILBytes();
            int    currentOffset       = 0;
            object metadataObject      = null;
            object methodNotResolvable = new object();

            while (currentOffset < ilBytes.Length)
            {
                ILOpcode opcode = (ILOpcode)ilBytes[currentOffset];
                if (opcode == ILOpcode.prefix1)
                {
                    opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1];
                }
                switch (opcode)
                {
                case ILOpcode.ldtoken:
                    if (metadataObject == null)
                    {
                        uint token = (uint)(ilBytes[currentOffset + 1] + (ilBytes[currentOffset + 2] << 8) + (ilBytes[currentOffset + 3] << 16) + (ilBytes[currentOffset + 4] << 24));
                        try
                        {
                            metadataObject = ilBody.GetObject((int)token);
                        }
                        catch (TypeSystemException)
                        {
                            // The method being referred to may be missing. In that situation,
                            // use the methodNotResolvable sentinel to indicate that this record should be ignored
                            metadataObject = methodNotResolvable;
                        }
                    }
                    break;

                case ILOpcode.pop:
                    if (metadataObject != methodNotResolvable)
                    {
                        MethodProfileData mibcData = new MethodProfileData((MethodDesc)metadataObject, MethodProfilingDataFlags.ReadMethodCode, 0xFFFFFFFF);
                        yield return(mibcData);
                    }
                    metadataObject = null;
                    break;
                }

                // This isn't correct if there is a switch opcode, but since we won't do that, its ok
                currentOffset += opcode.GetSize();
            }
        }
Beispiel #7
0
        private IEnumerable <VerificationResult> VerifyMethods(EcmaModule module, IEnumerable <MethodDefinitionHandle> methodHandles)
        {
            foreach (var methodHandle in methodHandles)
            {
                var method   = (EcmaMethod)module.GetMethod(methodHandle);
                var methodIL = EcmaMethodIL.Create(method);

                if (methodIL != null)
                {
                    var results = VerifyMethod(module, methodIL, methodHandle);
                    foreach (var result in results)
                    {
                        yield return(result);
                    }
                }
            }
        }
Beispiel #8
0
        public void TestGenericNameFormatting()
        {
            MetadataType testClass  = _testModule.GetType("ILDisassembler", "TestGenericClass`1");
            EcmaMethod   testMethod = (EcmaMethod)testClass.GetMethod("TestMethod", null);
            EcmaMethodIL methodIL   = EcmaMethodIL.Create(testMethod);

            Dictionary <int, string> interestingLines = new Dictionary <int, string>
            {
                { 4, "IL_0003:  ldstr       \"Hello \\\"World\\\"!\\n\"" },
                { 9, "IL_000D:  call        instance void class ILDisassembler.TestGenericClass`1<!TClassParam>::VoidGenericMethod<string, valuetype ILDisassembler.TestStruct>(!!0, int32, native int, class ILDisassembler.TestClass&)" },
                { 14, "IL_0017:  initobj     !TClassParam" },
                { 16, "IL_001E:  call        !!0 class ILDisassembler.TestGenericClass`1<!TClassParam>::MethodParamGenericMethod<class ILDisassembler.TestClass>(class ILDisassembler.TestGenericClass`1<!!0>, class ILDisassembler.TestGenericClass`1/Nested<!0>, valuetype ILDisassembler.TestStruct*[], !0)" },
                { 24, "IL_0030:  call        !!0 class ILDisassembler.TestGenericClass`1<!TClassParam>::MethodParamGenericMethod<!0>(class ILDisassembler.TestGenericClass`1<!!0>, class ILDisassembler.TestGenericClass`1/Nested<!0>, valuetype ILDisassembler.TestStruct*[], !0)" },
                { 26, "IL_0036:  ldtoken     !TClassParam" },
                { 28, "IL_003C:  ldtoken     valuetype [CoreTestAssembly]System.Nullable`1<int32>" },
                { 31, "IL_0043:  ldc.r8      3.14" },
                { 32, "IL_004C:  ldc.r4      1.68" },
                { 34, "IL_0053:  call        instance valuetype ILDisassembler.TestStruct class ILDisassembler.TestGenericClass`1<!TClassParam>::NonGenericMethod(float64, float32, int16)" },
                { 37, "IL_005A:  ldflda      !0 class ILDisassembler.TestGenericClass`1<!TClassParam>::somefield" },
                { 41, "IL_0067:  stfld       class ILDisassembler.TestClass class ILDisassembler.TestGenericClass`1<!TClassParam>::otherfield" },
                { 44, "IL_006E:  stfld       class ILDisassembler.TestGenericClass`1<class ILDisassembler.TestGenericClass`1<class ILDisassembler.TestClass>> class ILDisassembler.TestGenericClass`1<!TClassParam>::genericfield" },
                { 47, "IL_0075:  stfld       !0[] class ILDisassembler.TestGenericClass`1<!TClassParam>::arrayfield" },
                { 48, "IL_007A:  call        void ILDisassembler.TestClass::NonGenericMethod()" },
                { 49, "IL_007F:  ldsflda     valuetype ILDisassembler.TestStruct ILDisassembler.TestClass::somefield" },
                { 50, "IL_0084:  initobj     ILDisassembler.TestStruct" }
            };

            ILDisassembler disasm = new ILDisassembler(methodIL);

            int numLines = 1;

            while (disasm.HasNextInstruction)
            {
                string line = disasm.GetNextInstruction();
                string expectedLine;
                if (interestingLines.TryGetValue(numLines, out expectedLine))
                {
                    Assert.Equal(expectedLine, line);
                }
                numLines++;
            }

            Assert.Equal(52, numLines);
        }
Beispiel #9
0
        static IEnumerable <MIbcData> ReadMIbcData(TraceTypeSystemContext tsc, FileInfo outputFileName, byte[] moduleBytes)
        {
            var peReader = new System.Reflection.PortableExecutable.PEReader(System.Collections.Immutable.ImmutableArray.Create <byte>(moduleBytes));
            var module   = EcmaModule.Create(tsc, peReader, null, null, new CustomCanonResolver(tsc));

            var          loadedMethod = (EcmaMethod)module.GetGlobalModuleType().GetMethod("AssemblyDictionary", null);
            EcmaMethodIL ilBody       = EcmaMethodIL.Create(loadedMethod);

            byte[] ilBytes       = ilBody.GetILBytes();
            int    currentOffset = 0;

            while (currentOffset < ilBytes.Length)
            {
                ILOpcode opcode = (ILOpcode)ilBytes[currentOffset];
                if (opcode == ILOpcode.prefix1)
                {
                    opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1];
                }
                switch (opcode)
                {
                case ILOpcode.ldtoken:
                    UInt32 token = (UInt32)(ilBytes[currentOffset + 1] + (ilBytes[currentOffset + 2] << 8) + (ilBytes[currentOffset + 3] << 16) + (ilBytes[currentOffset + 4] << 24));
                    foreach (var data in ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject((int)token)))
                    {
                        yield return(data);
                    }
                    break;

                case ILOpcode.pop:
                    break;
                }

                // This isn't correct if there is a switch opcode, but since we won't do that, its ok
                currentOffset += opcode.GetSize();
            }
            GC.KeepAlive(peReader);
        }
Beispiel #10
0
        private PerMethodInfo GetOrCreateInfo(MethodDesc md)
        {
            if (!_methodInf.TryGetValue(md, out PerMethodInfo pmi))
            {
                MethodIL il =
                    md switch
                {
                    EcmaMethod em => EcmaMethodIL.Create(em),
                    _ => new InstantiatedMethodIL(md, EcmaMethodIL.Create((EcmaMethod)md.GetTypicalMethodDefinition())),
                };

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

                _methodInf.Add(md, pmi = new PerMethodInfo());
                pmi.IL        = il;
                pmi.FlowGraph = FlowGraph.Create(il);
                pmi.Profile   = new SampleProfile(pmi.IL, pmi.FlowGraph);
            }

            return(pmi);
        }
        /// <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);

            byte[] ilBytes       = ilBody.GetILBytes();
            int    currentOffset = 0;

            string mibcGroupName = "";

            while (currentOffset < ilBytes.Length)
            {
                ILOpcode opcode = (ILOpcode)ilBytes[currentOffset];
                if (opcode == ILOpcode.prefix1)
                {
                    opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1];
                }
                switch (opcode)
                {
                case ILOpcode.ldstr:
                    Debug.Assert(mibcGroupName == "");
                    if (mibcGroupName == "")
                    {
                        UInt32 userStringToken = BinaryPrimitives.ReadUInt32LittleEndian(ilBytes.AsSpan(currentOffset + 1));
                        mibcGroupName = (string)ilBody.GetObject((int)userStringToken);
                    }
                    break;

                case ILOpcode.ldtoken:
                    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;
                        }
                    }

                    uint token = BinaryPrimitives.ReadUInt32LittleEndian(ilBytes.AsSpan(currentOffset + 1));
                    loadedMethodProfileData = loadedMethodProfileData.Concat(ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject((int)token)));
                    break;

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

                // This isn't correct if there is a switch opcode, but since we won't do that, its ok
                currentOffset += opcode.GetSize();
            }

            return(new IBCProfileData(false, loadedMethodProfileData));
        }
        /// <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(CompilerTypeSystemContext tsc, string filename, HashSet <string> assemblyNamesInVersionBubble, string onlyDefinedInAssembly)
        {
            byte[] peData;

            using (var zipFile = ZipFile.OpenRead(filename))
            {
                var mibcDataEntry = zipFile.GetEntry(Path.GetFileName(filename) + ".dll");
                using (var mibcDataStream = mibcDataEntry.Open())
                {
                    peData = new byte[mibcDataEntry.Length];
                    using (BinaryReader br = new BinaryReader(mibcDataStream))
                    {
                        peData = br.ReadBytes(checked ((int)mibcDataEntry.Length));
                    }
                }
            }

            using (var peReader = new System.Reflection.PortableExecutable.PEReader(System.Collections.Immutable.ImmutableArray.Create <byte>(peData)))
            {
                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);
                byte[]       ilBytes       = ilBody.GetILBytes();
                int          currentOffset = 0;

                string mibcGroupName = "";
                while (currentOffset < ilBytes.Length)
                {
                    ILOpcode opcode = (ILOpcode)ilBytes[currentOffset];
                    if (opcode == ILOpcode.prefix1)
                    {
                        opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1];
                    }
                    switch (opcode)
                    {
                    case ILOpcode.ldstr:
                        if (mibcGroupName == "")
                        {
                            UInt32 userStringToken = (UInt32)(ilBytes[currentOffset + 1] + (ilBytes[currentOffset + 2] << 8) + (ilBytes[currentOffset + 3] << 16) + (ilBytes[currentOffset + 4] << 24));
                            mibcGroupName = (string)ilBody.GetObject((int)userStringToken);
                        }
                        break;

                    case ILOpcode.ldtoken:
                        if (String.IsNullOrEmpty(mibcGroupName))
                        {
                            break;
                        }

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

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

                        if (!hasMatchingDefinition)
                        {
                            break;
                        }

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

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

                        if (!areAllEntriesInVersionBubble)
                        {
                            break;
                        }

                        uint token = (uint)(ilBytes[currentOffset + 1] + (ilBytes[currentOffset + 2] << 8) + (ilBytes[currentOffset + 3] << 16) + (ilBytes[currentOffset + 4] << 24));
                        loadedMethodProfileData = loadedMethodProfileData.Concat(ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject((int)token)));
                        break;

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

                    // This isn't correct if there is a switch opcode, but since we won't do that, its ok
                    currentOffset += opcode.GetSize();
                }

                return(new IBCProfileData(false, loadedMethodProfileData));
            }
        }
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(CompilerTypeSystemContext tsc, string filename, HashSet <string> assemblyNamesInVersionBubble, string onlyDefinedInAssembly)
        {
            byte[]   peData = null;
            PEReader unprotectedPeReader = null;

            {
                FileStream fsMibcFile         = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 0x1000, useAsync: false);
                bool       disposeOnException = true;

                try
                {
                    byte firstByte  = (byte)fsMibcFile.ReadByte();
                    byte secondByte = (byte)fsMibcFile.ReadByte();
                    fsMibcFile.Seek(0, SeekOrigin.Begin);
                    if (firstByte == 0x4d && secondByte == 0x5a)
                    {
                        // Uncompressed Mibc format, starts with 'MZ' prefix like all other PE files
                        unprotectedPeReader = new PEReader(fsMibcFile, PEStreamOptions.Default);
                        disposeOnException  = false;
                    }
                    else
                    {
                        using (var zipFile = new ZipArchive(fsMibcFile, ZipArchiveMode.Read, leaveOpen: false, entryNameEncoding: null))
                        {
                            disposeOnException = false;
                            var mibcDataEntry = zipFile.GetEntry(Path.GetFileName(filename) + ".dll");
                            using (var mibcDataStream = mibcDataEntry.Open())
                            {
                                peData = new byte[mibcDataEntry.Length];
                                using (BinaryReader br = new BinaryReader(mibcDataStream))
                                {
                                    peData = br.ReadBytes(checked ((int)mibcDataEntry.Length));
                                }
                            }
                        }
                    }
                }
                finally
                {
                    if (disposeOnException)
                    {
                        fsMibcFile.Dispose();
                    }
                }
            }

            if (peData != null)
            {
                unprotectedPeReader = new PEReader(System.Collections.Immutable.ImmutableArray.Create <byte>(peData));
            }

            using (var peReader = unprotectedPeReader)
            {
                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);
                byte[]       ilBytes       = ilBody.GetILBytes();
                int          currentOffset = 0;

                string mibcGroupName = "";
                while (currentOffset < ilBytes.Length)
                {
                    ILOpcode opcode = (ILOpcode)ilBytes[currentOffset];
                    if (opcode == ILOpcode.prefix1)
                    {
                        opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1];
                    }
                    switch (opcode)
                    {
                    case ILOpcode.ldstr:
                        if (mibcGroupName == "")
                        {
                            UInt32 userStringToken = BinaryPrimitives.ReadUInt32LittleEndian(ilBytes.AsSpan(currentOffset + 1));
                            mibcGroupName = (string)ilBody.GetObject((int)userStringToken);
                        }
                        break;

                    case ILOpcode.ldtoken:
                        if (String.IsNullOrEmpty(mibcGroupName))
                        {
                            break;
                        }

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

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

                        if (!hasMatchingDefinition)
                        {
                            break;
                        }

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

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

                        if (!areAllEntriesInVersionBubble)
                        {
                            break;
                        }

                        uint token = BinaryPrimitives.ReadUInt32LittleEndian(ilBytes.AsSpan(currentOffset + 1));
                        loadedMethodProfileData = loadedMethodProfileData.Concat(ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject((int)token)));
                        break;

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

                    // This isn't correct if there is a switch opcode, but since we won't do that, its ok
                    currentOffset += opcode.GetSize();
                }

                return(new IBCProfileData(false, loadedMethodProfileData));
            }
        }
Beispiel #14
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 #15
0
 public InterpreterCallInterceptor(TypeSystemContext context, MethodDesc method) : base(false)
 {
     _context  = context;
     _method   = method;
     _methodIL = EcmaMethodIL.Create(method as EcmaMethod);
 }
Beispiel #16
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 #17
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;
                    }
                }
            }
        /// <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);

            byte[] ilBytes                       = ilBody.GetILBytes();
            int    currentOffset                 = 0;
            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 (currentOffset < ilBytes.Length)
            {
                ILOpcode opcode = (ILOpcode)ilBytes[currentOffset];
                if (opcode == ILOpcode.prefix1)
                {
                    opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1];
                }
                processIntValue = false;
                switch (opcode)
                {
                case ILOpcode.ldtoken:
                {
                    uint token = BitConverter.ToUInt32(ilBytes.AsSpan(currentOffset + 1, 4));
                    if (state == MibcGroupParseState.ProcessingInstrumentationData)
                    {
                        instrumentationDataLongs.Add(token);
                    }
                    else
                    {
                        metadataObject = null;
                        try
                        {
                            metadataObject = ilBody.GetObject((int)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 = BitConverter.ToSingle(ilBytes.AsSpan(currentOffset + 1, 4));

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

                    default:
                        state = MibcGroupParseState.LookingForOptionalData;
                        break;
                    }

                    break;
                }

                case ILOpcode.ldc_r8:
                {
                    double dblValue = BitConverter.ToDouble(ilBytes.AsSpan(currentOffset + 1, 8));

                    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)ilBytes[currentOffset + 1];
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4:
                    intValue        = BitConverter.ToInt32(ilBytes.AsSpan(currentOffset + 1, 4));
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i8:
                    if (state == MibcGroupParseState.ProcessingInstrumentationData)
                    {
                        instrumentationDataLongs.Add(BitConverter.ToInt64(ilBytes.AsSpan(currentOffset + 1, 8)));
                    }
                    break;

                case ILOpcode.ldstr:
                {
                    UInt32 userStringToken  = BitConverter.ToUInt32(ilBytes.AsSpan(currentOffset + 1, 4));
                    string optionalDataName = (string)ilBody.GetObject((int)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;
                    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;
                    }
                }

                // This isn't correct if there is a switch opcode, but since we won't do that, its ok
                currentOffset += opcode.GetSize();
            }
        }
 public MetadataLoaderForPgoData(EcmaMethodIL ilBody)
 {
     _ilBody = ilBody;
 }
Beispiel #20
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));
        }