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); } }