Ejemplo n.º 1
0
        private MetadataType LoadTypeFromIBCZapSig(IBCModule ibcModule, EcmaModule ecmaModule, CorElementType typ, ref BlobReader sig)
        {
            switch (typ)
            {
            case CorElementType.ELEMENT_TYPE_CLASS:
            case CorElementType.ELEMENT_TYPE_VALUETYPE:
                uint token = (uint)ibcModule.EcmaModule.MetadataReader.GetToken(sig.ReadTypeHandle());
                if (ecmaModule != ibcModule.EcmaModule)
                {
                    // ibcExternalType tokens are actually encoded as mdtTypeDef tokens in the signature
                    uint rid      = Cor.Macros.RidFromToken(token);
                    uint ibcToken = Cor.Macros.TokenFromRid(rid, CorTokenType.ibcExternalType);
                    token = LookupIbcTypeToken(ref ecmaModule, ibcToken, ibcModule.Blobs);
                }
                switch (Cor.Macros.TypeFromToken(token))
                {
                case CorTokenType.mdtTypeDef:
                case CorTokenType.mdtTypeRef:
                    // success
                    break;

                default:
                    throw new Exception("Invalid token found while parsing IBC ZapSig generic instantiation");
                }
                if (Cor.Macros.IsNilToken(token))
                {
                    return(null);
                }

                var result = (MetadataType)ecmaModule.GetType(MetadataTokens.EntityHandle((int)token));
                if ((typ == CorElementType.ELEMENT_TYPE_VALUETYPE) != result.IsValueType)
                {
                    if (_logger.IsVerbose)
                    {
                        _logger.Writer.WriteLine("Mismatch between valuetype and reference type in while parsing generic instantiation");
                    }
                    return(null);
                }
                return(result);

            default:
                if (_logger.IsVerbose)
                {
                    _logger.Writer.WriteLine("Unexpected token type parsing ELEMENT_TYPE_GENERICINST");
                }
                return(null);
            }
        }
Ejemplo n.º 2
0
        private MethodDesc GetSigMethodInstantiationFromIBCMethodSpec(IBCModule ibcModule, BlobReader sig)
        {
            TypeDesc methodType = GetSigTypeFromIBCZapSig(ibcModule, ibcModule.EcmaModule, sig);

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

            SkipTypeInIBCZapSig(ref sig);
            uint flags = (uint)sig.ReadCompressedInteger();

            if (Macros.IsSlotUsedInsteadOfToken(flags))
            {
                int slot = sig.ReadCompressedInteger();
                if (_logger.IsVerbose)
                {
                    _logger.Writer.WriteLine($"Warning: IBC Data for `{methodType}` with slot '{slot}' was ignored");
                }
                return(null); // Unsupported case thought to be used only for array methods, which don't really matter for R2R codegen
            }
            else
            {
                // Decode method token

                uint         methodRid = (uint)sig.ReadCompressedInteger();
                uint         methodToken;
                MetadataType methodMetadataType = (MetadataType)methodType;
                if (ibcModule.EcmaModule == methodMetadataType.Module)
                {
                    methodToken = Cor.Macros.TokenFromRid(methodRid, CorTokenType.mdtMethodDef);
                }
                else
                {
                    uint ibcToken = Cor.Macros.TokenFromRid(methodRid, CorTokenType.ibcExternalMethod);
                    methodToken = LookupIbcMethodToken(methodMetadataType, ibcToken, ibcModule.Blobs);
                    if (Cor.Macros.RidFromToken(methodToken) == 0)
                    {
                        if (_logger.IsVerbose)
                        {
                            _logger.Writer.WriteLine($"Warning: External Method Token {ibcToken:x} on '{methodMetadataType}' could not be found.");
                        }
                        return(null);
                    }
                }

                EcmaModule ecmaModuleOfMethod = ((EcmaType)methodMetadataType.GetTypeDefinition()).EcmaModule;
                MethodDesc ecmaMethod         = ecmaModuleOfMethod.GetMethod(MetadataTokens.EntityHandle((int)methodToken));
                MethodDesc methodOnType       = methodType.FindMethodOnTypeWithMatchingTypicalMethod(ecmaMethod);

                MethodDesc methodFound = methodOnType;
                if (Macros.IsInstantiationNeeded(flags))
                {
                    int instantiationArgumentCount = methodOnType.Instantiation.Length;
                    Debug.Assert(instantiationArgumentCount > 0);
                    List <TypeDesc> instantiationArguments = new List <TypeDesc>();
                    for (int i = 0; i < instantiationArgumentCount; i++)
                    {
                        TypeDesc instantiationType = GetSigTypeFromIBCZapSig(ibcModule, ibcModule.EcmaModule, sig);
                        if (instantiationType == null)
                        {
                            return(null);
                        }

                        instantiationArguments.Add(instantiationType);
                        SkipTypeInIBCZapSig(ref sig);
                    }

                    methodFound = methodOnType.MakeInstantiatedMethod(new Instantiation(instantiationArguments.ToArray()));
                }

                if (Macros.IsUnboxingStub(flags))
                {
                    if (_logger.IsVerbose)
                    {
                        _logger.Writer.WriteLine($"Warning: Skipping IBC data for unboxing stub {methodFound}");
                    }
                    return(null);
                }

                if (Macros.IsInstantiatingStub(flags))
                {
                    if (_logger.IsVerbose)
                    {
                        _logger.Writer.WriteLine($"Warning: Skipping IBC data for instantiating stub {methodFound}");
                    }
                    return(null);
                }

                return(methodFound);
            }
        }
