Exemple #1
0
        public MethodIL Link(MethodDesc owningMethod)
        {
            int totalLength       = 0;
            int numSequencePoints = 0;

            for (int i = 0; i < _codeStreams.Count; i++)
            {
                ILCodeStream ilCodeStream = _codeStreams[i];
                ilCodeStream._startOffsetForLinking = totalLength;
                totalLength       += ilCodeStream._length;
                numSequencePoints += ilCodeStream._sequencePoints.Count;
            }

            byte[] ilInstructions = new byte[totalLength];
            int    copiedLength   = 0;

            for (int i = 0; i < _codeStreams.Count; i++)
            {
                ILCodeStream ilCodeStream = _codeStreams[i];
                ilCodeStream.PatchLabels();
                Array.Copy(ilCodeStream._instructions, 0, ilInstructions, copiedLength, ilCodeStream._length);
                copiedLength += ilCodeStream._length;
            }

            MethodDebugInformation debugInfo = null;

            if (numSequencePoints > 0)
            {
                ILSequencePoint[] sequencePoints = new ILSequencePoint[numSequencePoints];
                int copiedSequencePointLength    = 0;
                for (int codeStreamIndex = 0; codeStreamIndex < _codeStreams.Count; codeStreamIndex++)
                {
                    ILCodeStream ilCodeStream = _codeStreams[codeStreamIndex];

                    for (int sequencePointIndex = 0; sequencePointIndex < ilCodeStream._sequencePoints.Count; sequencePointIndex++)
                    {
                        ILSequencePoint sequencePoint = ilCodeStream._sequencePoints[sequencePointIndex];
                        sequencePoints[copiedSequencePointLength] = new ILSequencePoint(
                            ilCodeStream._startOffsetForLinking + sequencePoint.Offset,
                            sequencePoint.Document,
                            sequencePoint.LineNumber);
                        copiedSequencePointLength++;
                    }
                }

                debugInfo = new EmittedMethodDebugInformation(sequencePoints);
            }

            ILExceptionRegion[] exceptionRegions = null;

            int numberOfExceptionRegions = _finallyRegions.Count;

            if (numberOfExceptionRegions > 0)
            {
                exceptionRegions = new ILExceptionRegion[numberOfExceptionRegions];

                for (int i = 0; i < _finallyRegions.Count; i++)
                {
                    ILExceptionRegionBuilder region = _finallyRegions[i];

                    Debug.Assert(region.IsDefined);

                    exceptionRegions[i] = new ILExceptionRegion(ILExceptionRegionKind.Finally,
                                                                region.TryOffset, region.TryLength, region.HandlerOffset, region.HandlerLength,
                                                                classToken: 0, filterOffset: 0);
                }
            }

            var result = new ILStubMethodIL(owningMethod, ilInstructions, _locals.ToArray(), _tokens.ToArray(), exceptionRegions, debugInfo);

            result.CheckStackBalance();
            return(result);
        }
        public static ReadyToRunStandaloneMethodMetadata Compute(EcmaMethod wrappedMethod)
        {
            var metadataReader = wrappedMethod.MetadataReader;
            var _module        = wrappedMethod.Module;
            var rva            = wrappedMethod.MetadataReader.GetMethodDefinition(wrappedMethod.Handle).RelativeVirtualAddress;
            var _methodBody    = _module.PEReader.GetMethodBody(rva);

            byte[] _alternateILStream = _methodBody.GetILBytes();

            var exceptionRegions = _methodBody.ExceptionRegions;

            ILExceptionRegion[] _exceptionRegions;

            int length = exceptionRegions.Length;

            if (length == 0)
            {
                _exceptionRegions = Array.Empty <ILExceptionRegion>();
            }
            else
            {
                _exceptionRegions = new ILExceptionRegion[length];
                for (int i = 0; i < length; i++)
                {
                    var exceptionRegion = exceptionRegions[i];

                    _exceptionRegions[i] = new ILExceptionRegion(
                        (ILExceptionRegionKind)exceptionRegion.Kind, // assumes that ILExceptionRegionKind and ExceptionRegionKind enums are in sync
                        exceptionRegion.TryOffset,
                        exceptionRegion.TryLength,
                        exceptionRegion.HandlerOffset,
                        exceptionRegion.HandlerLength,
                        MetadataTokens.GetToken(exceptionRegion.CatchType),
                        exceptionRegion.FilterOffset);
                }
            }

            BlobReader localsBlob = default(BlobReader);

            if (!_methodBody.LocalSignature.IsNil)
            {
                localsBlob = wrappedMethod.MetadataReader.GetBlobReader(wrappedMethod.MetadataReader.GetStandaloneSignature(_methodBody.LocalSignature).Signature);
            }

            AlternativeTypeRefProvider alternateTypes = new AlternativeTypeRefProvider();
            EcmaSignatureEncoder <AlternativeTypeRefProvider> alternateEncoder = new EcmaSignatureEncoder <AlternativeTypeRefProvider>(alternateTypes);
            Dictionary <int, int> _alternateNonTokenStrings  = new Dictionary <int, int>();
            BlobBuilder           _alternateNonTypeRefStream = new BlobBuilder();
            BlobBuilder           _nonCodeAlternateBlob      = new BlobBuilder();

            {
                // Generate alternate stream for exceptions.
                _nonCodeAlternateBlob.WriteCompressedInteger(_exceptionRegions.Length);

                for (int i = 0; i < _exceptionRegions.Length; i++)
                {
                    var region = _exceptionRegions[i];
                    _nonCodeAlternateBlob.WriteCompressedInteger((int)region.Kind);
                    _nonCodeAlternateBlob.WriteCompressedInteger((int)region.TryOffset);
                    _nonCodeAlternateBlob.WriteCompressedInteger((int)region.TryLength);
                    _nonCodeAlternateBlob.WriteCompressedInteger((int)region.HandlerOffset);
                    _nonCodeAlternateBlob.WriteCompressedInteger((int)region.HandlerLength);
                    if (region.Kind == ILExceptionRegionKind.Catch)
                    {
                        int alternateToken = GetAlternateStreamToken(region.ClassToken);
                        int encodedToken   = CodedIndex.TypeDefOrRefOrSpec(MetadataTokens.EntityHandle(alternateToken));
                        _nonCodeAlternateBlob.WriteCompressedInteger(encodedToken);
                    }
                    else if (region.Kind == ILExceptionRegionKind.Filter)
                    {
                        _nonCodeAlternateBlob.WriteCompressedInteger(region.FilterOffset);
                    }
                }

                if (localsBlob.Length == 0)
                {
                    // No locals. Encode a 2 to indicate this
                    _nonCodeAlternateBlob.WriteByte(2);
                }
                else
                {
                    _nonCodeAlternateBlob.WriteByte(_methodBody.LocalVariablesInitialized ? (byte)1 : (byte)0);
                    EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(localsBlob, _nonCodeAlternateBlob, GetAlternateStreamToken);
                    sigTranslator.ParseLocalsSignature();
                }
            }

            ILTokenReplacer.Replace(_alternateILStream, GetAlternateStreamToken);

            // Add all the streams together into the _nonCodeAlternateBlob
            int expectedFinalSize = _nonCodeAlternateBlob.Count + _alternateILStream.Length + _alternateNonTypeRefStream.Count;

            _nonCodeAlternateBlob.WriteBytes(_alternateILStream);
            _nonCodeAlternateBlob.LinkSuffix(_alternateNonTypeRefStream);
            Debug.Assert(expectedFinalSize == _nonCodeAlternateBlob.Count);

            ReadyToRunStandaloneMethodMetadata methodBlock = new ReadyToRunStandaloneMethodMetadata();

            methodBlock.ConstantData = _nonCodeAlternateBlob.ToArray();
            methodBlock.TypeRefs     = alternateTypes._alternateTypeRefStream.ToArray();
            return(methodBlock);

            ///// HELPER FUNCTIONS

            unsafe int GetAlternateStreamToken(int token)
            {
                if (token == 0 || !_alternateNonTokenStrings.TryGetValue(token, out int alternateToken))
                {
                    var handle = MetadataTokens.Handle(token);

                    if (handle.Kind == HandleKind.TypeDefinition || handle.Kind == HandleKind.TypeReference)
                    {
                        EcmaType ecmaType = (EcmaType)wrappedMethod.Module.GetObject(MetadataTokens.EntityHandle(token));
                        alternateToken = MetadataTokens.GetToken(alternateTypes.GetTypeDefOrRefHandleForTypeDesc(ecmaType));
                    }
                    else
                    {
                        BlobBuilder blob = new BlobBuilder();
                        int         flag = 0;
                        if (handle.Kind == HandleKind.UserString)
                        {
                            string strAlternate = metadataReader.GetUserString((UserStringHandle)handle);
                            flag = 0x70000000;
                            blob.WriteCompressedInteger(strAlternate.Length);
                            fixed(char *charData = strAlternate)
                            {
                                blob.WriteBytes((byte *)charData, strAlternate.Length * 2);
                            }

                            // TODO: consider encoding via wtf-8, or possibly utf-8
                        }
                        else if (handle.Kind == HandleKind.TypeSpecification)
                        {
                            flag = 0x1B000000;
                            var sigBlob = metadataReader.GetBlobReader(metadataReader.GetTypeSpecification((TypeSpecificationHandle)handle).Signature);
                            EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(sigBlob, blob, GetAlternateStreamToken);
                            sigTranslator.ParseType();
                        }
                        else if (handle.Kind == HandleKind.MemberReference)
                        {
                            flag = 0x0a000000;
                            var memberReference = metadataReader.GetMemberReference((MemberReferenceHandle)handle);
                            var sigBlob         = metadataReader.GetBlobReader(memberReference.Signature);
                            EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(sigBlob, blob, GetAlternateStreamToken);
                            sigTranslator.ParseMemberRefSignature();
                            blob.WriteSerializedString(metadataReader.GetString(memberReference.Name));
                            blob.WriteCompressedInteger(CodedIndex.MemberRefParent(MetadataTokens.EntityHandle(GetAlternateStreamToken(MetadataTokens.GetToken(memberReference.Parent)))));
                        }
                        else if (handle.Kind == HandleKind.MethodDefinition)
                        {
                            flag = 0x0a000000;
                            var methodDefinition = metadataReader.GetMethodDefinition((MethodDefinitionHandle)handle);
                            var sigBlob          = metadataReader.GetBlobReader(methodDefinition.Signature);
                            EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(sigBlob, blob, GetAlternateStreamToken);
                            sigTranslator.ParseMethodSignature();
                            blob.WriteSerializedString(metadataReader.GetString(methodDefinition.Name));
                            blob.WriteCompressedInteger(CodedIndex.MemberRefParent(MetadataTokens.EntityHandle(GetAlternateStreamToken(MetadataTokens.GetToken(methodDefinition.GetDeclaringType())))));
                        }
                        else if (handle.Kind == HandleKind.FieldDefinition)
                        {
                            flag = 0x0a000000;
                            var fieldDefinition = metadataReader.GetFieldDefinition((FieldDefinitionHandle)handle);
                            var sigBlob         = metadataReader.GetBlobReader(fieldDefinition.Signature);
                            EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(sigBlob, blob, GetAlternateStreamToken);
                            sigTranslator.ParseFieldSignature();
                            blob.WriteSerializedString(metadataReader.GetString(fieldDefinition.Name));
                            blob.WriteCompressedInteger(CodedIndex.MemberRefParent(MetadataTokens.EntityHandle(GetAlternateStreamToken(MetadataTokens.GetToken(fieldDefinition.GetDeclaringType())))));
                        }
                        else if (handle.Kind == HandleKind.MethodSpecification)
                        {
                            flag = 0x2B000000;
                            var methodSpecification = metadataReader.GetMethodSpecification((MethodSpecificationHandle)handle);
                            var sigBlob             = metadataReader.GetBlobReader(methodSpecification.Signature);
                            blob.WriteCompressedInteger(MetadataTokens.GetRowNumber(MetadataTokens.EntityHandle(GetAlternateStreamToken(MetadataTokens.GetToken(methodSpecification.Method)))));
                            EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(sigBlob, blob, GetAlternateStreamToken);
                            sigTranslator.ParseMethodSpecSignature();
                        }
                        else if (handle.Kind == HandleKind.StandaloneSignature)
                        {
                            flag = 0x11000000;
                            var reader  = wrappedMethod.Module.MetadataReader;
                            var sigBlob = reader.GetBlobReader(reader.GetStandaloneSignature((StandaloneSignatureHandle)handle).Signature);
                            EcmaSignatureTranslator sigTranslator = new EcmaSignatureTranslator(sigBlob, blob, GetAlternateStreamToken);
                            sigTranslator.ParseMethodSignature();
                        }

                        _alternateNonTypeRefStream.WriteBytes(blob.ToArray());
                        alternateToken = (_alternateNonTokenStrings.Count + 1) | flag;
                    }
                    _alternateNonTokenStrings.Add(token, alternateToken);
                }

                return(alternateToken);
            }
        }