예제 #1
0
        public ProfileData ParseIBCDataFromModule(EcmaModule ecmaModule)
        {
            ResourceData peResources = new ResourceData(ecmaModule);

            byte[] ibcDataSection = peResources.FindResource("PROFILE_DATA", "IBC", 0);
            if (ibcDataSection == null)
            {
                // If we don't have profile data, return empty ProfileData object
                return(EmptyProfileData.Singleton);
            }

            var          reader          = new IBCDataReader();
            int          pos             = 0;
            bool         basicBlocksOnly = false;
            AssemblyData parsedData      = reader.Read(ibcDataSection, ref pos, out bool minified);

            if (parsedData.FormatMajorVersion == 1)
            {
                throw new Exception("Unsupported V1 IBC Format");
            }

            Dictionary <IBCBlobKey, BlobEntry> blobs = GetIBCBlobs(parsedData.BlobStream, out HashSet <uint> ignoredIbcMethodSpecTokens);

            List <MethodProfileData> methodProfileData = new List <MethodProfileData>();

            IBCModule ibcModule = new IBCModule(ecmaModule, blobs);

            // Parse the token lists
            IBCData.SectionIteratorKind iteratorKind = basicBlocksOnly ? IBCData.SectionIteratorKind.BasicBlocks : IBCData.SectionIteratorKind.TokenFlags;
            foreach (SectionFormat section in IBCData.SectionIterator(iteratorKind))
            {
                if (!parsedData.Tokens.TryGetValue(section, out List <TokenData> TokenList) ||
                    TokenList.Count == 0)
                {
                    continue;
                }

                // In V1 and minified V3+ files, tokens aren't stored with a
                // scenario mask. In minified V3+ files, it can be treated as
                // anything nonzero--minified files make no guarantee about
                // preserving scenario information, but the flags must be left
                // alone.

                const uint           scenarioMaskIfMissing = 1u;
                HashSet <MethodDesc> methodsFoundInData    = new HashSet <MethodDesc>();

                foreach (TokenData entry in TokenList)
                {
                    //
                    // Discard any token list entries which refer to the ParamMethodSpec blob stream entries
                    // (if any) which were thrown away above.  Note that the MethodProfilingData token list is
                    // the only place anywhere in the IBC data which can ever contain an embedded ibcMethodSpec
                    // token.
                    //

                    if (section == SectionFormat.MethodProfilingData)
                    {
                        if (ignoredIbcMethodSpecTokens.Contains(entry.Token))
                        {
                            continue;
                        }
                    }

                    uint scenarioMask = entry.ScenarioMask ?? scenarioMaskIfMissing;

                    // scenarioMask will be 0 in unprocessed or V1 IBC data.
                    if (scenarioMask == 0)
                    {
                        // TODO Compute RunOnce and RunNever from basic block data
                        scenarioMask = scenarioMaskIfMissing;

                        /*                        Debug.Assert(fullScenarioMask == 1, "Token entry not owned by one scenario");
                         *                      // We have to compute the RunOnceMethod and RunNeverMethod flags.
                         *                      entry.Flags = result.GetFlags(entry.Flags, section, entry.Token);
                         *                      scenarioMask = defaultScenarioMask;*/
                    }

                    //                    Debug.Assert(((~fullScenarioMask & scenarioMask) == 0), "Illegal scenarios mask");

                    MethodDesc associatedMethod = null;

                    switch (Cor.Macros.TypeFromToken(entry.Token))
                    {
                    case CorTokenType.mdtMethodDef:
                    case CorTokenType.mdtMemberRef:
                    case CorTokenType.mdtMethodSpec:
                        object metadataObject = ecmaModule.GetObject(System.Reflection.Metadata.Ecma335.MetadataTokens.EntityHandle((int)entry.Token));
                        if (metadataObject is MethodDesc)
                        {
                            associatedMethod = (MethodDesc)metadataObject;
                        }
                        else
                        {
                            if (_logger.IsVerbose)
                            {
                                _logger.Writer.WriteLine($"Token {(int)entry.Token:x} does not refer to a method");
                            }
                        }
                        break;

                    case CorTokenType.ibcMethodSpec:
                    {
                        if (!blobs.TryGetValue(new IBCBlobKey(entry.Token, BlobType.ParamMethodSpec), out BlobEntry blobEntry))
                        {
                            throw new Exception($"Missing blob entry for ibcMethodSpec {entry.Token:x}");
                        }
                        BlobEntry.SignatureEntry paramSignatureEntry = blobEntry as BlobEntry.SignatureEntry;
                        if (paramSignatureEntry == null)
                        {
                            throw new Exception($"Blob entry for {entry.Token:x} is invalid");
                        }
                        unsafe
                        {
                            fixed(byte *pb = &paramSignatureEntry.Signature[0])
                            {
                                BlobReader br = new BlobReader(pb, paramSignatureEntry.Signature.Length);

                                associatedMethod = GetSigMethodInstantiationFromIBCMethodSpec(ibcModule, br);
                            }
                        }
                    }
                    break;
                    }

                    if (associatedMethod != null)
                    {
                        if (methodsFoundInData.Add(associatedMethod))
                        {
                            methodProfileData.Add(new MethodProfileData(associatedMethod, (MethodProfilingDataFlags)entry.Flags, 0, null, scenarioMask, null));
                        }
                        else
                        {
                            if (_logger.IsVerbose)
                            {
                                _logger.Writer.WriteLine($"Multiple copies of data for method '{associatedMethod}' found.");
                            }
                        }
                    }
                }
            }

            return(new IBCProfileData(parsedData.PartialNGen, methodProfileData));
        }