Ejemplo n.º 3
0
        // Load type from IBC ZapSig. Returns null for cases where the type is legally defined, but is not used in R2R image generation
        private TypeDesc GetSigTypeFromIBCZapSig(IBCModule ibcModule, EcmaModule ecmaModule, BlobReader sig)
        {
            TypeSystemContext context = ibcModule.EcmaModule.Context;

            CorElementType typ = (CorElementType)sig.ReadByte();

            switch (typ)
            {
            case CorElementType.ELEMENT_TYPE_VOID:
                return(context.GetWellKnownType(WellKnownType.Void));

            case CorElementType.ELEMENT_TYPE_BOOLEAN:
                return(context.GetWellKnownType(WellKnownType.Boolean));

            case CorElementType.ELEMENT_TYPE_CHAR:
                return(context.GetWellKnownType(WellKnownType.Char));

            case CorElementType.ELEMENT_TYPE_I:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case CorElementType.ELEMENT_TYPE_U:
                return(context.GetWellKnownType(WellKnownType.UIntPtr));

            case CorElementType.ELEMENT_TYPE_I1:
                return(context.GetWellKnownType(WellKnownType.SByte));

            case CorElementType.ELEMENT_TYPE_U1:
                return(context.GetWellKnownType(WellKnownType.Byte));

            case CorElementType.ELEMENT_TYPE_I2:
                return(context.GetWellKnownType(WellKnownType.Int16));

            case CorElementType.ELEMENT_TYPE_U2:
                return(context.GetWellKnownType(WellKnownType.UInt16));

            case CorElementType.ELEMENT_TYPE_I4:
                return(context.GetWellKnownType(WellKnownType.Int32));

            case CorElementType.ELEMENT_TYPE_U4:
                return(context.GetWellKnownType(WellKnownType.UInt32));

            case CorElementType.ELEMENT_TYPE_I8:
                return(context.GetWellKnownType(WellKnownType.Int64));

            case CorElementType.ELEMENT_TYPE_U8:
                return(context.GetWellKnownType(WellKnownType.UInt64));

            case CorElementType.ELEMENT_TYPE_R4:
                return(context.GetWellKnownType(WellKnownType.Single));

            case CorElementType.ELEMENT_TYPE_R8:
                return(context.GetWellKnownType(WellKnownType.Double));

            case CorElementType.ELEMENT_TYPE_STRING:
                return(context.GetWellKnownType(WellKnownType.String));

            case CorElementType.ELEMENT_TYPE_OBJECT:
                return(context.GetWellKnownType(WellKnownType.Object));

            case CorElementType.ELEMENT_TYPE_TYPEDBYREF:
                return(context.GetWellKnownType(WellKnownType.TypedReference));

            case CorElementType.ELEMENT_TYPE_CANON_ZAPSIG:
                if (!context.SupportsCanon)
                {
                    return(null);
                }
                return(context.CanonType);

            case CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG:
                // If null, then the remote reference is not found. GetSigTypeFromIBCZapSig will search all locations to try and resolve the type
                EcmaModule remoteModule = ibcModule.GetModuleFromIndex(sig.ReadCompressedInteger());
                return(GetSigTypeFromIBCZapSig(ibcModule, remoteModule, sig));

            case CorElementType.ELEMENT_TYPE_VAR:
            case CorElementType.ELEMENT_TYPE_MVAR:
                // VAR/MVAR can never appear in a ZapSig
                throw new Exception("Attempt to parse ELEMENT_TYPE_VAR or ELEMENT_TYPE_MVAR in an IBC ZapSig");

            case CorElementType.ELEMENT_TYPE_GENERICINST:
                CorElementType genericTyp            = (CorElementType)sig.ReadByte();
                MetadataType   genericDefinitionType = LoadTypeFromIBCZapSig(ibcModule, ecmaModule, genericTyp, ref sig);
                if (genericDefinitionType == null)
                {
                    return(null);
                }
                int        numTypeArgs = sig.ReadCompressedInteger();
                TypeDesc[] typeArgs    = new TypeDesc[numTypeArgs];
                for (int i = 0; i < numTypeArgs; i++)
                {
                    TypeDesc nextTypeArg = GetSigTypeFromIBCZapSig(ibcModule, ecmaModule, sig);
                    if (nextTypeArg == null)
                    {
                        return(null);
                    }
                    SkipTypeInIBCZapSig(ref sig);
                    typeArgs[i] = nextTypeArg;
                }
                return(genericDefinitionType.MakeInstantiatedType(new Instantiation(typeArgs)));

            case CorElementType.ELEMENT_TYPE_CLASS:
            case CorElementType.ELEMENT_TYPE_VALUETYPE:
                return(LoadTypeFromIBCZapSig(ibcModule, ecmaModule, typ, ref sig));

            case CorElementType.ELEMENT_TYPE_SZARRAY:
            {
                TypeDesc arrayElementType = GetSigTypeFromIBCZapSig(ibcModule, ecmaModule, sig);
                if (arrayElementType == null)
                {
                    return(null);
                }
                return(arrayElementType.MakeArrayType());
            }

            case CorElementType.ELEMENT_TYPE_ARRAY:
            {
                TypeDesc arrayElementType = GetSigTypeFromIBCZapSig(ibcModule, ecmaModule, sig);
                if (arrayElementType == null)
                {
                    return(null);
                }
                SkipTypeInIBCZapSig(ref sig);
                return(arrayElementType.MakeArrayType(sig.ReadCompressedInteger()));
            }

            case CorElementType.ELEMENT_TYPE_PINNED:
                // Return what follows
                return(GetSigTypeFromIBCZapSig(ibcModule, ecmaModule, sig));

            case CorElementType.ELEMENT_TYPE_BYREF:
            {
                TypeDesc byRefToType = GetSigTypeFromIBCZapSig(ibcModule, ecmaModule, sig);
                if (byRefToType == null)
                {
                    return(null);
                }
                return(byRefToType.MakeByRefType());
            }

            case CorElementType.ELEMENT_TYPE_PTR:
            {
                TypeDesc pointerToType = GetSigTypeFromIBCZapSig(ibcModule, ecmaModule, sig);
                if (pointerToType == null)
                {
                    return(null);
                }
                return(pointerToType.MakePointerType());
            }

            default:
                throw new Exception($"Invalid element type {typ:x} in IBC ZapSig");
            }
        }
Ejemplo n.º 4
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));
        }