diff --git a/src/IKVM.Reflection/Emit/ILGenerator.cs b/src/IKVM.Reflection/Emit/ILGenerator.cs index 7c287e5dd0..a7cfc046cc 100644 --- a/src/IKVM.Reflection/Emit/ILGenerator.cs +++ b/src/IKVM.Reflection/Emit/ILGenerator.cs @@ -158,10 +158,8 @@ internal ILGenerator(ModuleBuilder moduleBuilder, int initialCapacity) this.moduleBuilder = moduleBuilder; this.locals = SignatureHelper.GetLocalVarSigHelper(moduleBuilder); -#if NETFRAMEWORK if (moduleBuilder.symbolWriter != null) scope = new Scope(null); -#endif } // non-standard API @@ -825,13 +823,11 @@ public void ThrowException(Type excType) internal int WriteBody(bool initLocals) { -#if NETFRAMEWORK if (moduleBuilder.symbolWriter != null) { Debug.Assert(scope != null && scope.parent == null); scope.endOffset = code.Position; } -#endif ResolveBranches(); @@ -854,8 +850,6 @@ internal int WriteBody(bool initLocals) rva = WriteFatHeaderAndCode(bb, localVarSigTok, initLocals); } -#if NETFRAMEWORK - if (moduleBuilder.symbolWriter != null) { if (sequencePoints.Count != 0) @@ -885,8 +879,6 @@ internal int WriteBody(bool initLocals) WriteScope(scope, localVarSigTok); } -#endif - return rva; } @@ -1045,7 +1037,6 @@ internal static void AddTokenFixups(int codeOffset, List tokenFixupOffsets, void WriteScope(Scope scope, int localVarSigTok) { -#if NETFRAMEWORK moduleBuilder.symbolWriter.OpenScope(scope.startOffset); foreach (var local in scope.locals) @@ -1071,9 +1062,6 @@ void WriteScope(Scope scope, int localVarSigTok) WriteScope(child, localVarSigTok); moduleBuilder.symbolWriter.CloseScope(scope.endOffset); -#else - throw new NotSupportedException(); -#endif } } diff --git a/src/IKVM.Reflection/Emit/MethodBuilder.cs b/src/IKVM.Reflection/Emit/MethodBuilder.cs index 2355c7f667..2da60a31d1 100644 --- a/src/IKVM.Reflection/Emit/MethodBuilder.cs +++ b/src/IKVM.Reflection/Emit/MethodBuilder.cs @@ -90,15 +90,11 @@ public void __ReleaseILGenerator() { if (ilgen != null) { -#if NETFRAMEWORK ModuleBuilder.symbolWriter?.OpenMethod(new SymbolToken(-pseudoToken | 0x06000000), this); -#endif rva = ilgen.WriteBody(initLocals); -#if NETFRAMEWORK ModuleBuilder.symbolWriter?.CloseMethod(); -#endif ilgen = null; } @@ -658,6 +654,7 @@ internal ModuleBuilder ModuleBuilder internal void WriteMethodDefRecord(int baseRVA, MetadataWriter mw, ref int paramList) { + RowNumber = mw.GetNewMethodDefRowId(); if (rva != -1) mw.Write(rva + baseRVA); else diff --git a/src/IKVM.Reflection/Emit/ModuleBuilder.cs b/src/IKVM.Reflection/Emit/ModuleBuilder.cs index c9eac0a4d0..4fd6ed09ac 100644 --- a/src/IKVM.Reflection/Emit/ModuleBuilder.cs +++ b/src/IKVM.Reflection/Emit/ModuleBuilder.cs @@ -50,9 +50,7 @@ public sealed class ModuleBuilder : Module, ITypeOwner readonly AssemblyBuilder asm; internal readonly string moduleName; internal readonly string fileName; -#if NETFRAMEWORK internal readonly ISymbolWriterImpl symbolWriter; -#endif readonly TypeBuilder moduleType; readonly List types = new List(); readonly Dictionary typeTokens = new Dictionary(); @@ -245,8 +243,6 @@ internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, this.moduleName = moduleName; this.fileName = fileName; -#if NETFRAMEWORK - if (emitSymbolInfo) { symbolWriter = SymbolSupport.CreateSymbolWriterFor(this); @@ -254,8 +250,6 @@ internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, throw new NotSupportedException(); } -#endif - if (!universe.Deterministic) { __PEHeaderTimeDateStamp = DateTime.UtcNow; @@ -663,11 +657,7 @@ internal override void GetTypesImpl(List list) public ISymbolDocumentWriter DefineDocument(string url, Guid language, Guid languageVendor, Guid documentType) { -#if NETFRAMEWORK return symbolWriter.DefineDocument(url, language, languageVendor, documentType); -#else - throw new NotSupportedException(); -#endif } public int __GetAssemblyToken(Assembly assembly) @@ -943,7 +933,6 @@ private int FindOrAddAssemblyRef(AssemblyName name, bool alwaysAdd) internal void WriteSymbolTokenMap() { -#if NETFRAMEWORK for (int i = 0; i < resolvedTokens.Count; i++) { int newToken = resolvedTokens[i]; @@ -953,9 +942,6 @@ internal void WriteSymbolTokenMap() int oldToken = (i + 1) | (newToken & ~0xFFFFFF); SymbolSupport.RemapToken(symbolWriter, oldToken, newToken); } -#else - throw new NotSupportedException(); -#endif } internal void RegisterTokenFixup(int pseudoToken, int realToken) @@ -1415,11 +1401,7 @@ public override string ScopeName public ISymbolWriter GetSymWriter() { -#if NETFRAMEWORK return symbolWriter; -#else - return null; -#endif } public void DefineUnmanagedResource(string resourceFileName) @@ -1443,14 +1425,10 @@ public void SetUserEntryPoint(MethodInfo entryPoint) token = -token | 0x06000000; } -#if NETFRAMEWORK - if (symbolWriter != null) { symbolWriter.SetUserEntryPoint(new SymbolToken(token)); } - -#endif } public StringToken GetStringConstant(string str) diff --git a/src/IKVM.Reflection/Impl/AbstractPdbWriter.cs b/src/IKVM.Reflection/Impl/AbstractPdbWriter.cs new file mode 100644 index 0000000000..a459aac593 --- /dev/null +++ b/src/IKVM.Reflection/Impl/AbstractPdbWriter.cs @@ -0,0 +1,898 @@ +/* + Copyright (C) 2008-2010 Jeroen Frijters + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jeroen Frijters + jeroen@frijters.net +*/ +using System; +using System.Collections.Generic; +using System.Diagnostics.SymbolStore; +using System.Runtime.InteropServices; + +using IKVM.Reflection.Emit; + +namespace IKVM.Reflection.Impl +{ + abstract class AbstractPdbWriter : ISymbolWriterImpl + { + protected readonly ModuleBuilder moduleBuilder; + protected readonly Dictionary documents = new Dictionary(); + protected readonly List methods = new List(); + protected readonly Dictionary remap = new Dictionary(); + protected readonly Dictionary reversemap = new Dictionary(); + protected readonly Dictionary methodMap = new Dictionary(); + protected Method currentMethod; + + internal AbstractPdbWriter(ModuleBuilder moduleBuilder) + { + this.moduleBuilder = moduleBuilder; + } + + + protected sealed class LocalVar + { + internal readonly FieldAttributes attributes; + internal readonly int signature; + internal readonly SymAddressKind addrKind; + internal readonly int addr1; + internal readonly int addr2; + internal readonly int addr3; + internal readonly int startOffset; + internal readonly int endOffset; + + internal LocalVar(FieldAttributes attributes, int signature, SymAddressKind addrKind, int addr1, int addr2, int addr3, int startOffset, int endOffset) + { + this.attributes = attributes; + this.signature = signature; + this.addrKind = addrKind; + this.addr1 = addr1; + this.addr2 = addr2; + this.addr3 = addr3; + this.startOffset = startOffset; + this.endOffset = endOffset; + } + } + + protected sealed class Scope + { + internal readonly int startOffset; + internal int endOffset; + internal readonly List scopes = new List(); + internal readonly Dictionary locals = new Dictionary(); + + internal Scope(int startOffset) + { + this.startOffset = startOffset; + } + } + + protected sealed class Method + { + internal readonly int token; + internal Document document; + internal int[] offsets; + internal int[] lines; + internal int[] columns; + internal int[] endLines; + internal int[] endColumns; + internal readonly List scopes = new List(); + internal readonly Stack scopeStack = new Stack(); + + internal Method(int token) + { + this.token = token; + } + } + + protected sealed class Document : ISymbolDocumentWriter + { + internal readonly string url; + internal Guid language; + internal Guid languageVendor; + internal Guid documentType; + internal object unmanagedDocument; + + internal Document(string url, Guid language, Guid languageVendor, Guid documentType) + { + this.url = url; + this.language = language; + this.languageVendor = languageVendor; + this.documentType = documentType; + } + + public void SetCheckSum(Guid algorithmId, byte[] checkSum) + { + throw new NotImplementedException(); + } + + public void SetSource(byte[] source) + { + throw new NotImplementedException(); + } + } + + public ISymbolDocumentWriter DefineDocument(string url, Guid language, Guid languageVendor, Guid documentType) + { + Document doc; + if (!documents.TryGetValue(url, out doc)) + { + doc = new Document(url, language, languageVendor, documentType); + documents.Add(url, doc); + } + return doc; + } + + public void OpenMethod(SymbolToken method) + { + throw new NotImplementedException(); + } + + public void OpenMethod(SymbolToken method, MethodBase mb) + { + int token = method.GetToken(); + currentMethod = new Method(token); + methodMap.Add(token, mb); + } + + public void CloseMethod() + { + methods.Add(currentMethod); + currentMethod = null; + } + + public void DefineSequencePoints(ISymbolDocumentWriter document, int[] offsets, int[] lines, int[] columns, int[] endLines, int[] endColumns) + { + currentMethod.document = (Document)document; + currentMethod.offsets = offsets; + currentMethod.lines = lines; + currentMethod.columns = columns; + currentMethod.endLines = endLines; + currentMethod.endColumns = endColumns; + } + + public int OpenScope(int startOffset) + { + Scope scope = new Scope(startOffset); + if (currentMethod.scopeStack.Count == 0) + { + currentMethod.scopes.Add(scope); + } + else + { + currentMethod.scopeStack.Peek().scopes.Add(scope); + } + currentMethod.scopeStack.Push(scope); + return 0; + } + + public void CloseScope(int endOffset) + { + currentMethod.scopeStack.Pop().endOffset = endOffset; + } + + public void DefineLocalVariable2(string name, FieldAttributes attributes, int signature, SymAddressKind addrKind, int addr1, int addr2, int addr3, int startOffset, int endOffset) + { + currentMethod.scopeStack.Peek().locals[name] = new LocalVar(attributes, signature, addrKind, addr1, addr2, addr3, startOffset, endOffset); + } + + public abstract byte[] GetDebugInfo(ref IMAGE_DEBUG_DIRECTORY idd); + + public void RemapToken(int oldToken, int newToken) + { + remap.Add(oldToken, newToken); + reversemap.Add(newToken, oldToken); + } + + public abstract void Close(); + + public void DefineLocalVariable(string name, System.Reflection.FieldAttributes attributes, byte[] signature, SymAddressKind addrKind, int addr1, int addr2, int addr3, int startOffset, int endOffset) + { + throw new NotImplementedException(); + } + + public void CloseNamespace() + { + throw new NotImplementedException(); + } + + public void DefineField(SymbolToken parent, string name, System.Reflection.FieldAttributes attributes, byte[] signature, SymAddressKind addrKind, int addr1, int addr2, int addr3) + { + throw new NotImplementedException(); + } + + public void DefineGlobalVariable(string name, System.Reflection.FieldAttributes attributes, byte[] signature, SymAddressKind addrKind, int addr1, int addr2, int addr3) + { + throw new NotImplementedException(); + } + + public void DefineParameter(string name, System.Reflection.ParameterAttributes attributes, int sequence, SymAddressKind addrKind, int addr1, int addr2, int addr3) + { + throw new NotImplementedException(); + } + + public void Initialize(IntPtr emitter, string filename, bool fFullBuild) + { + throw new NotImplementedException(); + } + + public void OpenNamespace(string name) + { + throw new NotImplementedException(); + } + + public void SetMethodSourceRange(ISymbolDocumentWriter startDoc, int startLine, int startColumn, ISymbolDocumentWriter endDoc, int endLine, int endColumn) + { + throw new NotImplementedException(); + } + + public void SetScopeRange(int scopeID, int startOffset, int endOffset) + { + throw new NotImplementedException(); + } + + public void SetSymAttribute(SymbolToken parent, string name, byte[] data) + { + throw new NotImplementedException(); + } + + public void SetUnderlyingWriter(IntPtr underlyingWriter) + { + throw new NotImplementedException(); + } + + public void SetUserEntryPoint(SymbolToken entryMethod) + { + throw new NotImplementedException(); + } + + public void UsingNamespace(string fullName) + { + throw new NotImplementedException(); + } + + public void PlaceHolder_CloseEnum() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_CountEnum() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_ResetEnum() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumTypeDefs() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumInterfaceImpls() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumTypeRefs() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_FindTypeDefByName() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetScopeProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetModuleFromScope() + { + throw new NotImplementedException(); + } + + private static void WriteString(IntPtr ptrString, IntPtr ptrLength, string str, int length) + { + if (ptrString != IntPtr.Zero) + { + for (int i = 0; i < Math.Min(length, str.Length); i++) + { + Marshal.WriteInt16(ptrString, i, str[i]); + } + } + if (ptrLength != IntPtr.Zero) + { + Marshal.WriteInt32(ptrLength, str.Length); + } + } + + private static void WriteToken(IntPtr ptr, MemberInfo member) + { + if (ptr != IntPtr.Zero) + { + Marshal.WriteInt32(ptr, member == null ? 0 : member.MetadataToken); + } + } + + private static void WriteInt32(IntPtr ptr, int value) + { + if (ptr != IntPtr.Zero) + { + Marshal.WriteInt32(ptr, value); + } + } + + public void GetTypeDefProps( + int td, // [IN] TypeDef token for inquiry. + IntPtr szTypeDef, // [OUT] Put name here. + int cchTypeDef, // [IN] size of name buffer in wide chars. + IntPtr pchTypeDef, // [OUT] put size of name (wide chars) here. + IntPtr pdwTypeDefFlags, // [OUT] Put flags here. + IntPtr ptkExtends) // [OUT] Put base class TypeDef/TypeRef here. + { + if (td == 0) + { + // why are we being called with an invalid token? + WriteString(szTypeDef, pchTypeDef, "", cchTypeDef); + WriteInt32(pdwTypeDefFlags, 0); + WriteToken(ptkExtends, null); + } + else + { + Type type = moduleBuilder.ResolveType(td); + WriteString(szTypeDef, pchTypeDef, type.FullName, cchTypeDef); + WriteInt32(pdwTypeDefFlags, (int)type.Attributes); + WriteToken(ptkExtends, type.BaseType); + } + } + + public void PlaceHolder_GetInterfaceImplProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetTypeRefProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_ResolveTypeRef() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumMembers() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumMembersWithName() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumMethods() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumMethodsWithName() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumFields() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumFieldsWithName() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumParams() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumMemberRefs() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumMethodImpls() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumPermissionSets() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_FindMember() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_FindMethod() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_FindField() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_FindMemberRef() + { + throw new NotImplementedException(); + } + + public void GetMethodProps( + int mb, // The method for which to get props. + IntPtr pClass, // [OUT] Put method's class here. + IntPtr szMethod, // [OUT] Put method's name here. + int cchMethod, // Size of szMethod buffer in wide chars. + IntPtr pchMethod, // [OUT] Put actual size here + IntPtr pdwAttr, // [OUT] Put flags here. + IntPtr ppvSigBlob, // [OUT] point to the blob value of meta data + IntPtr pcbSigBlob, // [OUT] actual size of signature blob + IntPtr pulCodeRVA, // [OUT] codeRVA + IntPtr pdwImplFlags) // [OUT] Impl. Flags + { + if (pdwAttr != IntPtr.Zero || ppvSigBlob != IntPtr.Zero || pcbSigBlob != IntPtr.Zero || pulCodeRVA != IntPtr.Zero || pdwImplFlags != IntPtr.Zero) + { + throw new NotImplementedException(); + } + MethodBase method = methodMap[reversemap[mb]]; + WriteToken(pClass, method.DeclaringType); + WriteString(szMethod, pchMethod, method.Name, cchMethod); + } + + public void PlaceHolder_GetMemberRefProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumProperties() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumEvents() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetEventProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumMethodSemantics() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetMethodSemantics() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetClassLayout() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetFieldMarshal() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetRVA() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetPermissionSetProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetSigFromToken() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetModuleRefProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumModuleRefs() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetTypeSpecFromToken() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetNameFromToken() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumUnresolvedMethods() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetUserString() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetPinvokeMap() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumSignatures() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumTypeSpecs() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumUserStrings() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetParamForMethodIndex() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_EnumCustomAttributes() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetCustomAttributeProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_FindTypeRef() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetMemberProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetFieldProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetPropertyProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetParamProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetCustomAttributeByName() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_IsValidToken() + { + throw new NotImplementedException(); + } + + public void GetNestedClassProps( + int tdNestedClass, // [IN] NestedClass token. + IntPtr ptdEnclosingClass) // [OUT] EnclosingClass token. + { + Type type = moduleBuilder.ResolveType(tdNestedClass); + WriteToken(ptdEnclosingClass, type.DeclaringType); + } + + public void PlaceHolder_GetNativeCallConvFromSig() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_IsGlobal() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetModuleProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_Save() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SaveToStream() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetSaveSize() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineTypeDef() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineNestedType() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetHandler() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineMethod() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineMethodImpl() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineTypeRefByName() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineImportType() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineMemberRef() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineImportMember() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineEvent() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetClassLayout() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DeleteClassLayout() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetFieldMarshal() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DeleteFieldMarshal() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefinePermissionSet() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetRVA() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetTokenFromSig() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineModuleRef() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetParent() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_GetTokenFromTypeSpec() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SaveToMemory() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineUserString() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DeleteToken() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetMethodProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetTypeDefProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetEventProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetPermissionSetProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefinePinvokeMap() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetPinvokeMap() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DeletePinvokeMap() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineCustomAttribute() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetCustomAttributeValue() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineField() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineProperty() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineParam() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetFieldProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetPropertyProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetParamProps() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_DefineSecurityAttributeSet() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_ApplyEditAndContinue() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_TranslateSigWithScope() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetMethodImplFlags() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_SetFieldRVA() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_Merge() + { + throw new NotImplementedException(); + } + + public void PlaceHolder_MergeEnd() + { + throw new NotImplementedException(); + } + + public bool IsDeterministic + { + get { return false; } + } + } +} diff --git a/src/IKVM.Reflection/Impl/PdbWriter.cs b/src/IKVM.Reflection/Impl/PdbWriter.cs index f67f97a2cf..af7b3d195f 100644 --- a/src/IKVM.Reflection/Impl/PdbWriter.cs +++ b/src/IKVM.Reflection/Impl/PdbWriter.cs @@ -33,199 +33,45 @@ Jeroen Frijters namespace IKVM.Reflection.Impl { - sealed class PdbWriter : ISymbolWriterImpl, IMetaDataEmit, IMetaDataImport + sealed class PdbWriter : AbstractPdbWriter, ISymbolWriterImpl, IMetaDataEmit, IMetaDataImport { - - private readonly ModuleBuilder moduleBuilder; private ISymUnmanagedWriter2 symUnmanagedWriter; - private readonly Dictionary documents = new Dictionary(); - private readonly List methods = new List(); - private readonly Dictionary remap = new Dictionary(); - private readonly Dictionary reversemap = new Dictionary(); - private readonly Dictionary methodMap = new Dictionary(); - private Method currentMethod; - - internal PdbWriter(ModuleBuilder moduleBuilder) - { - this.moduleBuilder = moduleBuilder; - } - private sealed class Document : ISymbolDocumentWriter + internal PdbWriter(ModuleBuilder moduleBuilder) : base(moduleBuilder) { - internal readonly string url; - private Guid language; - private Guid languageVendor; - private Guid documentType; - private ISymUnmanagedDocumentWriter unmanagedDocument; - - internal Document(string url, Guid language, Guid languageVendor, Guid documentType) - { - this.url = url; - this.language = language; - this.languageVendor = languageVendor; - this.documentType = documentType; - } - - public void SetCheckSum(Guid algorithmId, byte[] checkSum) - { - throw new NotImplementedException(); - } - - public void SetSource(byte[] source) - { - throw new NotImplementedException(); - } - - internal ISymUnmanagedDocumentWriter GetUnmanagedDocument(ISymUnmanagedWriter2 symUnmanagedWriter) - { - if (unmanagedDocument == null) - { - unmanagedDocument = symUnmanagedWriter.DefineDocument(url, ref language, ref languageVendor, ref documentType); - } - return unmanagedDocument; - } - - internal void Release() - { - if (unmanagedDocument != null) - { - Marshal.ReleaseComObject(unmanagedDocument); - unmanagedDocument = null; - } - } - } - - private sealed class LocalVar - { - internal readonly FieldAttributes attributes; - internal readonly int signature; - internal readonly SymAddressKind addrKind; - internal readonly int addr1; - internal readonly int addr2; - internal readonly int addr3; - internal readonly int startOffset; - internal readonly int endOffset; - - internal LocalVar(FieldAttributes attributes, int signature, SymAddressKind addrKind, int addr1, int addr2, int addr3, int startOffset, int endOffset) - { - this.attributes = attributes; - this.signature = signature; - this.addrKind = addrKind; - this.addr1 = addr1; - this.addr2 = addr2; - this.addr3 = addr3; - this.startOffset = startOffset; - this.endOffset = endOffset; - } } - private sealed class Scope - { - internal readonly int startOffset; - internal int endOffset; - internal readonly List scopes = new List(); - internal readonly Dictionary locals = new Dictionary(); - - internal Scope(int startOffset) - { - this.startOffset = startOffset; - } - internal void Do(ISymUnmanagedWriter2 symUnmanagedWriter) - { - symUnmanagedWriter.OpenScope(startOffset); - foreach (KeyValuePair kv in locals) - { - symUnmanagedWriter.DefineLocalVariable2(kv.Key, (int)kv.Value.attributes, kv.Value.signature, (int)kv.Value.addrKind, kv.Value.addr1, kv.Value.addr2, kv.Value.addr3, kv.Value.startOffset, kv.Value.endOffset); - } - foreach (Scope scope in scopes) - { - scope.Do(symUnmanagedWriter); - } - symUnmanagedWriter.CloseScope(endOffset); - } - } - - private sealed class Method + private ISymUnmanagedDocumentWriter GetUnmanagedDocument(Document document) { - internal readonly int token; - internal Document document; - internal int[] offsets; - internal int[] lines; - internal int[] columns; - internal int[] endLines; - internal int[] endColumns; - internal readonly List scopes = new List(); - internal readonly Stack scopeStack = new Stack(); - - internal Method(int token) + if (document.unmanagedDocument == null) { - this.token = token; + document.unmanagedDocument = symUnmanagedWriter.DefineDocument(document.url, ref document.language, ref document.languageVendor, ref document.documentType); } + return document.unmanagedDocument as ISymUnmanagedDocumentWriter; } - public ISymbolDocumentWriter DefineDocument(string url, Guid language, Guid languageVendor, Guid documentType) + private void ReleaseDocument(Document document) { - Document doc; - if (!documents.TryGetValue(url, out doc)) + if (document.unmanagedDocument != null) { - doc = new Document(url, language, languageVendor, documentType); - documents.Add(url, doc); + Marshal.ReleaseComObject(document.unmanagedDocument); + document.unmanagedDocument = null; } - return doc; } - public void OpenMethod(SymbolToken method) + private void WriteScope(Scope scope) { - throw new NotImplementedException(); - } - - public void OpenMethod(SymbolToken method, MethodBase mb) - { - int token = method.GetToken(); - currentMethod = new Method(token); - methodMap.Add(token, mb); - } - - public void CloseMethod() - { - methods.Add(currentMethod); - currentMethod = null; - } - - public void DefineSequencePoints(ISymbolDocumentWriter document, int[] offsets, int[] lines, int[] columns, int[] endLines, int[] endColumns) - { - currentMethod.document = (Document)document; - currentMethod.offsets = offsets; - currentMethod.lines = lines; - currentMethod.columns = columns; - currentMethod.endLines = endLines; - currentMethod.endColumns = endColumns; - } - - public int OpenScope(int startOffset) - { - Scope scope = new Scope(startOffset); - if (currentMethod.scopeStack.Count == 0) + symUnmanagedWriter.OpenScope(scope.startOffset); + foreach (KeyValuePair kv in scope.locals) { - currentMethod.scopes.Add(scope); + symUnmanagedWriter.DefineLocalVariable2(kv.Key, (int)kv.Value.attributes, kv.Value.signature, (int)kv.Value.addrKind, kv.Value.addr1, kv.Value.addr2, kv.Value.addr3, kv.Value.startOffset, kv.Value.endOffset); } - else + foreach (Scope child in scope.scopes) { - currentMethod.scopeStack.Peek().scopes.Add(scope); + WriteScope(child); } - currentMethod.scopeStack.Push(scope); - return 0; - } - - public void CloseScope(int endOffset) - { - currentMethod.scopeStack.Pop().endOffset = endOffset; - } - - public void DefineLocalVariable2(string name, FieldAttributes attributes, int signature, SymAddressKind addrKind, int addr1, int addr2, int addr3, int startOffset, int endOffset) - { - currentMethod.scopeStack.Peek().locals[name] = new LocalVar(attributes, signature, addrKind, addr1, addr2, addr3, startOffset, endOffset); + symUnmanagedWriter.CloseScope(scope.endOffset); } private void InitWriter() @@ -240,7 +86,7 @@ private void InitWriter() } } - public byte[] GetDebugInfo(ref IMAGE_DEBUG_DIRECTORY idd) + public override byte[] GetDebugInfo(ref IMAGE_DEBUG_DIRECTORY idd) { InitWriter(); uint cData; @@ -250,13 +96,7 @@ public byte[] GetDebugInfo(ref IMAGE_DEBUG_DIRECTORY idd) return buf; } - public void RemapToken(int oldToken, int newToken) - { - remap.Add(oldToken, newToken); - reversemap.Add(newToken, oldToken); - } - - public void Close() + public override void Close() { InitWriter(); @@ -267,19 +107,19 @@ public void Close() symUnmanagedWriter.OpenMethod(remappedToken); if (method.document != null) { - ISymUnmanagedDocumentWriter doc = method.document.GetUnmanagedDocument(symUnmanagedWriter); + ISymUnmanagedDocumentWriter doc = GetUnmanagedDocument(method.document); symUnmanagedWriter.DefineSequencePoints(doc, method.offsets.Length, method.offsets, method.lines, method.columns, method.endLines, method.endColumns); } foreach (Scope scope in method.scopes) { - scope.Do(symUnmanagedWriter); + WriteScope(scope); } symUnmanagedWriter.CloseMethod(); } foreach (Document doc in documents.Values) { - doc.Release(); + ReleaseDocument(doc); } symUnmanagedWriter.Close(); @@ -290,700 +130,6 @@ public void Close() remap.Clear(); reversemap.Clear(); } - - public void DefineLocalVariable(string name, System.Reflection.FieldAttributes attributes, byte[] signature, SymAddressKind addrKind, int addr1, int addr2, int addr3, int startOffset, int endOffset) - { - throw new NotImplementedException(); - } - - public void CloseNamespace() - { - throw new NotImplementedException(); - } - - public void DefineField(SymbolToken parent, string name, System.Reflection.FieldAttributes attributes, byte[] signature, SymAddressKind addrKind, int addr1, int addr2, int addr3) - { - throw new NotImplementedException(); - } - - public void DefineGlobalVariable(string name, System.Reflection.FieldAttributes attributes, byte[] signature, SymAddressKind addrKind, int addr1, int addr2, int addr3) - { - throw new NotImplementedException(); - } - - public void DefineParameter(string name, System.Reflection.ParameterAttributes attributes, int sequence, SymAddressKind addrKind, int addr1, int addr2, int addr3) - { - throw new NotImplementedException(); - } - - public void Initialize(IntPtr emitter, string filename, bool fFullBuild) - { - throw new NotImplementedException(); - } - - public void OpenNamespace(string name) - { - throw new NotImplementedException(); - } - - public void SetMethodSourceRange(ISymbolDocumentWriter startDoc, int startLine, int startColumn, ISymbolDocumentWriter endDoc, int endLine, int endColumn) - { - throw new NotImplementedException(); - } - - public void SetScopeRange(int scopeID, int startOffset, int endOffset) - { - throw new NotImplementedException(); - } - - public void SetSymAttribute(SymbolToken parent, string name, byte[] data) - { - throw new NotImplementedException(); - } - - public void SetUnderlyingWriter(IntPtr underlyingWriter) - { - throw new NotImplementedException(); - } - - public void SetUserEntryPoint(SymbolToken entryMethod) - { - throw new NotImplementedException(); - } - - public void UsingNamespace(string fullName) - { - throw new NotImplementedException(); - } - - public void PlaceHolder_CloseEnum() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_CountEnum() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_ResetEnum() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumTypeDefs() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumInterfaceImpls() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumTypeRefs() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_FindTypeDefByName() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetScopeProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetModuleFromScope() - { - throw new NotImplementedException(); - } - - private static void WriteString(IntPtr ptrString, IntPtr ptrLength, string str, int length) - { - if (ptrString != IntPtr.Zero) - { - for (int i = 0; i < Math.Min(length, str.Length); i++) - { - Marshal.WriteInt16(ptrString, i, str[i]); - } - } - if (ptrLength != IntPtr.Zero) - { - Marshal.WriteInt32(ptrLength, str.Length); - } - } - - private static void WriteToken(IntPtr ptr, MemberInfo member) - { - if (ptr != IntPtr.Zero) - { - Marshal.WriteInt32(ptr, member == null ? 0 : member.MetadataToken); - } - } - - private static void WriteInt32(IntPtr ptr, int value) - { - if (ptr != IntPtr.Zero) - { - Marshal.WriteInt32(ptr, value); - } - } - - public void GetTypeDefProps( - int td, // [IN] TypeDef token for inquiry. - IntPtr szTypeDef, // [OUT] Put name here. - int cchTypeDef, // [IN] size of name buffer in wide chars. - IntPtr pchTypeDef, // [OUT] put size of name (wide chars) here. - IntPtr pdwTypeDefFlags, // [OUT] Put flags here. - IntPtr ptkExtends) // [OUT] Put base class TypeDef/TypeRef here. - { - if (td == 0) - { - // why are we being called with an invalid token? - WriteString(szTypeDef, pchTypeDef, "", cchTypeDef); - WriteInt32(pdwTypeDefFlags, 0); - WriteToken(ptkExtends, null); - } - else - { - Type type = moduleBuilder.ResolveType(td); - WriteString(szTypeDef, pchTypeDef, type.FullName, cchTypeDef); - WriteInt32(pdwTypeDefFlags, (int)type.Attributes); - WriteToken(ptkExtends, type.BaseType); - } - } - - public void PlaceHolder_GetInterfaceImplProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetTypeRefProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_ResolveTypeRef() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumMembers() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumMembersWithName() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumMethods() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumMethodsWithName() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumFields() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumFieldsWithName() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumParams() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumMemberRefs() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumMethodImpls() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumPermissionSets() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_FindMember() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_FindMethod() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_FindField() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_FindMemberRef() - { - throw new NotImplementedException(); - } - - public void GetMethodProps( - int mb, // The method for which to get props. - IntPtr pClass, // [OUT] Put method's class here. - IntPtr szMethod, // [OUT] Put method's name here. - int cchMethod, // Size of szMethod buffer in wide chars. - IntPtr pchMethod, // [OUT] Put actual size here - IntPtr pdwAttr, // [OUT] Put flags here. - IntPtr ppvSigBlob, // [OUT] point to the blob value of meta data - IntPtr pcbSigBlob, // [OUT] actual size of signature blob - IntPtr pulCodeRVA, // [OUT] codeRVA - IntPtr pdwImplFlags) // [OUT] Impl. Flags - { - if (pdwAttr != IntPtr.Zero || ppvSigBlob != IntPtr.Zero || pcbSigBlob != IntPtr.Zero || pulCodeRVA != IntPtr.Zero || pdwImplFlags != IntPtr.Zero) - { - throw new NotImplementedException(); - } - MethodBase method = methodMap[reversemap[mb]]; - WriteToken(pClass, method.DeclaringType); - WriteString(szMethod, pchMethod, method.Name, cchMethod); - } - - public void PlaceHolder_GetMemberRefProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumProperties() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumEvents() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetEventProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumMethodSemantics() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetMethodSemantics() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetClassLayout() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetFieldMarshal() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetRVA() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetPermissionSetProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetSigFromToken() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetModuleRefProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumModuleRefs() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetTypeSpecFromToken() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetNameFromToken() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumUnresolvedMethods() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetUserString() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetPinvokeMap() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumSignatures() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumTypeSpecs() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumUserStrings() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetParamForMethodIndex() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_EnumCustomAttributes() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetCustomAttributeProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_FindTypeRef() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetMemberProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetFieldProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetPropertyProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetParamProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetCustomAttributeByName() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_IsValidToken() - { - throw new NotImplementedException(); - } - - public void GetNestedClassProps( - int tdNestedClass, // [IN] NestedClass token. - IntPtr ptdEnclosingClass) // [OUT] EnclosingClass token. - { - Type type = moduleBuilder.ResolveType(tdNestedClass); - WriteToken(ptdEnclosingClass, type.DeclaringType); - } - - public void PlaceHolder_GetNativeCallConvFromSig() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_IsGlobal() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetModuleProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_Save() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SaveToStream() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetSaveSize() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineTypeDef() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineNestedType() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetHandler() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineMethod() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineMethodImpl() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineTypeRefByName() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineImportType() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineMemberRef() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineImportMember() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineEvent() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetClassLayout() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DeleteClassLayout() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetFieldMarshal() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DeleteFieldMarshal() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefinePermissionSet() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetRVA() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetTokenFromSig() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineModuleRef() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetParent() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_GetTokenFromTypeSpec() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SaveToMemory() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineUserString() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DeleteToken() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetMethodProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetTypeDefProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetEventProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetPermissionSetProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefinePinvokeMap() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetPinvokeMap() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DeletePinvokeMap() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineCustomAttribute() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetCustomAttributeValue() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineField() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineProperty() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineParam() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetFieldProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetPropertyProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetParamProps() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_DefineSecurityAttributeSet() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_ApplyEditAndContinue() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_TranslateSigWithScope() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetMethodImplFlags() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_SetFieldRVA() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_Merge() - { - throw new NotImplementedException(); - } - - public void PlaceHolder_MergeEnd() - { - throw new NotImplementedException(); - } - - public bool IsDeterministic - { - get { return false; } - } } } diff --git a/src/IKVM.Reflection/Impl/PortablePdbWriter.cs b/src/IKVM.Reflection/Impl/PortablePdbWriter.cs new file mode 100644 index 0000000000..902bdfcf4b --- /dev/null +++ b/src/IKVM.Reflection/Impl/PortablePdbWriter.cs @@ -0,0 +1,257 @@ +#if NETCOREAPP + +using IKVM.Reflection.Emit; +using IKVM.Reflection.Writer; +using System; +using System.Collections.Immutable; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.InteropServices; +using System.Text; + +namespace IKVM.Reflection.Impl +{ + sealed class PortablePdbWriter : AbstractPdbWriter, ISymbolWriterImpl + { + + private Guid guid = Guid.NewGuid(); + private uint timestamp = (uint)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; + + public PortablePdbWriter(ModuleBuilder moduleBuilder) : base(moduleBuilder) + { + } + + private string PdbPath => System.IO.Path.ChangeExtension(moduleBuilder.FullyQualifiedName, ".pdb"); + + public override void Close() + { + var metadataBuilder = new MetadataBuilder(); + + var sortedMethods = new (Method method, MethodBase methodBase)[moduleBuilder.MethodDef.RowCount + 1]; // 1-based + + foreach (var tuple in methods.Select(m => + { + int remappedToken = m.token; + remap.TryGetValue(remappedToken, out remappedToken); + + var methodBase = methodMap[m.token]; + + return (m, methodBase); + })) + { + sortedMethods[tuple.methodBase.RowNumber] = tuple; + } + + // By spec doc: + // > MethodDebugInformation table is either empty (missing) or has exactly as many rows as MethodDef table + // https://github.com/dotnet/runtime/blob/main/docs/design/specs/PortablePdb-Metadata.md#methoddebuginformation-table-0x31 + // + // So we need to write MethodDebugInformation in exactly the same order as MethodDef table + for (int i = 1; i <= moduleBuilder.MethodDef.RowCount; i++) + { + var methodDef = MetadataTokens.MethodDefinitionHandle(i); + var method = sortedMethods[i].method; + var methodBase = sortedMethods[i].methodBase; + + if (method?.document != null) + { + DocumentHandle doc = GetUnmanagedDocument(metadataBuilder, method.document); + metadataBuilder.AddMethodDebugInformation(doc, MakeSequencePoints(metadataBuilder, method)); + } + else + { + metadataBuilder.AddMethodDebugInformation(default, default); + } + + if (method != null) + { + foreach (Scope scope in method.scopes) + { + WriteScope(metadataBuilder, methodDef, scope); + } + } + } + + var serializer = new PortablePdbBuilder( + metadataBuilder, + ImmutableArray.CreateRange(Enumerable.Repeat(0, MetadataTokens.TableCount)), + new MethodDefinitionHandle(), + blob => new BlobContentId(guid, timestamp) + ); + BlobBuilder blobBuilder = new BlobBuilder(); + serializer.Serialize(blobBuilder); + + using (FileStream fs = File.Open(PdbPath, FileMode.OpenOrCreate)) + { + blobBuilder.WriteContentTo(fs); + } + + documents.Clear(); + methods.Clear(); + remap.Clear(); + reversemap.Clear(); + } + + private BlobHandle GetMethodSignature(MetadataBuilder builder, MethodBase methodInfo) + { + var buffer = new ByteBuffer(16); + methodInfo.MethodSignature.WriteSig(moduleBuilder, buffer); + return builder.GetOrAddBlob(buffer.ToArray()); + } + + private static ParameterHandle GetParameterList(MetadataBuilder builder, MethodBase methodInfo) + { + ParameterHandle firstHandle = default; + int index = 1; + foreach (var parameter in methodInfo.GetParameters()) + { + var handle = builder.AddParameter(System.Reflection.ParameterAttributes.None, builder.GetOrAddString(parameter.Name ?? ""), index); + if (firstHandle.IsNil) + { + firstHandle = handle; + } + index++; + } + return firstHandle; + } + + private void WriteScope(MetadataBuilder builder, MethodDefinitionHandle methodDef, Scope scope) + { + builder.AddLocalScope( + method: methodDef, + importScope: default, + variableList: MakeLocalVariables(builder, scope), + constantList: default, + startOffset: scope.startOffset, + length: scope.endOffset - scope.startOffset + ); + + // By spec doc: + // > The table is required to be sorted first by Method in ascending order, then by StartOffset in ascending order, then by Length in descending order. + // https://github.com/dotnet/runtime/blob/main/docs/design/specs/PortablePdb-Metadata.md#localscope-table-0x32 + foreach (var child in scope.scopes.OrderBy(s => s.startOffset).ThenByDescending(s => s.endOffset - s.startOffset)) + { + WriteScope(builder, methodDef, child); + } + } + + private LocalVariableHandle MakeLocalVariables(MetadataBuilder builder, Scope scope) + { + LocalVariableHandle firstHandle = default; + foreach (var (name, local) in scope.locals.OrderBy(kv => kv.Value.addr1).Select(kv => (kv.Key, kv.Value))) + { + Debug.Assert(local.addrKind == System.Diagnostics.SymbolStore.SymAddressKind.ILOffset); + var handle = builder.AddLocalVariable(LocalVariableAttributes.None, local.addr1, builder.GetOrAddString(name)); + if (firstHandle.IsNil) + { + firstHandle = handle; + } + } + return firstHandle; + } + + private BlobHandle MakeSequencePoints(MetadataBuilder builder, Method method) + { + // https://github.com/dotnet/runtime/blob/main/docs/design/specs/PortablePdb-Metadata.md#sequence-points-blob + var writer = new BlobBuilder(); + + // header: + // LocalSignature + writer.WriteCompressedInteger(0); // Omit for now? + + // Java does not have partial methods so initial document is not needed. + + var length = method.offsets.Length; + Debug.Assert(method.lines.Length == length); + Debug.Assert(method.columns.Length == length); + Debug.Assert(method.endLines.Length == length); + Debug.Assert(method.endColumns.Length == length); + + // Java does not have hidden sequence points so we can solely rely on previous entry. + + for (int i = 0; i < length; i++) + { + // ILOffset + if (i == 0) + { + writer.WriteCompressedInteger(method.offsets[i]); + } + else + { + writer.WriteCompressedInteger(method.offsets[i] - method.offsets[i - 1]); + } + + // Lines + writer.WriteCompressedInteger(method.endLines[i] - method.lines[i]); + + // Columns + if (method.endLines[i] - method.lines[i] == 0) + { + writer.WriteCompressedInteger(method.endColumns[i] - method.columns[i]); + } + else + { + writer.WriteCompressedSignedInteger(method.endColumns[i] - method.columns[i]); + } + + // StartLine & StartColumn + if (i == 0) + { + writer.WriteCompressedInteger(method.lines[i]); + writer.WriteCompressedInteger(method.columns[i]); + } + else + { + writer.WriteCompressedSignedInteger(method.lines[i] - method.lines[i - 1]); + writer.WriteCompressedSignedInteger(method.columns[i] - method.columns[i - 1]); + } + } + + return builder.GetOrAddBlob(writer); + } + + private DocumentHandle GetUnmanagedDocument(MetadataBuilder builder, Document document) + { + string name = document.url; + Guid language = document.language; + + return builder.AddDocument( + name: builder.GetOrAddDocumentName(name), + hashAlgorithm: builder.GetOrAddGuid(default), + hash: default, + language: builder.GetOrAddGuid(language)); + } + + public override byte[] GetDebugInfo(ref IMAGE_DEBUG_DIRECTORY idd) + { + // https://github.com/dotnet/runtime/blob/main/docs/design/specs/PE-COFF.md#codeview-debug-directory-entry-type-2 + + idd.TimeDateStamp = timestamp; + idd.MajorVersion = 0; + idd.MinorVersion = 0x504d; + idd.Type = 2; + + Span signature = stackalloc byte[] { 0x52, 0x53, 0x44, 0x53 }; + Span guid = this.guid.ToByteArray(); + Span age = stackalloc byte[4] { 1, 0, 0, 0 }; + Span path = Encoding.UTF8.GetBytes(PdbPath); + + idd.SizeOfData = 4 + 16 + 4 + (uint)path.Length + 1; + byte[] buf = new byte[idd.SizeOfData]; + + Span b = buf; + signature.CopyTo(b); + guid.CopyTo(b[4..]); + age.CopyTo(b[20..]); + path.CopyTo(b[24..]); + b[(int)idd.SizeOfData - 1] = 0; + + return buf; + } + } +} + +#endif diff --git a/src/IKVM.Reflection/Impl/SymbolSupport.cs b/src/IKVM.Reflection/Impl/SymbolSupport.cs index be378a9682..5a4a5f106f 100644 --- a/src/IKVM.Reflection/Impl/SymbolSupport.cs +++ b/src/IKVM.Reflection/Impl/SymbolSupport.cs @@ -37,6 +37,8 @@ internal static ISymbolWriterImpl CreateSymbolWriterFor(ModuleBuilder moduleBuil { #if NETFRAMEWORK return new PdbWriter(moduleBuilder); +#elif NETCOREAPP + return new PortablePdbWriter(moduleBuilder); #else throw new NotSupportedException("IKVM.Reflection must be compiled with MONO defined to support writing Mono debugging symbols."); #endif diff --git a/src/IKVM.Reflection/MethodBase.cs b/src/IKVM.Reflection/MethodBase.cs index a4b6fd1640..bc40f1048d 100644 --- a/src/IKVM.Reflection/MethodBase.cs +++ b/src/IKVM.Reflection/MethodBase.cs @@ -44,6 +44,11 @@ internal MethodBase() public abstract CallingConventions CallingConvention { get; } public abstract int __MethodRVA { get; } + /// + /// MethodDef table row number in the written PE image + /// + internal int RowNumber { get; set; } = 0; + public bool IsConstructor { get diff --git a/src/IKVM.Reflection/Writer/MetadataWriter.cs b/src/IKVM.Reflection/Writer/MetadataWriter.cs index 28f7a0bf60..1d503e7c96 100644 --- a/src/IKVM.Reflection/Writer/MetadataWriter.cs +++ b/src/IKVM.Reflection/Writer/MetadataWriter.cs @@ -37,6 +37,8 @@ sealed class MetadataWriter : MetadataRW readonly Stream stream; readonly byte[] buffer = new byte[8]; + private int methodDefRow = 0; + /// /// Initializes a new instance. /// @@ -430,6 +432,10 @@ internal void WriteHasFieldMarshal(int token) Write((short)encodedToken); } - } + internal int GetNewMethodDefRowId() + { + return ++methodDefRow; + } + } } diff --git a/src/IKVM.Reflection/Writer/ModuleWriter.cs b/src/IKVM.Reflection/Writer/ModuleWriter.cs index f17ba0b8be..67849e08d2 100644 --- a/src/IKVM.Reflection/Writer/ModuleWriter.cs +++ b/src/IKVM.Reflection/Writer/ModuleWriter.cs @@ -338,13 +338,11 @@ static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, ModuleB if (keyPair != null) StrongName(stream, keyPair, writer.HeaderSize, text.PointerToRawData, code.StrongNameSignatureRVA - text.VirtualAddress + text.PointerToRawData, code.StrongNameSignatureLength); -#if NETFRAMEWORK if (moduleBuilder.symbolWriter != null) { moduleBuilder.WriteSymbolTokenMap(); moduleBuilder.symbolWriter.Close(); } -#endif } static int ComputeStrongNameSignatureLength(byte[] publicKey) diff --git a/src/IKVM.Reflection/Writer/TextSection.cs b/src/IKVM.Reflection/Writer/TextSection.cs index 8acd4165f4..b15ad333d9 100644 --- a/src/IKVM.Reflection/Writer/TextSection.cs +++ b/src/IKVM.Reflection/Writer/TextSection.cs @@ -108,13 +108,11 @@ uint DebugDirectoryContentsLength { get { -#if NETFRAMEWORK if (moduleBuilder.symbolWriter != null) { var idd = new IMAGE_DEBUG_DIRECTORY(); return (uint)SymbolSupport.GetDebugInfo(moduleBuilder.symbolWriter, ref idd).Length; } -#endif return 0; } @@ -357,9 +355,8 @@ void WriteDebugDirectory(MetadataWriter mw) { if (DebugDirectoryLength != 0) { -#if NETFRAMEWORK IMAGE_DEBUG_DIRECTORY idd = new IMAGE_DEBUG_DIRECTORY(); - idd.Characteristics = 0; + idd.Characteristics = 0; idd.TimeDateStamp = peWriter.Headers.FileHeader.TimeDateStamp; byte[] buf = SymbolSupport.GetDebugInfo(moduleBuilder.symbolWriter, ref idd); idd.PointerToRawData = (DebugDirectoryRVA - BaseRVA) + DebugDirectoryLength + PointerToRawData; @@ -373,9 +370,6 @@ void WriteDebugDirectory(MetadataWriter mw) mw.Write(idd.AddressOfRawData); mw.Write(idd.PointerToRawData); mw.Write(buf); -#else - throw new NotSupportedException(); -#endif } } diff --git a/src/IKVM.Runtime/CodeEmitter.cs b/src/IKVM.Runtime/CodeEmitter.cs index 4968af995a..b057f38ad9 100644 --- a/src/IKVM.Runtime/CodeEmitter.cs +++ b/src/IKVM.Runtime/CodeEmitter.cs @@ -110,9 +110,7 @@ sealed class CodeEmitter #endif IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter linenums; CodeEmitterLocal[] tempLocals = new CodeEmitterLocal[32]; -#if NETFRAMEWORK ISymbolDocumentWriter symbols; -#endif List code = new List(10); readonly Type declaringType; #if LABELCHECK @@ -480,8 +478,8 @@ private void RealEmitPseudoOpCode(int ilOffset, CodeType type, object data) case CodeType.ReleaseTempLocal: break; case CodeType.SequencePoint: +#if NETFRAMEWORK || IMPORTER // MarkSequencePoint does not exist in .net core -#if NETFRAMEWORK ilgen_real.MarkSequencePoint(symbols, (int)data, 0, (int)data + 1, 0); #endif // we emit a nop to make sure we always have an instruction associated with the sequence point @@ -2350,7 +2348,7 @@ internal void DumpMethod() internal void DefineSymbolDocument(ModuleBuilder module, string url, Guid language, Guid languageVendor, Guid documentType) { -#if NETFRAMEWORK +#if NETFRAMEWORK || IMPORTER symbols = module.DefineDocument(url, language, languageVendor, documentType); #endif } @@ -2676,12 +2674,10 @@ internal void ThrowException(Type excType) internal void SetLineNumber(ushort line) { -#if NETFRAMEWORK if (symbols != null) { EmitPseudoOpCode(CodeType.SequencePoint, (int)line); } -#endif EmitPseudoOpCode(CodeType.LineNumber, (int)line); } diff --git a/src/IKVM.Runtime/CodeEmitterLocal.cs b/src/IKVM.Runtime/CodeEmitterLocal.cs index 3005afa572..fce61a906b 100644 --- a/src/IKVM.Runtime/CodeEmitterLocal.cs +++ b/src/IKVM.Runtime/CodeEmitterLocal.cs @@ -76,13 +76,13 @@ internal void Declare(ILGenerator ilgen) local = ilgen.DeclareLocal(type); if (name != null) { -#if NETFRAMEWORK +#if NETFRAMEWORK || IMPORTER // SetLocalSymInfo does not exist in .net core local.SetLocalSymInfo(name); #endif - } + } - } + } }