From 35bccd70ac7f019a0a66a9d3483c648369f89050 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Tue, 9 Jan 2024 18:45:52 -0600 Subject: [PATCH 01/10] Space. --- src/IKVM.Reflection/Emit/ModuleBuilder.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/IKVM.Reflection/Emit/ModuleBuilder.cs b/src/IKVM.Reflection/Emit/ModuleBuilder.cs index cfcf853a15..7acf4ba6f3 100644 --- a/src/IKVM.Reflection/Emit/ModuleBuilder.cs +++ b/src/IKVM.Reflection/Emit/ModuleBuilder.cs @@ -850,6 +850,7 @@ internal int ImportMethodSpec(Type declaringType, MethodInfo method, Type[] gene // (in order words the method and type have already been decoupled by the caller) rec.Method = ImportMethodOrField(declaringType, method.Name, method.MethodSignature); } + var spec = new ByteBuffer(10); Signature.WriteMethodSpec(this, spec, genericParameters); rec.Instantiation = Blobs.Add(spec); From 90d16558ca7f969e22135f89fb52dc66f4496364 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sat, 13 Jan 2024 08:47:46 -0600 Subject: [PATCH 02/10] Replace writing with SRME. --- src/IKVM.Reflection/Writer/ModuleWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IKVM.Reflection/Writer/ModuleWriter.cs b/src/IKVM.Reflection/Writer/ModuleWriter.cs index f17ba0b8be..d74adf0c7c 100644 --- a/src/IKVM.Reflection/Writer/ModuleWriter.cs +++ b/src/IKVM.Reflection/Writer/ModuleWriter.cs @@ -77,7 +77,7 @@ static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, ModuleB moduleBuilder.FixupMethodBodyTokens(); int moduleVersionIdIndex = moduleBuilder.Guids.Add(moduleBuilder.GetModuleVersionIdOrEmpty()); - moduleBuilder.ModuleTable.Add(0, moduleBuilder.Strings.Add(moduleBuilder.moduleName), moduleVersionIdIndex, 0, 0); + moduleBuilder.Metadata.GetOrAddUserString(""); if (moduleBuilder.UserStrings.IsEmpty) { From 8df14ddb8246a00cdc52a9d0338ddfddde513424 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sat, 13 Jan 2024 08:47:57 -0600 Subject: [PATCH 03/10] Replace writing with SRME. --- .../ModuleWriterTests.cs | 18 +- src/IKVM.Reflection/CustomAttributeData.cs | 8 +- src/IKVM.Reflection/Emit/AssemblyBuilder.cs | 69 +- .../Emit/CustomAttributeBuilder.cs | 29 +- src/IKVM.Reflection/Emit/EventBuilder.cs | 21 +- src/IKVM.Reflection/Emit/FieldBuilder.cs | 26 +- .../Emit/GenericTypeParameterBuilder.cs | 13 +- src/IKVM.Reflection/Emit/ILGenerator.cs | 6 +- src/IKVM.Reflection/Emit/MethodBuilder.cs | 49 +- src/IKVM.Reflection/Emit/ModuleBuilder.cs | 630 ++++----- src/IKVM.Reflection/Emit/ParameterBuilder.cs | 16 +- src/IKVM.Reflection/Emit/PropertyBuilder.cs | 5 +- src/IKVM.Reflection/Emit/TypeBuilder.cs | 53 +- src/IKVM.Reflection/FieldMarshal.cs | 8 +- src/IKVM.Reflection/IKVM.Reflection.csproj | 1 + .../Metadata/AssemblyRefTable.cs | 57 +- src/IKVM.Reflection/Metadata/AssemblyTable.cs | 51 +- .../Metadata/ClassLayoutTable.cs | 57 +- src/IKVM.Reflection/Metadata/CliHeader.cs | 16 - src/IKVM.Reflection/Metadata/ConstantTable.cs | 41 +- .../Metadata/CustomAttributeTable.cs | 103 +- .../Metadata/DeclSecurityTable.cs | 81 +- src/IKVM.Reflection/Metadata/EventMapTable.cs | 55 +- src/IKVM.Reflection/Metadata/EventTable.cs | 65 +- .../Metadata/ExportedTypeTable.cs | 43 +- .../Metadata/FieldLayoutTable.cs | 63 +- .../Metadata/FieldMarshalTable.cs | 27 +- src/IKVM.Reflection/Metadata/FieldRVATable.cs | 25 +- src/IKVM.Reflection/Metadata/FieldTable.cs | 47 +- src/IKVM.Reflection/Metadata/FileTable.cs | 68 +- .../Metadata/GenericParamConstraintTable.cs | 71 +- .../Metadata/GenericParamTable.cs | 129 +- src/IKVM.Reflection/Metadata/ImplMapTable.cs | 78 +- .../Metadata/InterfaceImplTable.cs | 119 +- .../Metadata/ManifestResourceTable.cs | 33 +- .../Metadata/MemberRefTable.cs | 45 +- .../Metadata/MethodDefTable.cs | 36 +- .../Metadata/MethodImplTable.cs | 78 +- .../Metadata/MethodSemanticsTable.cs | 182 ++- .../Metadata/MethodSpecTable.cs | 29 +- .../Metadata/ModuleRefTable.cs | 33 +- src/IKVM.Reflection/Metadata/ModuleTable.cs | 101 +- .../Metadata/NestedClassTable.cs | 23 +- src/IKVM.Reflection/Metadata/ParamTable.cs | 24 +- .../Metadata/PropertyMapTable.cs | 47 +- src/IKVM.Reflection/Metadata/PropertyTable.cs | 65 +- src/IKVM.Reflection/Metadata/RvaSize.cs | 6 - .../Metadata/StandAloneSigTable.cs | 27 +- src/IKVM.Reflection/Metadata/Table.cs | 189 +-- src/IKVM.Reflection/Metadata/TypeDefTable.cs | 31 +- src/IKVM.Reflection/Metadata/TypeRefTable.cs | 36 +- src/IKVM.Reflection/Metadata/TypeSpecTable.cs | 25 +- src/IKVM.Reflection/MissingModule.cs | 7 +- src/IKVM.Reflection/MissingType.cs | 21 - src/IKVM.Reflection/Module.cs | 11 +- src/IKVM.Reflection/Reader/AssemblyReader.cs | 25 +- src/IKVM.Reflection/Reader/ByteReader.cs | 382 +++--- src/IKVM.Reflection/Reader/Field.cs | 2 +- .../Reader/GenericTypeParameter.cs | 2 +- src/IKVM.Reflection/Reader/MethodDefImpl.cs | 2 +- src/IKVM.Reflection/Reader/ModuleReader.cs | 79 +- .../Reader/PropertyInfoImpl.cs | 2 +- src/IKVM.Reflection/Reader/ResourceModule.cs | 2 +- .../WindowsRuntimeProjection.cs | 581 -------- src/IKVM.Reflection/Writer/BlobHeap.cs | 117 -- src/IKVM.Reflection/Writer/ByteBuffer.cs | 5 - src/IKVM.Reflection/Writer/GuidHeap.cs | 64 - src/IKVM.Reflection/Writer/Heap.cs | 64 - src/IKVM.Reflection/Writer/MetadataWriter.cs | 395 +----- src/IKVM.Reflection/Writer/ModuleWriter.cs | 666 ++++----- src/IKVM.Reflection/Writer/PEWriter.cs | 138 -- src/IKVM.Reflection/Writer/ResourceSection.cs | 11 - src/IKVM.Reflection/Writer/SimpleHeap.cs | 45 - src/IKVM.Reflection/Writer/StringHeap.cs | 90 -- src/IKVM.Reflection/Writer/TableHeap.cs | 117 -- src/IKVM.Reflection/Writer/TextSection.cs | 1211 ++++++----------- src/IKVM.Reflection/Writer/UserStringHeap.cs | 89 -- 77 files changed, 2360 insertions(+), 4926 deletions(-) delete mode 100644 src/IKVM.Reflection/WindowsRuntimeProjection.cs delete mode 100644 src/IKVM.Reflection/Writer/BlobHeap.cs delete mode 100644 src/IKVM.Reflection/Writer/GuidHeap.cs delete mode 100644 src/IKVM.Reflection/Writer/Heap.cs delete mode 100644 src/IKVM.Reflection/Writer/PEWriter.cs delete mode 100644 src/IKVM.Reflection/Writer/SimpleHeap.cs delete mode 100644 src/IKVM.Reflection/Writer/StringHeap.cs delete mode 100644 src/IKVM.Reflection/Writer/TableHeap.cs delete mode 100644 src/IKVM.Reflection/Writer/UserStringHeap.cs diff --git a/src/IKVM.Reflection.Tests/ModuleWriterTests.cs b/src/IKVM.Reflection.Tests/ModuleWriterTests.cs index f91a56dc5a..d66d3b7da7 100644 --- a/src/IKVM.Reflection.Tests/ModuleWriterTests.cs +++ b/src/IKVM.Reflection.Tests/ModuleWriterTests.cs @@ -16,16 +16,30 @@ public class ModuleWriterTests [TestMethod] public void CanWriteNetFxModule() { - var d = Path.Combine(TestContext.TestRunResultsDirectory, "IKVM.Reflection.Tests", "ModuleWriterTests"); + var d = Path.Combine(Path.GetTempPath(), "IKVM.Reflection.Tests", "ModuleWriterTests"); if (Directory.Exists(d)) Directory.Delete(d, true); Directory.CreateDirectory(d); var u = new Universe("mscorlib"); + u.AssemblyResolve += U_AssemblyResolve; var a = u.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save, d); var m = a.DefineDynamicModule("Test", "Test.dll", false); - m.DefineType("Type"); + var t = m.DefineType("Type"); + var z = t.DefineMethod("Exec", MethodAttributes.Public, u.Import(typeof(object)), new[] { u.Import(typeof(string[])) }); + z.DefineParameter(0, ParameterAttributes.None, "args"); a.Save("Test.dll"); + TestContext.WriteLine(d); + } + + Assembly U_AssemblyResolve(object sender, ResolveEventArgs args) + { + var d = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8.1"; + var p = Path.Combine(d, args.Name + ".dll"); + if (File.Exists(p)) + return ((Universe)sender).LoadFile(p); + + return null; } [TestMethod] diff --git a/src/IKVM.Reflection/CustomAttributeData.cs b/src/IKVM.Reflection/CustomAttributeData.cs index 6f7ab4c1d3..015b460b5b 100644 --- a/src/IKVM.Reflection/CustomAttributeData.cs +++ b/src/IKVM.Reflection/CustomAttributeData.cs @@ -250,7 +250,7 @@ internal static void ReadDeclarativeSecurity(Module module, int index, List NamedArguments void LazyParseArguments(bool requireNameArguments) { - var br = module.GetBlob(module.CustomAttribute.records[customAttributeIndex].Value); + var br = module.GetBlobReader(module.CustomAttribute.records[customAttributeIndex].Value); if (br.Length == 0) { // it's legal to have an empty blob @@ -775,7 +775,7 @@ internal static List GetCustomAttributesImpl(List(); list.Add(new CustomAttributeData(module, i)); diff --git a/src/IKVM.Reflection/Emit/AssemblyBuilder.cs b/src/IKVM.Reflection/Emit/AssemblyBuilder.cs index e3ed867e28..cca8003441 100644 --- a/src/IKVM.Reflection/Emit/AssemblyBuilder.cs +++ b/src/IKVM.Reflection/Emit/AssemblyBuilder.cs @@ -24,6 +24,8 @@ Jeroen Frijters using System; using System.Collections.Generic; using System.IO; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Resources; using System.Security.Cryptography; @@ -330,24 +332,35 @@ public void Save(string assemblyFileName, PortableExecutableKinds portableExecut SaveImpl(assemblyFileName, null, portableExecutableKind, imageFileMachine); } + /// + /// Implements the logic to save all of the modules within the assembly. + /// + /// + /// + /// + /// void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine) { ModuleBuilder manifestModule = null; + // finalize and populate all modules foreach (var moduleBuilder in modules) { moduleBuilder.SetIsSaved(); moduleBuilder.PopulatePropertyAndEventTables(); + // is this the default manifest module? if (manifestModule == null && string.Compare(moduleBuilder.fileName, assemblyFileName, StringComparison.OrdinalIgnoreCase) == 0) manifestModule = moduleBuilder; } + // generate new manifest module manifestModule ??= DefineDynamicModule("RefEmit_OnDiskManifestModule", assemblyFileName, false); + // assembly record goes on manifest module var assemblyRecord = new AssemblyTable.Record(); assemblyRecord.HashAlgId = (int)hashAlgorithm; - assemblyRecord.Name = manifestModule.Strings.Add(name); + assemblyRecord.Name = manifestModule.GetOrAddString(name); assemblyRecord.MajorVersion = majorVersion; assemblyRecord.MinorVersion = minorVersion; assemblyRecord.BuildNumber = buildVersion; @@ -355,7 +368,7 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi if (publicKey != null) { - assemblyRecord.PublicKey = manifestModule.Blobs.Add(ByteBuffer.Wrap(publicKey)); + assemblyRecord.PublicKey = manifestModule.GetOrAddBlob(publicKey); assemblyRecord.Flags = (int)(flags | AssemblyNameFlags.PublicKey); } else @@ -364,9 +377,8 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi } if (culture != null) - { - assemblyRecord.Culture = manifestModule.Strings.Add(culture); - } + assemblyRecord.Culture = manifestModule.GetOrAddString(culture); + manifestModule.AssemblyTable.AddRecord(assemblyRecord); var unmanagedResources = versionInfo != null || win32icon != null || win32manifest != null || win32resources != null ? new ResourceSection() : null; @@ -381,6 +393,7 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi if (!cab.HasBlob || universe.DecodeVersionInfoAttributeBlobs) versionInfo.SetAttribute(this, cab); } + var versionInfoData = new ByteBuffer(512); versionInfo.Write(versionInfoData); unmanagedResources.AddVersionInfo(versionInfoData); @@ -395,11 +408,9 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi if (win32resources != null) unmanagedResources.ExtractResources(win32resources); + // we intentionally don't filter out the version info (pseudo) custom attributes (to be compatible with .NET) foreach (var cab in customAttributes) - { - // we intentionally don't filter out the version info (pseudo) custom attributes (to be compatible with .NET) manifestModule.SetCustomAttribute(0x20000001, cab); - } manifestModule.AddDeclarativeSecurity(0x20000001, declarativeSecurity); @@ -414,16 +425,16 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi resfile.Writer.Close(); } - int fileToken = AddFile(manifestModule, resfile.FileName, 1 /*ContainsNoMetaData*/); + var fileToken = AddFile(manifestModule, resfile.FileName, 1 /*ContainsNoMetaData*/); var rec = new ManifestResourceTable.Record(); rec.Offset = 0; rec.Flags = (int)resfile.Attributes; - rec.Name = manifestModule.Strings.Add(resfile.Name); - rec.Implementation = fileToken; + rec.Name = manifestModule.GetOrAddString(resfile.Name); + rec.Implementation = MetadataTokens.GetToken(fileToken); manifestModule.ManifestResource.AddRecord(rec); } - int entryPointToken = 0; + var entryPointToken = MetadataTokens.MethodDefinitionHandle(0); foreach (var moduleBuilder in modules) { @@ -432,15 +443,14 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi if (moduleBuilder != manifestModule) { - int fileToken; + var fileToken = default(AssemblyFileHandle); if (entryPoint != null && entryPoint.Module == moduleBuilder) { - ModuleWriter.WriteModule(null, null, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, moduleBuilder.unmanagedResources, entryPoint.MetadataToken); - entryPointToken = fileToken = AddFile(manifestModule, moduleBuilder.fileName, 0 /*ContainsMetaData*/); + throw new NotSupportedException("Multi-module assemblies cannot have an entry point in a module other than the manifest module."); } else { - ModuleWriter.WriteModule(null, null, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, moduleBuilder.unmanagedResources, 0); + ModuleWriter.WriteModule(null, null, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, moduleBuilder.unmanagedResources, default); fileToken = AddFile(manifestModule, moduleBuilder.fileName, 0 /*ContainsMetaData*/); } @@ -452,31 +462,28 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi foreach (var module in addedModules) { - int fileToken = AddFile(manifestModule, module.FullyQualifiedName, 0 /*ContainsMetaData*/); + var fileToken = AddFile(manifestModule, module.FullyQualifiedName, 0 /*ContainsMetaData*/); module.ExportTypes(fileToken, manifestModule); } - if (entryPointToken == 0 && entryPoint != null) - entryPointToken = entryPoint.MetadataToken; + if (entryPointToken.IsNil && entryPoint != null) + entryPointToken = MetadataTokens.MethodDefinitionHandle(entryPoint.MetadataToken); // finally, write the manifest module ModuleWriter.WriteModule(keyPair, publicKey, manifestModule, fileKind, portableExecutableKind, imageFileMachine, unmanagedResources ?? manifestModule.unmanagedResources, entryPointToken, streamOrNull); } - int AddFile(ModuleBuilder manifestModule, string fileName, int flags) + AssemblyFileHandle AddFile(ModuleBuilder manifestModule, string fileName, int flags) { - string fullPath = fileName; + var fullPath = fileName; if (dir != null) - { fullPath = Path.Combine(dir, fileName); - } - byte[] hash; - using (SHA1 sha1 = SHA1.Create()) - using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.Read)) - { - hash = sha1.ComputeHash(fs); - } - return manifestModule.__AddModule(flags, Path.GetFileName(fileName), hash); + + using var sha1 = SHA1.Create(); + using var fs = new FileStream(fullPath, FileMode.Open, FileAccess.Read); + var hash = sha1.ComputeHash(fs); + + return MetadataTokens.AssemblyFileHandle(manifestModule.__AddModule(flags, Path.GetFileName(fileName), hash)); } public void AddResourceFile(string name, string fileName) @@ -486,7 +493,7 @@ public void AddResourceFile(string name, string fileName) public void AddResourceFile(string name, string fileName, ResourceAttributes attribs) { - ResourceFile resfile = new ResourceFile(); + var resfile = new ResourceFile(); resfile.Name = name; resfile.FileName = fileName; resfile.Attributes = attribs; diff --git a/src/IKVM.Reflection/Emit/CustomAttributeBuilder.cs b/src/IKVM.Reflection/Emit/CustomAttributeBuilder.cs index 2fb11e456f..3d9c071c14 100644 --- a/src/IKVM.Reflection/Emit/CustomAttributeBuilder.cs +++ b/src/IKVM.Reflection/Emit/CustomAttributeBuilder.cs @@ -24,6 +24,8 @@ Jeroen Frijters using System; using System.Collections.Generic; using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Text; using IKVM.Reflection.Writer; @@ -517,7 +519,7 @@ internal ConstructorInfo Constructor get { return con; } } - internal int WriteBlob(ModuleBuilder moduleBuilder) + internal BlobHandle WriteBlob(ModuleBuilder moduleBuilder) { ByteBuffer bb; if (blob != null) @@ -527,10 +529,11 @@ internal int WriteBlob(ModuleBuilder moduleBuilder) else { bb = new ByteBuffer(100); - BlobWriter bw = new BlobWriter(moduleBuilder.Assembly, this, bb); + var bw = new BlobWriter(moduleBuilder.Assembly, this, bb); bw.WriteCustomAttributeBlob(); } - return moduleBuilder.Blobs.Add(bb); + + return moduleBuilder.GetOrAddBlob(bb.ToArray()); } internal object GetConstructorArgument(int pos) @@ -599,15 +602,15 @@ internal bool IsLegacyDeclSecurity } } - internal int WriteLegacyDeclSecurityBlob(ModuleBuilder moduleBuilder) + internal BlobHandle WriteLegacyDeclSecurityBlob(ModuleBuilder moduleBuilder) { if (blob != null) { - return moduleBuilder.Blobs.Add(ByteBuffer.Wrap(blob)); + return moduleBuilder.GetOrAddBlob(blob); } else { - return moduleBuilder.Blobs.Add(ByteBuffer.Wrap(Encoding.Unicode.GetBytes((string)propertyValues[0]))); + return moduleBuilder.GetOrAddBlob(Encoding.Unicode.GetBytes((string)propertyValues[0])); } } @@ -629,28 +632,22 @@ internal CustomAttributeData ToData(Assembly asm) if (blob != null) { if (constructorArgs != null) - { return new CustomAttributeData(asm, con, (int)constructorArgs[0], blob, -1); - } + return new CustomAttributeData(asm, con, new IKVM.Reflection.Reader.ByteReader(blob, 0, blob.Length)); } else { var namedArgs = new List(); + if (namedProperties != null) - { for (int i = 0; i < namedProperties.Length; i++) - { namedArgs.Add(new CustomAttributeNamedArgument(namedProperties[i], RewrapValue(namedProperties[i].PropertyType, propertyValues[i]))); - } - } + if (namedFields != null) - { for (int i = 0; i < namedFields.Length; i++) - { namedArgs.Add(new CustomAttributeNamedArgument(namedFields[i], RewrapValue(namedFields[i].FieldType, fieldValues[i]))); - } - } + var args = new List(constructorArgs.Length); var parameters = Constructor.GetParameters(); for (int i = 0; i < constructorArgs.Length; i++) diff --git a/src/IKVM.Reflection/Emit/EventBuilder.cs b/src/IKVM.Reflection/Emit/EventBuilder.cs index fc7d420253..7d82dfb884 100644 --- a/src/IKVM.Reflection/Emit/EventBuilder.cs +++ b/src/IKVM.Reflection/Emit/EventBuilder.cs @@ -22,6 +22,7 @@ Jeroen Frijters */ using System.Collections.Generic; +using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Metadata; @@ -31,6 +32,14 @@ namespace IKVM.Reflection.Emit public sealed class EventBuilder : EventInfo { + struct Accessor + { + + internal short Semantics; + internal MethodBuilder Method; + + } + readonly TypeBuilder typeBuilder; readonly string name; EventAttributes attributes; @@ -41,14 +50,6 @@ public sealed class EventBuilder : EventInfo readonly List accessors = new List(); int lazyPseudoToken; - struct Accessor - { - - internal short Semantics; - internal MethodBuilder Method; - - } - /// /// Initializes a new instance. /// @@ -191,9 +192,9 @@ internal void Bake() { var rec = new EventTable.Record(); rec.EventFlags = (short)attributes; - rec.Name = typeBuilder.ModuleBuilder.Strings.Add(name); + rec.Name = typeBuilder.ModuleBuilder.GetOrAddString(name); rec.EventType = eventtype; - var token = 0x14000000 | typeBuilder.ModuleBuilder.Event.AddRecord(rec); + var token = MetadataTokens.GetToken(MetadataTokens.EventDefinitionHandle(typeBuilder.ModuleBuilder.Event.AddRecord(rec))); if (lazyPseudoToken == 0) lazyPseudoToken = token; diff --git a/src/IKVM.Reflection/Emit/FieldBuilder.cs b/src/IKVM.Reflection/Emit/FieldBuilder.cs index 6f6de8ba4e..4f28c61204 100644 --- a/src/IKVM.Reflection/Emit/FieldBuilder.cs +++ b/src/IKVM.Reflection/Emit/FieldBuilder.cs @@ -22,6 +22,9 @@ Jeroen Frijters */ using System; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Metadata; using IKVM.Reflection.Writer; @@ -36,8 +39,8 @@ public sealed class FieldBuilder : FieldInfo readonly string name; readonly int pseudoToken; FieldAttributes attribs; - readonly int nameIndex; - readonly int signature; + readonly StringHandle nameIndex; + readonly BlobHandle signature; readonly FieldSignature fieldSig; /// @@ -53,11 +56,11 @@ internal FieldBuilder(TypeBuilder type, string name, Type fieldType, CustomModif this.typeBuilder = type; this.name = name; this.pseudoToken = type.ModuleBuilder.AllocPseudoToken(); - this.nameIndex = type.ModuleBuilder.Strings.Add(name); + this.nameIndex = type.ModuleBuilder.GetOrAddString(name); this.fieldSig = FieldSignature.Create(fieldType, customModifiers); - ByteBuffer sig = new ByteBuffer(5); - fieldSig.WriteSig(this.typeBuilder.ModuleBuilder, sig); - this.signature = this.typeBuilder.ModuleBuilder.Blobs.Add(sig); + var sig = new ByteBuffer(5); + fieldSig.WriteSig(typeBuilder.ModuleBuilder, sig); + this.signature = typeBuilder.ModuleBuilder.GetOrAddBlob(sig.ToArray()); this.attribs = attribs; this.typeBuilder.ModuleBuilder.Field.AddVirtualRecord(); } @@ -193,16 +196,17 @@ public FieldToken GetToken() return new FieldToken(pseudoToken); } - internal void WriteFieldRecords(MetadataWriter mw) + internal void WriteFieldRecords(MetadataBuilder metadata) { - mw.Write((short)attribs); - mw.WriteStringIndex(nameIndex); - mw.WriteBlobIndex(signature); + metadata.AddFieldDefinition( + (System.Reflection.FieldAttributes)attribs, + nameIndex, + signature); } internal void FixupToken(int token) { - typeBuilder.ModuleBuilder.RegisterTokenFixup(this.pseudoToken, token); + typeBuilder.ModuleBuilder.RegisterTokenFixup(pseudoToken, token); } internal override FieldSignature FieldSignature diff --git a/src/IKVM.Reflection/Emit/GenericTypeParameterBuilder.cs b/src/IKVM.Reflection/Emit/GenericTypeParameterBuilder.cs index 655d154ef4..918f8163a7 100644 --- a/src/IKVM.Reflection/Emit/GenericTypeParameterBuilder.cs +++ b/src/IKVM.Reflection/Emit/GenericTypeParameterBuilder.cs @@ -22,6 +22,7 @@ Jeroen Frijters */ using System; +using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Metadata; using IKVM.Reflection.Writer; @@ -80,12 +81,12 @@ internal GenericTypeParameterBuilder(string name, MethodBuilder method, int posi this.type = type; this.method = method; this.position = position; - GenericParamTable.Record rec = new GenericParamTable.Record(); + var rec = new GenericParamTable.Record(); rec.Number = (short)position; rec.Flags = 0; rec.Owner = type != null ? type.MetadataToken : method.MetadataToken; - rec.Name = this.ModuleBuilder.Strings.Add(name); - this.paramPseudoIndex = this.ModuleBuilder.GenericParam.AddRecord(rec); + rec.Name = ModuleBuilder.GetOrAddString(name); + paramPseudoIndex = ModuleBuilder.GenericParam.AddRecord(rec); } public override string AssemblyQualifiedName @@ -241,9 +242,9 @@ internal override int GetModuleBuilderToken() { if (typeToken == 0) { - ByteBuffer spec = new ByteBuffer(5); - Signature.WriteTypeSpec(this.ModuleBuilder, spec, this); - typeToken = 0x1B000000 | this.ModuleBuilder.TypeSpec.AddRecord(this.ModuleBuilder.Blobs.Add(spec)); + var spec = new ByteBuffer(5); + Signature.WriteTypeSpec(ModuleBuilder, spec, this); + typeToken = MetadataTokens.GetToken(MetadataTokens.TypeSpecificationHandle(ModuleBuilder.TypeSpec.AddRecord(ModuleBuilder.GetOrAddBlob(spec.ToArray())))); } return typeToken; } diff --git a/src/IKVM.Reflection/Emit/ILGenerator.cs b/src/IKVM.Reflection/Emit/ILGenerator.cs index 7c287e5dd0..5985f7c7f4 100644 --- a/src/IKVM.Reflection/Emit/ILGenerator.cs +++ b/src/IKVM.Reflection/Emit/ILGenerator.cs @@ -25,6 +25,7 @@ Jeroen Frijters using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.SymbolStore; +using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using IKVM.Reflection.Writer; @@ -600,9 +601,8 @@ public void Emit(OpCode opc, LocalBuilder local) void WriteToken(int token) { if (ModuleBuilder.IsPseudoToken(token)) - { tokenFixups.Add(code.Position); - } + code.Write(token); } @@ -739,7 +739,7 @@ public void __EmitCalli(OpCode opc, __StandAloneMethodSig sig) } var bb = new ByteBuffer(16); Signature.WriteStandAloneMethodSig(moduleBuilder, bb, sig); - code.Write(0x11000000 | moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.Blobs.Add(bb))); + code.Write(MetadataTokens.GetToken(MetadataTokens.StandaloneSignatureHandle(moduleBuilder.StandAloneSig.FindOrAddRecord(moduleBuilder.GetOrAddBlob(bb.ToArray()))))); } public void EmitWriteLine(string text) diff --git a/src/IKVM.Reflection/Emit/MethodBuilder.cs b/src/IKVM.Reflection/Emit/MethodBuilder.cs index 2355c7f667..01346a3aca 100644 --- a/src/IKVM.Reflection/Emit/MethodBuilder.cs +++ b/src/IKVM.Reflection/Emit/MethodBuilder.cs @@ -24,11 +24,12 @@ Jeroen Frijters using System; using System.Collections.Generic; using System.Diagnostics.SymbolStore; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using IKVM.Reflection.Metadata; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Emit { @@ -39,8 +40,8 @@ public sealed class MethodBuilder : MethodInfo readonly TypeBuilder typeBuilder; readonly string name; readonly int pseudoToken; - int nameIndex; - int signature; + StringHandle nameIndex; + BlobHandle signature; Type returnType; Type[] parameterTypes; PackedCustomModifiers customModifiers; @@ -205,8 +206,8 @@ internal void SetDllImportPseudoCustomAttribute(string dllName, string entryName var rec = new ImplMapTable.Record(); rec.MappingFlags = flags; rec.MemberForwarded = pseudoToken; - rec.ImportName = this.ModuleBuilder.Strings.Add(entryName ?? name); - rec.ImportScope = this.ModuleBuilder.ModuleRef.FindOrAddRecord(dllName == null ? 0 : this.ModuleBuilder.Strings.Add(dllName)); + rec.ImportName = ModuleBuilder.GetOrAddString(entryName ?? name); + rec.ImportScope = MetadataTokens.GetToken(MetadataTokens.ModuleReferenceHandle(ModuleBuilder.ModuleRef.FindOrAddRecord(dllName == null ? default : ModuleBuilder.GetOrAddString(dllName)))); ModuleBuilder.ImplMap.AddRecord(rec); } @@ -259,7 +260,7 @@ public void SetCustomAttribute(CustomAttributeBuilder customBuilder) attributes |= MethodAttributes.HasSecurity; goto default; default: - this.ModuleBuilder.SetCustomAttribute(pseudoToken, customBuilder); + ModuleBuilder.SetCustomAttribute(pseudoToken, customBuilder); break; } } @@ -286,15 +287,15 @@ public ParameterBuilder DefineParameter(int position, ParameterAttributes attrib { parameters ??= new List(); - this.ModuleBuilder.Param.AddVirtualRecord(); - var pb = new ParameterBuilder(this.ModuleBuilder, position, attributes, strParamName); + ModuleBuilder.Param.AddVirtualRecord(); + var pb = new ParameterBuilder(ModuleBuilder, position, attributes, strParamName); if (parameters.Count == 0 || position >= parameters[parameters.Count - 1].Position) { parameters.Add(pb); } else { - for (int i = 0; i < parameters.Count; i++) + for (var i = 0; i < parameters.Count; i++) { if (parameters[i].Position > position) { @@ -303,6 +304,7 @@ public ParameterBuilder DefineParameter(int position, ParameterAttributes attrib } } } + return pb; } @@ -642,7 +644,7 @@ public void SetMethodBody(byte[] il, int maxStack, byte[] localSignature, IEnume internal void Bake() { - nameIndex = ModuleBuilder.Strings.Add(name); + nameIndex = ModuleBuilder.GetOrAddString(name); signature = ModuleBuilder.GetSignatureBlobIndex(MethodSignature); __ReleaseILGenerator(); @@ -656,33 +658,32 @@ internal ModuleBuilder ModuleBuilder get { return typeBuilder.ModuleBuilder; } } - internal void WriteMethodDefRecord(int baseRVA, MetadataWriter mw, ref int paramList) + internal void WriteMethodDefRecord(MetadataBuilder metadata, ref int paramList) { - if (rva != -1) - mw.Write(rva + baseRVA); - else - mw.Write(0); - mw.Write((short)implFlags); - mw.Write((short)attributes); - mw.WriteStringIndex(nameIndex); - mw.WriteBlobIndex(signature); - mw.WriteParam(paramList); + metadata.AddMethodDefinition( + (System.Reflection.MethodAttributes)attributes, + (System.Reflection.MethodImplAttributes)implFlags, + nameIndex, + signature, + rva, + MetadataTokens.ParameterHandle(paramList)); + if (parameters != null) paramList += parameters.Count; } - internal void WriteParamRecords(MetadataWriter mw) + internal void WriteParamRecords(MetadataBuilder metadata) { if (parameters != null) - foreach (ParameterBuilder pb in parameters) - pb.WriteParamRecord(mw); + foreach (var pb in parameters) + pb.WriteParamRecord(metadata); } internal void FixupToken(int token, ref int parameterToken) { typeBuilder.ModuleBuilder.RegisterTokenFixup(this.pseudoToken, token); if (parameters != null) - foreach (ParameterBuilder pb in parameters) + foreach (var pb in parameters) pb.FixupToken(parameterToken++); } diff --git a/src/IKVM.Reflection/Emit/ModuleBuilder.cs b/src/IKVM.Reflection/Emit/ModuleBuilder.cs index 864ee277c0..92785905b7 100644 --- a/src/IKVM.Reflection/Emit/ModuleBuilder.cs +++ b/src/IKVM.Reflection/Emit/ModuleBuilder.cs @@ -26,11 +26,14 @@ Jeroen Frijters using System.Diagnostics; using System.Diagnostics.SymbolStore; using System.IO; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Resources; using System.Runtime.InteropServices; using IKVM.Reflection.Impl; using IKVM.Reflection.Metadata; +using IKVM.Reflection.Reader; using IKVM.Reflection.Writer; namespace IKVM.Reflection.Emit @@ -39,45 +42,6 @@ namespace IKVM.Reflection.Emit public sealed class ModuleBuilder : Module, ITypeOwner { - static readonly bool usePublicKeyAssemblyReference = false; - - Guid mvid; - uint timestamp; - long imageBaseAddress = 0x00400000; - long stackReserve = -1; - int fileAlignment = 0x200; - DllCharacteristics dllCharacteristics = DllCharacteristics.DynamicBase | DllCharacteristics.NoSEH | DllCharacteristics.NXCompat | DllCharacteristics.TerminalServerAware; - 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(); - readonly Dictionary memberRefTypeTokens = new Dictionary(); - internal readonly ByteBuffer methodBodies = new ByteBuffer(128 * 1024); - internal readonly List tokenFixupOffsets = new List(); - internal readonly ByteBuffer initializedData = new ByteBuffer(512); - internal ResourceSection unmanagedResources; - readonly Dictionary importedMemberRefs = new Dictionary(); - readonly Dictionary importedMethodSpecs = new Dictionary(); - readonly Dictionary referencedAssemblies = new Dictionary(); - List referencedAssemblyNames; - int nextPseudoToken = -1; - readonly List resolvedTokens = new List(); - internal readonly TableHeap Tables = new TableHeap(); - internal readonly StringHeap Strings = new StringHeap(); - internal readonly UserStringHeap UserStrings = new UserStringHeap(); - internal readonly GuidHeap Guids = new GuidHeap(); - internal readonly BlobHeap Blobs = new BlobHeap(); - internal readonly List vtablefixups = new List(); - internal readonly List unmanagedExports = new List(); - List interfaceImplCustomAttributes; - readonly List resourceWriters = new List(); - bool saved; - struct ResourceWriterRecord { @@ -120,21 +84,16 @@ internal readonly void Emit(ModuleBuilder mb, int offset) var rec = new ManifestResourceTable.Record(); rec.Offset = offset; rec.Flags = (int)attributes; - rec.Name = mb.Strings.Add(name); + rec.Name = mb.GetOrAddString(name); rec.Implementation = 0; mb.ManifestResource.AddRecord(rec); } internal readonly int GetLength() => 4 + (int)stream.Length; - internal readonly void Write(MetadataWriter mw) + internal readonly void Write(ModuleBuilder module) { - mw.Write((int)stream.Length); - stream.Position = 0; - var buffer = new byte[8192]; - int length; - while ((length = stream.Read(buffer, 0, buffer.Length)) != 0) - mw.Write(buffer, 0, length); + throw new NotImplementedException(); } internal readonly void Close() @@ -231,6 +190,45 @@ public bool Equals(MethodSpecKey other) } + static readonly bool usePublicKeyAssemblyReference = false; + + readonly MetadataBuilder metadata; + readonly BlobBuilder ilStream; + readonly AssemblyBuilder asm; + Guid mvid; + uint timestamp; + long imageBaseAddress = 0x00400000; + long stackReserve = -1; + int fileAlignment = 0x200; + DllCharacteristics dllCharacteristics = DllCharacteristics.DynamicBase | DllCharacteristics.NoSEH | DllCharacteristics.NXCompat | DllCharacteristics.TerminalServerAware; + 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(); + readonly Dictionary memberRefTypeTokens = new Dictionary(); + internal readonly ByteBuffer methodBodies = new ByteBuffer(128 * 1024); + internal readonly List tokenFixupOffsets = new List(); + internal readonly ByteBuffer initializedData = new ByteBuffer(512); + internal ResourceSection unmanagedResources; + readonly Dictionary importedMemberRefs = new Dictionary(); + readonly Dictionary importedMethodSpecs = new Dictionary(); + readonly Dictionary referencedAssemblies = new Dictionary(); + List referencedAssemblyNames; + int nextPseudoToken = -1; + readonly List resolvedTokens = new List(); + + internal readonly Dictionary strings = new(); + internal readonly Dictionary blobs = new(); + internal readonly List vtableFixups = new List(); + internal readonly List unmanagedExports = new List(); + List interfaceImplCustomAttributes; + readonly List resourceWriters = new List(); + bool saved; + /// /// Initializes a new instance. /// @@ -239,9 +237,14 @@ public bool Equals(MethodSpecKey other) /// /// /// - internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, bool emitSymbolInfo) : base(asm.universe) + internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, bool emitSymbolInfo) : + base(asm.universe) { - this.asm = asm; + this.metadata = new MetadataBuilder(); + this.ilStream = new BlobBuilder(); + + this.asm = asm ?? throw new ArgumentNullException(nameof(asm)); + this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); this.moduleName = moduleName; this.fileName = fileName; @@ -262,11 +265,85 @@ internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, mvid = Guid.NewGuid(); } + // add module + ModuleTable.Add(0, GetOrAddString(moduleName), metadata.GetOrAddGuid(mvid), default, default); + // must be the first record in the TypeDef table moduleType = new TypeBuilder(this, null, ""); types.Add(moduleType); } + /// + /// Gets a reference to the underlying this instance. + /// + internal MetadataBuilder Metadata => metadata; + + /// + /// Gets a reference to the for the IL stream. As of now, this data is written into the and later copied to the IL stream. + /// + internal BlobBuilder ILStream => ilStream; + + /// + /// Gets a new string handle from the metadata. + /// + /// + /// + internal StringHandle GetOrAddString(string value) + { + var h = metadata.GetOrAddString(value); + strings[h] = value; + return h; + } + + /// + /// Gets the string value of the specified handle. + /// + /// + /// + internal override string GetString(StringHandle handle) => strings.TryGetValue(handle, out var value) ? value : throw new InvalidOperationException(); + + /// + /// Gets a new blob handle from the metadata. + /// + /// + /// + internal BlobHandle GetOrAddBlob(BlobBuilder value) + { + var h = metadata.GetOrAddBlob(value); + blobs[h] = value; + return h; + } + + /// + /// Gets a new blob handle from the metadata. + /// + /// + /// + internal BlobHandle GetOrAddBlob(byte[] value) + { + var b = new BlobBuilder(); + b.WriteBytes(value); + return GetOrAddBlob(b); + } + + /// + /// Gets the blob value of the specified handle. + /// + /// + /// + internal BlobBuilder GetBlob(BlobHandle handle) => blobs.TryGetValue(handle, out var value) ? value : throw new InvalidOperationException(); + + /// + /// Gets a for the the specified handle. + /// + /// + /// + internal override ByteReader GetBlobReader(BlobHandle handle) + { + var b = GetBlob(handle).ToArray(); + return new ByteReader(b, 0, b.Length); + } + internal void PopulatePropertyAndEventTables() { // LAMESPEC the PropertyMap and EventMap tables are not required to be sorted by the CLI spec, @@ -276,31 +353,31 @@ internal void PopulatePropertyAndEventTables() type.PopulatePropertyAndEventTables(); } - internal void WriteTypeDefTable(MetadataWriter mw) + internal void WriteTypeDefTable() { int fieldList = 1; int methodList = 1; foreach (var type in types) - type.WriteTypeDefRecord(mw, ref fieldList, ref methodList); + type.WriteTypeDefRecord(metadata, ref fieldList, ref methodList); } - internal void WriteMethodDefTable(int baseRVA, MetadataWriter mw) + internal void WriteMethodDefTable() { int paramList = 1; foreach (var type in types) - type.WriteMethodDefRecords(baseRVA, mw, ref paramList); + type.WriteMethodDefRecords(metadata, ref paramList); } - internal void WriteParamTable(MetadataWriter mw) + internal void WriteParamTable() { foreach (var type in types) - type.WriteParamRecords(mw); + type.WriteParamRecords(metadata); } - internal void WriteFieldTable(MetadataWriter mw) + internal void WriteFieldTable() { foreach (var type in types) - type.WriteFieldRecords(mw); + type.WriteFieldRecords(metadata); } internal int AllocPseudoToken() @@ -442,7 +519,7 @@ internal void AddTypeForwarder(Type type, bool includeNested) if (includeNested && !type.__IsMissing) { - foreach (Type nested in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic)) + foreach (var nested in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic)) { // we export all nested types (i.e. even the private ones) // (this behavior is the same as the C# compiler) @@ -475,10 +552,10 @@ int ExportType(Type type) return 0x27000000 | ExportedType.FindOrAddRecord(rec); } - void SetTypeNameAndTypeNamespace(TypeName name, out int typeName, out int typeNamespace) + void SetTypeNameAndTypeNamespace(TypeName name, out StringHandle typeName, out StringHandle typeNamespace) { - typeName = Strings.Add(name.Name); - typeNamespace = name.Namespace == null ? 0 : Strings.Add(name.Namespace); + typeName = GetOrAddString(name.Name); + typeNamespace = name.Namespace == null ? default : GetOrAddString(name.Namespace); } public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) @@ -495,12 +572,12 @@ internal void SetCustomAttribute(int token, CustomAttributeBuilder customBuilder { var rec = new CustomAttributeTable.Record(); rec.Parent = token; - rec.Type = asm.IsWindowsRuntime ? customBuilder.Constructor.ImportTo(this) : GetConstructorToken(customBuilder.Constructor).Token; + rec.Constructor = asm.IsWindowsRuntime ? customBuilder.Constructor.ImportTo(this) : GetConstructorToken(customBuilder.Constructor).Token; rec.Value = customBuilder.WriteBlob(this); CustomAttribute.AddRecord(rec); } - private void AddDeclSecurityRecord(int token, int action, int blob) + void AddDeclSecurityRecord(int token, int action, BlobHandle blob) { var rec = new DeclSecurityTable.Record(); rec.Action = (short)action; @@ -511,7 +588,7 @@ private void AddDeclSecurityRecord(int token, int action, int blob) internal void AddDeclarativeSecurity(int token, System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet) { - AddDeclSecurityRecord(token, (int)securityAction, Blobs.Add(ByteBuffer.Wrap(System.Text.Encoding.Unicode.GetBytes(permissionSet.ToXml().ToString())))); + AddDeclSecurityRecord(token, (int)securityAction, GetOrAddBlob(System.Text.Encoding.Unicode.GetBytes(permissionSet.ToXml().ToString()))); } internal void AddDeclarativeSecurity(int token, List declarativeSecurity) @@ -549,7 +626,7 @@ internal void AddDeclarativeSecurity(int token, List dec AddDeclSecurityRecord(token, kv.Key, WriteDeclSecurityBlob(kv.Value)); } - int WriteDeclSecurityBlob(List list) + BlobHandle WriteDeclSecurityBlob(List list) { var namedArgs = new ByteBuffer(100); var bb = new ByteBuffer(list.Count * 100); @@ -564,7 +641,7 @@ int WriteDeclSecurityBlob(List list) bb.Write(namedArgs); } - return Blobs.Add(bb); + return GetOrAddBlob(bb.ToArray()); } public void DefineManifestResource(string name, Stream stream, ResourceAttributes attribute) @@ -598,17 +675,20 @@ internal void EmitResources() } } - internal void WriteResources(MetadataWriter mw) + internal void WriteResources() { int offset = 0; + foreach (var rwr in resourceWriters) { - // resources must be 8-byte aligned - int alignment = ((offset + 7) & ~7) - offset; - for (int i = 0; i < alignment; i++) - mw.Write((byte)0); - rwr.Write(mw); - offset += rwr.GetLength() + alignment; + throw new NotImplementedException(); + + //// resources must be 8-byte aligned + //int alignment = ((offset + 7) & ~7) - offset; + //for (int i = 0; i < alignment; i++) + // mw.Write((byte)0); + //rwr.Write(mw); + //offset += rwr.GetLength() + alignment; } } @@ -700,14 +780,14 @@ internal int GetTypeTokenForMemberRef(Type type) { var spec = new ByteBuffer(5); Signature.WriteTypeSpec(this, spec, type); - token = 0x1B000000 | this.TypeSpec.AddRecord(this.Blobs.Add(spec)); + token = MetadataTokens.GetToken(MetadataTokens.TypeSpecificationHandle(TypeSpec.AddRecord(GetOrAddBlob(spec.ToArray())))); memberRefTypeTokens.Add(type, token); } return token; } else if (type.IsModulePseudoType) { - return 0x1A000000 | this.ModuleRef.FindOrAddRecord(this.Strings.Add(type.Module.ScopeName)); + return MetadataTokens.GetToken(MetadataTokens.ModuleReferenceHandle(ModuleRef.FindOrAddRecord(GetOrAddString(type.Module.ScopeName)))); } else { @@ -758,9 +838,9 @@ public MethodToken __GetMethodToken(MethodInfo method, Type[] optionalParameterT var record = new MemberRefTable.Record(); record.Class = method.Module == this ? method.MetadataToken : GetTypeTokenForMemberRef(method.DeclaringType ?? method.Module.GetModuleType()); - record.Name = Strings.Add(method.Name); - record.Signature = Blobs.Add(sig); - return new MethodToken(0x0A000000 | MemberRef.FindOrAddRecord(record)); + record.Name = GetOrAddString(method.Name); + record.Signature = GetOrAddBlob(sig.ToArray()); + return new MethodToken(MetadataTokens.GetToken(MetadataTokens.MemberReferenceHandle(MemberRef.FindOrAddRecord(record)))); } // when we refer to a method on a generic type definition in the IL stream, @@ -803,11 +883,11 @@ internal int ImportMethodOrField(Type declaringType, string name, Signature sig) { var rec = new MemberRefTable.Record(); rec.Class = GetTypeTokenForMemberRef(declaringType); - rec.Name = Strings.Add(name); + rec.Name = GetOrAddString(name); var bb = new ByteBuffer(16); sig.WriteSig(this, bb); - rec.Signature = Blobs.Add(bb); - token = 0x0A000000 | MemberRef.AddRecord(rec); + rec.Signature = GetOrAddBlob(bb.ToArray()); + token = MetadataTokens.GetToken(MetadataTokens.MemberReferenceHandle(MemberRef.AddRecord(rec))); importedMemberRefs.Add(key, token); } @@ -836,8 +916,8 @@ internal int ImportMethodSpec(Type declaringType, MethodInfo method, Type[] gene var spec = new ByteBuffer(10); Signature.WriteMethodSpec(this, spec, genericParameters); - rec.Instantiation = Blobs.Add(spec); - token = 0x2B000000 | MethodSpec.FindOrAddRecord(rec); + rec.Instantiation = GetOrAddBlob(spec.ToArray()); + token = MetadataTokens.GetToken(MetadataTokens.MethodSpecificationHandle(MethodSpec.FindOrAddRecord(rec))); importedMethodSpecs.Add(key, token); } @@ -853,7 +933,7 @@ internal int ImportType(Type type) { var spec = new ByteBuffer(5); Signature.WriteTypeSpec(this, spec, type); - token = 0x1B000000 | this.TypeSpec.AddRecord(this.Blobs.Add(spec)); + token = MetadataTokens.GetToken(MetadataTokens.TypeSpecificationHandle(TypeSpec.AddRecord(GetOrAddBlob(spec.ToArray())))); } else { @@ -866,7 +946,7 @@ internal int ImportType(Type type) rec.ResolutionScope = ImportAssemblyRef(type.Assembly); SetTypeNameAndTypeNamespace(type.TypeName, out rec.TypeName, out rec.TypeNamespace); - token = 0x01000000 | this.TypeRef.AddRecord(rec); + token = 0x01000000 | TypeRef.AddRecord(rec); } typeTokens.Add(type, token); } @@ -927,19 +1007,19 @@ private int FindOrAddAssemblyRef(AssemblyName name, bool alwaysAdd) const int PublicKey = 0x0001; rec.Flags |= PublicKey; } - rec.PublicKeyOrToken = this.Blobs.Add(ByteBuffer.Wrap(publicKeyOrToken)); - rec.Name = this.Strings.Add(name.Name); - rec.Culture = name.CultureName == null ? 0 : this.Strings.Add(name.CultureName); + rec.PublicKeyOrToken = GetOrAddBlob(publicKeyOrToken); + rec.Name = GetOrAddString(name.Name); + rec.Culture = name.CultureName == null ? default : GetOrAddString(name.CultureName); if (name.hash != null) { - rec.HashValue = this.Blobs.Add(ByteBuffer.Wrap(name.hash)); + rec.HashValue = GetOrAddBlob(name.hash); } else { - rec.HashValue = 0; + rec.HashValue = default; } - return 0x23000000 | (alwaysAdd ? this.AssemblyRef.AddRecord(rec) : this.AssemblyRef.FindOrAddRecord(rec)); + return MetadataTokens.GetToken(MetadataTokens.AssemblyReferenceHandle(alwaysAdd ? AssemblyRef.AddRecord(rec) : AssemblyRef.FindOrAddRecord(rec))); } internal void WriteSymbolTokenMap() @@ -1026,17 +1106,18 @@ internal void FixupMethodBodyTokens() int methodToken = 0x06000001; int fieldToken = 0x04000001; int parameterToken = 0x08000001; - foreach (TypeBuilder type in types) - { + + foreach (var type in types) type.ResolveMethodAndFieldTokens(ref methodToken, ref fieldToken, ref parameterToken); - } - foreach (int offset in tokenFixupOffsets) + + foreach (var offset in tokenFixupOffsets) { methodBodies.Position = offset; int pseudoToken = methodBodies.GetInt32AtCurrentPosition(); methodBodies.Write(ResolvePseudoToken(pseudoToken)); } - foreach (VTableFixups fixup in vtablefixups) + + foreach (var fixup in vtableFixups) { for (int i = 0; i < fixup.count; i++) { @@ -1046,104 +1127,14 @@ internal void FixupMethodBodyTokens() } } - int GetHeaderLength() - { - return - 4 + // Signature - 2 + // MajorVersion - 2 + // MinorVersion - 4 + // Reserved - 4 + // ImageRuntimeVersion Length - StringToPaddedUTF8Length(asm.ImageRuntimeVersion) + - 2 + // Flags - 2 + // Streams - 4 + // #~ Offset - 4 + // #~ Size - 4 + // StringToPaddedUTF8Length("#~") - 4 + // #Strings Offset - 4 + // #Strings Size - 12 + // StringToPaddedUTF8Length("#Strings") - 4 + // #US Offset - 4 + // #US Size - 4 + // StringToPaddedUTF8Length("#US") - 4 + // #GUID Offset - 4 + // #GUID Size - 8 + // StringToPaddedUTF8Length("#GUID") - (Blobs.IsEmpty ? 0 : - ( - 4 + // #Blob Offset - 4 + // #Blob Size - 8 // StringToPaddedUTF8Length("#Blob") - )); - } - - internal int MetadataLength + /// + /// Writes all of the metadata of the module. + /// + internal void WriteMetadata() { - get - { - return GetHeaderLength() + (Blobs.IsEmpty ? 0 : Blobs.Length) + Tables.Length + Strings.Length + UserStrings.Length + Guids.Length; - } - } - - internal void WriteMetadata(MetadataWriter mw, out uint guidHeapOffset) - { - mw.Write(0x424A5342); // Signature ("BSJB") - mw.Write((ushort)1); // MajorVersion - mw.Write((ushort)1); // MinorVersion - mw.Write(0); // Reserved - byte[] version = StringToPaddedUTF8(asm.ImageRuntimeVersion); - mw.Write(version.Length); // Length - mw.Write(version); - mw.Write((ushort)0); // Flags - // #Blob is the only optional heap - if (Blobs.IsEmpty) - { - mw.Write((ushort)4); // Streams - } - else - { - mw.Write((ushort)5); // Streams - } - - int offset = GetHeaderLength(); - - // Streams - mw.Write(offset); // Offset - mw.Write(Tables.Length); // Size - mw.Write(StringToPaddedUTF8("#~")); - offset += Tables.Length; - - mw.Write(offset); // Offset - mw.Write(Strings.Length); // Size - mw.Write(StringToPaddedUTF8("#Strings")); - offset += Strings.Length; - - mw.Write(offset); // Offset - mw.Write(UserStrings.Length); // Size - mw.Write(StringToPaddedUTF8("#US")); - offset += UserStrings.Length; - - mw.Write(offset); // Offset - mw.Write(Guids.Length); // Size - mw.Write(StringToPaddedUTF8("#GUID")); - offset += Guids.Length; - - if (!Blobs.IsEmpty) - { - mw.Write(offset); // Offset - mw.Write(Blobs.Length); // Size - mw.Write(StringToPaddedUTF8("#Blob")); - } - - Tables.Write(mw); - Strings.Write(mw); - UserStrings.Write(mw); - guidHeapOffset = mw.Position; - Guids.Write(mw); - if (!Blobs.IsEmpty) - { - Blobs.Write(mw); - } + foreach (var table in GetTables()) + if (table != null) + table.Write(this); } static int StringToPaddedUTF8Length(string str) @@ -1158,38 +1149,37 @@ static byte[] StringToPaddedUTF8(string str) return buf; } - internal override void ExportTypes(int fileToken, ModuleBuilder manifestModule) + internal override void ExportTypes(AssemblyFileHandle fileToken, ModuleBuilder manifestModule) { manifestModule.ExportTypes(types.ToArray(), fileToken); } - internal void ExportTypes(Type[] types, int fileToken) + internal void ExportTypes(Type[] types, AssemblyFileHandle fileToken) { - Dictionary declaringTypes = new Dictionary(); - foreach (Type type in types) + var declaringTypes = new Dictionary(); + + foreach (var type in types) { - if (!type.IsModulePseudoType && IsVisible(type)) + if (type.IsModulePseudoType == false && IsVisible(type)) { - ExportedTypeTable.Record rec = new ExportedTypeTable.Record(); + var rec = new ExportedTypeTable.Record(); rec.Flags = (int)type.Attributes; // LAMESPEC ECMA says that TypeDefId is a row index, but it should be a token rec.TypeDefId = type.MetadataToken; SetTypeNameAndTypeNamespace(type.TypeName, out rec.TypeName, out rec.TypeNamespace); + if (type.IsNested) - { - rec.Implementation = declaringTypes[type.DeclaringType]; - } + rec.Implementation = MetadataTokens.GetToken(declaringTypes[type.DeclaringType]); else - { - rec.Implementation = fileToken; - } - int exportTypeToken = 0x27000000 | this.ExportedType.AddRecord(rec); + rec.Implementation = MetadataTokens.GetToken(fileToken); + + var exportTypeToken = MetadataTokens.ExportedTypeHandle(ExportedType.AddRecord(rec)); declaringTypes.Add(type, exportTypeToken); } } } - private static bool IsVisible(Type type) + static bool IsVisible(Type type) { // NOTE this is not the same as Type.IsVisible, because that doesn't take into account family access return type.IsPublic || ((type.IsNestedFamily || type.IsNestedFamORAssem || type.IsNestedPublic) && IsVisible(type.DeclaringType)); @@ -1197,93 +1187,95 @@ private static bool IsVisible(Type type) internal void AddConstant(int parentToken, object defaultValue) { - ConstantTable.Record rec = new ConstantTable.Record(); + var rec = new ConstantTable.Record(); rec.Parent = parentToken; - ByteBuffer val = new ByteBuffer(16); + var val = new ByteBuffer(16); if (defaultValue == null) { rec.Type = Signature.ELEMENT_TYPE_CLASS; val.Write((int)0); } - else if (defaultValue is bool) + else if (defaultValue is bool boolValue) { rec.Type = Signature.ELEMENT_TYPE_BOOLEAN; - val.Write((bool)defaultValue ? (byte)1 : (byte)0); + val.Write(boolValue ? (byte)1 : (byte)0); } - else if (defaultValue is char) + else if (defaultValue is char charValue) { rec.Type = Signature.ELEMENT_TYPE_CHAR; - val.Write((char)defaultValue); + val.Write(charValue); } - else if (defaultValue is sbyte) + else if (defaultValue is sbyte sbyteValue) { rec.Type = Signature.ELEMENT_TYPE_I1; - val.Write((sbyte)defaultValue); + val.Write(sbyteValue); } - else if (defaultValue is byte) + else if (defaultValue is byte byteValue) { rec.Type = Signature.ELEMENT_TYPE_U1; - val.Write((byte)defaultValue); + val.Write(byteValue); } - else if (defaultValue is short) + else if (defaultValue is short shortValue) { rec.Type = Signature.ELEMENT_TYPE_I2; - val.Write((short)defaultValue); + val.Write(shortValue); } - else if (defaultValue is ushort) + else if (defaultValue is ushort ushortValue) { rec.Type = Signature.ELEMENT_TYPE_U2; - val.Write((ushort)defaultValue); + val.Write(ushortValue); } - else if (defaultValue is int) + else if (defaultValue is int intValue) { rec.Type = Signature.ELEMENT_TYPE_I4; - val.Write((int)defaultValue); + val.Write(intValue); } - else if (defaultValue is uint) + else if (defaultValue is uint uintValue) { rec.Type = Signature.ELEMENT_TYPE_U4; - val.Write((uint)defaultValue); + val.Write(uintValue); } - else if (defaultValue is long) + else if (defaultValue is long longValue) { rec.Type = Signature.ELEMENT_TYPE_I8; - val.Write((long)defaultValue); + val.Write(longValue); } - else if (defaultValue is ulong) + else if (defaultValue is ulong ulongValue) { rec.Type = Signature.ELEMENT_TYPE_U8; - val.Write((ulong)defaultValue); + val.Write(ulongValue); } - else if (defaultValue is float) + else if (defaultValue is float floatValue) { rec.Type = Signature.ELEMENT_TYPE_R4; - val.Write((float)defaultValue); + val.Write(floatValue); } - else if (defaultValue is double) + else if (defaultValue is double doubleValue) { rec.Type = Signature.ELEMENT_TYPE_R8; - val.Write((double)defaultValue); + val.Write(doubleValue); } - else if (defaultValue is string) + else if (defaultValue is string stringValue) { rec.Type = Signature.ELEMENT_TYPE_STRING; - foreach (char c in (string)defaultValue) - { + foreach (var c in stringValue) val.Write(c); - } } - else if (defaultValue is DateTime) + else if (defaultValue is DateTime dateTimeValue) { rec.Type = Signature.ELEMENT_TYPE_I8; - val.Write(((DateTime)defaultValue).Ticks); + val.Write(dateTimeValue.Ticks); } else { throw new ArgumentException(); } - rec.Value = this.Blobs.Add(val); - this.Constant.AddRecord(rec); + + // encode index into blobs, as well as pass along value, since SRME does not have an AddConstant override that takes a handle + // final blob should be deduplicated, leading to the same index value on write + rec.Offset = GetOrAddBlob(val.ToArray()); + rec.Value = val; + Constant.AddRecord(rec); } ModuleBuilder ITypeOwner.ModuleBuilder @@ -1456,17 +1448,19 @@ public void SetUserEntryPoint(MethodInfo entryPoint) public StringToken GetStringConstant(string str) { - return new StringToken(this.UserStrings.Add(str) | (0x70 << 24)); + return new StringToken(MetadataTokens.GetHeapOffset(metadata.GetOrAddUserString(str)) | (0x70 << 24)); } public SignatureToken GetSignatureToken(SignatureHelper sigHelper) { - return new SignatureToken(this.StandAloneSig.FindOrAddRecord(this.Blobs.Add(sigHelper.GetSignature(this))) | (StandAloneSigTable.Index << 24)); + return new SignatureToken(StandAloneSig.FindOrAddRecord(GetOrAddBlob(sigHelper.GetSignature(this).ToArray())) | (StandAloneSigTable.Index << 24)); } public SignatureToken GetSignatureToken(byte[] sigBytes, int sigLength) { - return new SignatureToken(this.StandAloneSig.FindOrAddRecord(this.Blobs.Add(ByteBuffer.Wrap(sigBytes, sigLength))) | (StandAloneSigTable.Index << 24)); + var bb = new BlobBuilder(); + bb.WriteBytes(sigBytes, 0, sigLength); + return new SignatureToken(StandAloneSig.FindOrAddRecord(GetOrAddBlob(bb)) | (StandAloneSigTable.Index << 24)); } public MethodInfo GetArrayMethod(Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes) @@ -1484,16 +1478,11 @@ internal override Type GetModuleType() return moduleType; } - internal override IKVM.Reflection.Reader.ByteReader GetBlob(int blobIndex) - { - return Blobs.GetBlob(blobIndex); - } - - internal int GetSignatureBlobIndex(Signature sig) + internal BlobHandle GetSignatureBlobIndex(Signature sig) { - ByteBuffer bb = new ByteBuffer(16); + var bb = new ByteBuffer(16); sig.WriteSig(this, bb); - return this.Blobs.Add(bb); + return GetOrAddBlob(bb.ToArray()); } // non-standard API @@ -1583,25 +1572,23 @@ private void SaveImpl(Stream streamOrNull, PortableExecutableKinds portableExecu { SetIsSaved(); PopulatePropertyAndEventTables(); - IList attributes = asm.GetCustomAttributesData(null); + + var attributes = asm.GetCustomAttributesData(null); if (attributes.Count > 0) { - int mscorlib = ImportAssemblyRef(universe.CoreLib); - int[] placeholderTokens = new int[4]; - string[] placeholderTypeNames = new string[] { "AssemblyAttributesGoHere", "AssemblyAttributesGoHereM", "AssemblyAttributesGoHereS", "AssemblyAttributesGoHereSM" }; + var mscorlib = ImportAssemblyRef(universe.CoreLib); + var placeholderTokens = new int[4]; + var placeholderTypeNames = new string[] { "AssemblyAttributesGoHere", "AssemblyAttributesGoHereM", "AssemblyAttributesGoHereS", "AssemblyAttributesGoHereSM" }; + foreach (CustomAttributeData cad in attributes) { int index; if (cad.Constructor.DeclaringType.BaseType == universe.System_Security_Permissions_CodeAccessSecurityAttribute) { if (cad.Constructor.DeclaringType.IsAllowMultipleCustomAttribute) - { index = 3; - } else - { index = 2; - } } else if (cad.Constructor.DeclaringType.IsAllowMultipleCustomAttribute) { @@ -1611,17 +1598,20 @@ private void SaveImpl(Stream streamOrNull, PortableExecutableKinds portableExecu { index = 0; } + if (placeholderTokens[index] == 0) { // we manually add a TypeRef without looking it up in mscorlib, because Mono and Silverlight's mscorlib don't have these types placeholderTokens[index] = AddTypeRefByName(mscorlib, "System.Runtime.CompilerServices", placeholderTypeNames[index]); } + SetCustomAttribute(placeholderTokens[index], cad.__ToBuilder()); } } + FillAssemblyRefTable(); EmitResources(); - ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, unmanagedResources, 0, streamOrNull); + ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, unmanagedResources, default, streamOrNull); CloseResources(); } @@ -1632,67 +1622,52 @@ public void __AddAssemblyReference(AssemblyName assemblyName) public void __AddAssemblyReference(AssemblyName assemblyName, Assembly assembly) { - if (referencedAssemblyNames == null) - { - referencedAssemblyNames = new List(); - } + referencedAssemblyNames ??= new List(); referencedAssemblyNames.Add((AssemblyName)assemblyName.Clone()); - int token = FindOrAddAssemblyRef(assemblyName, true); + var token = FindOrAddAssemblyRef(assemblyName, true); if (assembly != null) - { referencedAssemblies.Add(assembly, token); - } } public override AssemblyName[] __GetReferencedAssemblies() { - List list = new List(); + var list = new List(); if (referencedAssemblyNames != null) - { - foreach (AssemblyName name in referencedAssemblyNames) - { - if (!list.Contains(name)) - { + foreach (var name in referencedAssemblyNames) + if (list.Contains(name) == false) list.Add(name); - } - } - } - foreach (Assembly asm in referencedAssemblies.Keys) + + foreach (var asm in referencedAssemblies.Keys) { - AssemblyName name = asm.GetName(); - if (!list.Contains(name)) - { + var name = asm.GetName(); + if (list.Contains(name) == false) list.Add(name); - } } + return list.ToArray(); } public void __AddModuleReference(string module) { - this.ModuleRef.FindOrAddRecord(module == null ? 0 : this.Strings.Add(module)); + ModuleRef.FindOrAddRecord(module == null ? default : GetOrAddString(module)); } public override string[] __GetReferencedModules() { - string[] arr = new string[this.ModuleRef.RowCount]; + var arr = new string[ModuleRef.RowCount]; for (int i = 0; i < arr.Length; i++) - { - arr[i] = this.Strings.Find(this.ModuleRef.records[i]); - } + arr[i] = GetString(ModuleRef.records[i]); + return arr; } public override Type[] __GetReferencedTypes() { - List list = new List(); - foreach (KeyValuePair kv in typeTokens) - { + var list = new List(); + foreach (var kv in typeTokens) if (kv.Value >> 24 == TypeRefTable.Index) - { list.Add(kv.Key); - } - } + return list.ToArray(); } @@ -1703,21 +1678,21 @@ public override Type[] __GetExportedTypes() public int __AddModule(int flags, string name, byte[] hash) { - FileTable.Record file = new FileTable.Record(); + var file = new FileTable.Record(); file.Flags = flags; - file.Name = this.Strings.Add(name); - file.HashValue = this.Blobs.Add(ByteBuffer.Wrap(hash)); - return 0x26000000 + this.File.AddRecord(file); + file.Name = GetOrAddString(name); + file.HashValue = GetOrAddBlob(hash); + return MetadataTokens.GetToken(MetadataTokens.AssemblyFileHandle(File.AddRecord(file))); } public int __AddManifestResource(int offset, ResourceAttributes flags, string name, int implementation) { - ManifestResourceTable.Record res = new ManifestResourceTable.Record(); + var res = new ManifestResourceTable.Record(); res.Offset = offset; res.Flags = (int)flags; - res.Name = this.Strings.Add(name); + res.Name = GetOrAddString(name); res.Implementation = implementation; - return 0x28000000 + this.ManifestResource.AddRecord(res); + return MetadataTokens.GetToken(MetadataTokens.ManifestResourceHandle(ManifestResource.AddRecord(res))); } public void __SetCustomAttributeFor(int token, CustomAttributeBuilder customBuilder) @@ -1728,19 +1703,18 @@ public void __SetCustomAttributeFor(int token, CustomAttributeBuilder customBuil public RelativeVirtualAddress __AddVTableFixups(MethodBuilder[] methods, int type) { initializedData.Align(8); - VTableFixups fixups; + var fixups = new VTableFixups(); fixups.initializedDataOffset = (uint)initializedData.Position; fixups.count = (ushort)methods.Length; fixups.type = (ushort)type; - foreach (MethodBuilder mb in methods) + foreach (var mb in methods) { initializedData.Write(mb.MetadataToken); if (fixups.SlotWidth == 8) - { initializedData.Write(0); - } } - vtablefixups.Add(fixups); + + vtableFixups.Add(fixups); return new RelativeVirtualAddress(fixups.initializedDataOffset); } @@ -1751,7 +1725,7 @@ public void __AddUnmanagedExportStub(string name, int ordinal, RelativeVirtualAd internal void AddUnmanagedExport(string name, int ordinal, MethodBuilder methodBuilder, RelativeVirtualAddress rva) { - UnmanagedExport export; + var export = new UnmanagedExport(); export.name = name; export.ordinal = ordinal; export.mb = methodBuilder; @@ -1763,30 +1737,24 @@ internal void SetInterfaceImplementationCustomAttribute(TypeBuilder typeBuilder, { // NOTE since interfaceimpls are extremely common and custom attributes on them are extremely rare, // we store (and resolve) the custom attributes in such away as to avoid impacting the common case performance - if (interfaceImplCustomAttributes == null) - { - interfaceImplCustomAttributes = new List(); - } - InterfaceImplCustomAttribute rec; + interfaceImplCustomAttributes ??= new List(); + + var rec = new InterfaceImplCustomAttribute(); rec.type = typeBuilder.MetadataToken; - int token = GetTypeToken(interfaceType).Token; - switch (token >> 24) - { - case TypeDefTable.Index: - token = (token & 0xFFFFFF) << 2 | 0; - break; - case TypeRefTable.Index: - token = (token & 0xFFFFFF) << 2 | 1; - break; - case TypeSpecTable.Index: - token = (token & 0xFFFFFF) << 2 | 2; - break; - default: - throw new InvalidOperationException(); - } + var token = GetTypeToken(interfaceType).Token; + + token = (token >> 24) switch + { + TypeDefTable.Index => (token & 0xFFFFFF) << 2 | 0, + TypeRefTable.Index => (token & 0xFFFFFF) << 2 | 1, + TypeSpecTable.Index => (token & 0xFFFFFF) << 2 | 2, + _ => throw new InvalidOperationException(), + }; + rec.interfaceType = token; rec.pseudoToken = AllocPseudoToken(); interfaceImplCustomAttributes.Add(rec); + SetCustomAttribute(rec.pseudoToken, cab); } @@ -1811,17 +1779,14 @@ internal void ResolveInterfaceImplPseudoTokens() internal void FixupPseudoToken(ref int token) { if (IsPseudoToken(token)) - { token = ResolvePseudoToken(token); - } } internal void SetIsSaved() { if (saved) - { throw new InvalidOperationException(); - } + saved = true; } @@ -1830,11 +1795,6 @@ internal bool IsSaved get { return saved; } } - internal override string GetString(int index) - { - return this.Strings.Find(index); - } - } } diff --git a/src/IKVM.Reflection/Emit/ParameterBuilder.cs b/src/IKVM.Reflection/Emit/ParameterBuilder.cs index 7f15f4954e..0e982a90c8 100644 --- a/src/IKVM.Reflection/Emit/ParameterBuilder.cs +++ b/src/IKVM.Reflection/Emit/ParameterBuilder.cs @@ -21,7 +21,8 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Writer; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; namespace IKVM.Reflection.Emit { @@ -32,7 +33,7 @@ public sealed class ParameterBuilder readonly ModuleBuilder moduleBuilder; short flags; readonly short sequence; - readonly int nameIndex; + readonly StringHandle nameIndex; readonly string name; int lazyPseudoToken; @@ -48,7 +49,7 @@ internal ParameterBuilder(ModuleBuilder moduleBuilder, int sequence, ParameterAt this.moduleBuilder = moduleBuilder; this.flags = (short)attribs; this.sequence = (short)sequence; - this.nameIndex = name == null ? 0 : moduleBuilder.Strings.Add(name); + this.nameIndex = name == null ? default : moduleBuilder.GetOrAddString(name); this.name = name; } @@ -130,11 +131,12 @@ public void SetConstant(object defaultValue) moduleBuilder.AddConstant(PseudoToken, defaultValue); } - internal void WriteParamRecord(MetadataWriter mw) + internal void WriteParamRecord(MetadataBuilder metadata) { - mw.Write(flags); - mw.Write(sequence); - mw.WriteStringIndex(nameIndex); + metadata.AddParameter( + (System.Reflection.ParameterAttributes)flags, + nameIndex, + sequence); } internal void FixupToken(int parameterToken) diff --git a/src/IKVM.Reflection/Emit/PropertyBuilder.cs b/src/IKVM.Reflection/Emit/PropertyBuilder.cs index 427f80626f..91f52442d0 100644 --- a/src/IKVM.Reflection/Emit/PropertyBuilder.cs +++ b/src/IKVM.Reflection/Emit/PropertyBuilder.cs @@ -23,6 +23,7 @@ Jeroen Frijters */ using System; using System.Collections.Generic; +using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Metadata; @@ -197,9 +198,9 @@ internal void Bake() var rec = new PropertyTable.Record(); rec.Flags = (short)attributes; - rec.Name = typeBuilder.ModuleBuilder.Strings.Add(name); + rec.Name = typeBuilder.ModuleBuilder.GetOrAddString(name); rec.Type = typeBuilder.ModuleBuilder.GetSignatureBlobIndex(sig); - int token = 0x17000000 | typeBuilder.ModuleBuilder.Property.AddRecord(rec); + int token = MetadataTokens.GetToken(MetadataTokens.PropertyDefinitionHandle(typeBuilder.ModuleBuilder.Property.AddRecord(rec))); if (lazyPseudoToken == 0) lazyPseudoToken = token; diff --git a/src/IKVM.Reflection/Emit/TypeBuilder.cs b/src/IKVM.Reflection/Emit/TypeBuilder.cs index a510b2c2c0..d2ceff7bac 100644 --- a/src/IKVM.Reflection/Emit/TypeBuilder.cs +++ b/src/IKVM.Reflection/Emit/TypeBuilder.cs @@ -23,11 +23,13 @@ Jeroen Frijters */ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using IKVM.Reflection.Impl; using IKVM.Reflection.Metadata; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Emit { @@ -41,8 +43,8 @@ public sealed class TypeBuilder : TypeInfo, ITypeOwner readonly int token; int extends; Type lazyBaseType; // (lazyBaseType == null && attribs & TypeAttributes.Interface) == 0) => BaseType == System.Object - readonly int typeName; - readonly int typeNameSpace; + readonly StringHandle typeName; + readonly StringHandle typeNameSpace; readonly string ns; readonly string name; readonly List methods = new List(); @@ -66,11 +68,11 @@ public sealed class TypeBuilder : TypeInfo, ITypeOwner internal TypeBuilder(ITypeOwner owner, string ns, string name) { this.owner = owner; - this.token = this.ModuleBuilder.TypeDef.AllocToken(); + this.token = ModuleBuilder.TypeDef.AllocToken(); this.ns = ns; this.name = name; - this.typeNameSpace = ns == null ? 0 : this.ModuleBuilder.Strings.Add(ns); - this.typeName = this.ModuleBuilder.Strings.Add(name); + this.typeNameSpace = ns == null ? default : ModuleBuilder.GetOrAddString(ns); + this.typeName = ModuleBuilder.GetOrAddString(name); MarkKnownType(ns, name); } @@ -470,18 +472,14 @@ public TypeInfo CreateTypeInfo() } if (!hasConstructor && !IsModulePseudoType && !IsInterface && !IsValueType && !(IsAbstract && IsSealed) && Universe.AutomaticallyProvideDefaultConstructor) - { ((MethodBuilder)DefineDefaultConstructor(MethodAttributes.Public).GetMethodInfo()).Bake(); - } if (declarativeSecurity != null) - { ModuleBuilder.AddDeclarativeSecurity(token, declarativeSecurity); - } if (!IsModulePseudoType) { - var baseType = this.BaseType; + var baseType = BaseType; if (baseType != null) extends = ModuleBuilder.GetTypeToken(baseType).Token; } @@ -670,22 +668,27 @@ public TypeToken TypeToken get { return new TypeToken(token); } } - internal void WriteTypeDefRecord(MetadataWriter mw, ref int fieldList, ref int methodList) + internal void WriteTypeDefRecord(MetadataBuilder metadata, ref int fieldList, ref int methodList) { - mw.Write((int)attribs); - mw.WriteStringIndex(typeName); - mw.WriteStringIndex(typeNameSpace); - mw.WriteTypeDefOrRef(extends); - mw.WriteField(fieldList); - mw.WriteMethodDef(methodList); - methodList += methods.Count; + var h = metadata.AddTypeDefinition( + (System.Reflection.TypeAttributes)attribs, + typeNameSpace, + typeName, + MetadataTokens.EntityHandle(extends), + MetadataTokens.FieldDefinitionHandle(fieldList), + MetadataTokens.MethodDefinitionHandle(methodList)); + + Debug.Assert(h == MetadataTokens.TypeDefinitionHandle(token)); + + // increment next expected method and field row numbers fieldList += fields.Count; + methodList += methods.Count; } - internal void WriteMethodDefRecords(int baseRVA, MetadataWriter mw, ref int paramList) + internal void WriteMethodDefRecords(MetadataBuilder metadata, ref int paramList) { foreach (var mb in methods) - mb.WriteMethodDefRecord(baseRVA, mw, ref paramList); + mb.WriteMethodDefRecord(metadata, ref paramList); } internal void ResolveMethodAndFieldTokens(ref int methodToken, ref int fieldToken, ref int parameterToken) @@ -696,16 +699,16 @@ internal void ResolveMethodAndFieldTokens(ref int methodToken, ref int fieldToke field.FixupToken(fieldToken++); } - internal void WriteParamRecords(MetadataWriter mw) + internal void WriteParamRecords(MetadataBuilder metadata) { foreach (var mb in methods) - mb.WriteParamRecords(mw); + mb.WriteParamRecords(metadata); } - internal void WriteFieldRecords(MetadataWriter mw) + internal void WriteFieldRecords(MetadataBuilder metadata) { foreach (var fb in fields) - fb.WriteFieldRecords(mw); + fb.WriteFieldRecords(metadata); } internal ModuleBuilder ModuleBuilder diff --git a/src/IKVM.Reflection/FieldMarshal.cs b/src/IKVM.Reflection/FieldMarshal.cs index 3dc653fd88..737313aa89 100644 --- a/src/IKVM.Reflection/FieldMarshal.cs +++ b/src/IKVM.Reflection/FieldMarshal.cs @@ -22,6 +22,8 @@ Jeroen Frijters */ +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using System.Text; @@ -56,7 +58,7 @@ internal static bool ReadFieldMarshal(Module module, int token, out FieldMarshal foreach (var i in module.FieldMarshal.Filter(token)) { - var blob = module.GetBlob(module.FieldMarshal.records[i].NativeType); + var blob = module.GetBlobReader(module.FieldMarshal.records[i].NativeType); fm.UnmanagedType = (UnmanagedType)blob.ReadCompressedUInt(); switch (fm.UnmanagedType) @@ -128,7 +130,7 @@ internal static void SetMarshalAsAttribute(ModuleBuilder module, int token, Cust module.FieldMarshal.AddRecord(rec); } - static int WriteMarshallingDescriptor(ModuleBuilder module, CustomAttributeBuilder attribute) + static BlobHandle WriteMarshallingDescriptor(ModuleBuilder module, CustomAttributeBuilder attribute) { var val = attribute.GetConstructorArgument(0); var unmanagedType = val switch @@ -218,7 +220,7 @@ static int WriteMarshallingDescriptor(ModuleBuilder module, CustomAttributeBuild } } - return module.Blobs.Add(bb); + return module.GetOrAddBlob(bb.ToArray()); } static Type ReadType(Module module, ByteReader br) diff --git a/src/IKVM.Reflection/IKVM.Reflection.csproj b/src/IKVM.Reflection/IKVM.Reflection.csproj index 8cdcd2d889..58e577a065 100644 --- a/src/IKVM.Reflection/IKVM.Reflection.csproj +++ b/src/IKVM.Reflection/IKVM.Reflection.csproj @@ -10,6 +10,7 @@ + diff --git a/src/IKVM.Reflection/Metadata/AssemblyRefTable.cs b/src/IKVM.Reflection/Metadata/AssemblyRefTable.cs index 32c55722fe..35cd9f47c8 100644 --- a/src/IKVM.Reflection/Metadata/AssemblyRefTable.cs +++ b/src/IKVM.Reflection/Metadata/AssemblyRefTable.cs @@ -21,11 +21,17 @@ Jeroen Frijters jeroen@frijters.net */ +using System; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { + sealed class AssemblyRefTable : Table { @@ -37,10 +43,10 @@ internal struct Record internal ushort BuildNumber; internal ushort RevisionNumber; internal int Flags; - internal int PublicKeyOrToken; - internal int Name; - internal int Culture; - internal int HashValue; + internal BlobHandle PublicKeyOrToken; + internal StringHandle Name; + internal StringHandle Culture; + internal BlobHandle HashValue; } @@ -65,7 +71,7 @@ internal int FindOrAddRecord(Record rec) return AddRecord(rec); } - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { @@ -74,40 +80,29 @@ internal override void Read(MetadataReader mr) records[i].BuildNumber = mr.ReadUInt16(); records[i].RevisionNumber = mr.ReadUInt16(); records[i].Flags = mr.ReadInt32(); - records[i].PublicKeyOrToken = mr.ReadBlobIndex(); - records[i].Name = mr.ReadStringIndex(); - records[i].Culture = mr.ReadStringIndex(); - records[i].HashValue = mr.ReadBlobIndex(); + records[i].PublicKeyOrToken = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); + records[i].Name = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].Culture = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].HashValue = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); } } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) { - mw.Write(records[i].MajorVersion); - mw.Write(records[i].MinorVersion); - mw.Write(records[i].BuildNumber); - mw.Write(records[i].RevisionNumber); - mw.Write(records[i].Flags); - mw.WriteBlobIndex(records[i].PublicKeyOrToken); - mw.WriteStringIndex(records[i].Name); - mw.WriteStringIndex(records[i].Culture); - mw.WriteBlobIndex(records[i].HashValue); + var h = module.Metadata.AddAssemblyReference( + records[i].Name, + new Version(records[i].MajorVersion, records[i].MinorVersion, records[i].BuildNumber, records[i].RevisionNumber), + records[i].Culture, + records[i].PublicKeyOrToken, + (System.Reflection.AssemblyFlags)records[i].Flags, + records[i].HashValue); + + Debug.Assert(h == MetadataTokens.AssemblyReferenceHandle(i + 1)); } } - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(12) - .WriteBlobIndex() - .WriteStringIndex() - .WriteStringIndex() - .WriteBlobIndex() - .Value; - } - } } diff --git a/src/IKVM.Reflection/Metadata/AssemblyTable.cs b/src/IKVM.Reflection/Metadata/AssemblyTable.cs index 39cfc4ab79..fd3784da20 100644 --- a/src/IKVM.Reflection/Metadata/AssemblyTable.cs +++ b/src/IKVM.Reflection/Metadata/AssemblyTable.cs @@ -21,8 +21,11 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { @@ -37,14 +40,14 @@ internal struct Record internal ushort BuildNumber; internal ushort RevisionNumber; internal int Flags; - internal int PublicKey; - internal int Name; - internal int Culture; + internal BlobHandle PublicKey; + internal StringHandle Name; + internal StringHandle Culture; } internal const int Index = 0x20; - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { @@ -54,36 +57,22 @@ internal override void Read(MetadataReader mr) records[i].BuildNumber = mr.ReadUInt16(); records[i].RevisionNumber = mr.ReadUInt16(); records[i].Flags = mr.ReadInt32(); - records[i].PublicKey = mr.ReadBlobIndex(); - records[i].Name = mr.ReadStringIndex(); - records[i].Culture = mr.ReadStringIndex(); + records[i].PublicKey = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); + records[i].Name = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].Culture = MetadataTokens.StringHandle(mr.ReadStringIndex()); } } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) - { - mw.Write(records[i].HashAlgId); - mw.Write(records[i].MajorVersion); - mw.Write(records[i].MinorVersion); - mw.Write(records[i].BuildNumber); - mw.Write(records[i].RevisionNumber); - mw.Write(records[i].Flags); - mw.WriteBlobIndex(records[i].PublicKey); - mw.WriteStringIndex(records[i].Name); - mw.WriteStringIndex(records[i].Culture); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(16) - .WriteBlobIndex() - .WriteStringIndex() - .WriteStringIndex() - .Value; + module.Metadata.AddAssembly( + records[i].Name, + new Version(records[i].MajorVersion, records[i].MinorVersion, records[i].BuildNumber, records[i].RevisionNumber), + records[i].Culture, + records[i].PublicKey, + (System.Reflection.AssemblyFlags)records[i].Flags, + (System.Reflection.AssemblyHashAlgorithm)records[i].HashAlgId); } } diff --git a/src/IKVM.Reflection/Metadata/ClassLayoutTable.cs b/src/IKVM.Reflection/Metadata/ClassLayoutTable.cs index ba10e0faee..85f23e6cf8 100644 --- a/src/IKVM.Reflection/Metadata/ClassLayoutTable.cs +++ b/src/IKVM.Reflection/Metadata/ClassLayoutTable.cs @@ -21,8 +21,10 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -44,36 +46,27 @@ internal struct Record : IRecord internal const int Index = 0x0f; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].PackingSize = mr.ReadInt16(); - records[i].ClassSize = mr.ReadInt32(); - records[i].Parent = mr.ReadTypeDef(); - } - } - - internal override void Write(MetadataWriter mw) - { - Sort(); - - for (int i = 0; i < rowCount; i++) - { - mw.Write(records[i].PackingSize); - mw.Write(records[i].ClassSize); - mw.WriteTypeDef(records[i].Parent); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(6) - .WriteTypeDef() - .Value; - } - - } + internal override void Read(Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].PackingSize = mr.ReadInt16(); + records[i].ClassSize = mr.ReadInt32(); + records[i].Parent = mr.ReadTypeDef(); + } + } + + internal override void Write(ModuleBuilder module) + { + Sort(); + + for (int i = 0; i < rowCount; i++) + module.Metadata.AddTypeLayout( + System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].Parent), + (ushort)records[i].PackingSize, + (uint)records[i].ClassSize); + } + + } } diff --git a/src/IKVM.Reflection/Metadata/CliHeader.cs b/src/IKVM.Reflection/Metadata/CliHeader.cs index 85f2316066..29969c30e6 100644 --- a/src/IKVM.Reflection/Metadata/CliHeader.cs +++ b/src/IKVM.Reflection/Metadata/CliHeader.cs @@ -64,22 +64,6 @@ internal void Read(BinaryReader br) ManagedNativeHeader.Read(br); } - internal void Write(IKVM.Reflection.Writer.MetadataWriter mw) - { - mw.Write(Cb); - mw.Write(MajorRuntimeVersion); - mw.Write(MinorRuntimeVersion); - MetaData.Write(mw); - mw.Write(Flags); - mw.Write(EntryPointToken); - Resources.Write(mw); - StrongNameSignature.Write(mw); - CodeManagerTable.Write(mw); - VTableFixups.Write(mw); - ExportAddressTableJumps.Write(mw); - ManagedNativeHeader.Write(mw); - } - } } diff --git a/src/IKVM.Reflection/Metadata/ConstantTable.cs b/src/IKVM.Reflection/Metadata/ConstantTable.cs index 280420caf6..cf98fc8b4e 100644 --- a/src/IKVM.Reflection/Metadata/ConstantTable.cs +++ b/src/IKVM.Reflection/Metadata/ConstantTable.cs @@ -22,13 +22,16 @@ Jeroen Frijters */ using System; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { + sealed class ConstantTable : SortedTable { @@ -37,42 +40,39 @@ internal struct Record : IRecord internal short Type; internal int Parent; - internal int Value; + internal BlobHandle Offset; + internal object Value; + + readonly int IRecord.SortKey => EncodeHasConstant(Parent); - int IRecord.SortKey => EncodeHasConstant(Parent); + readonly int IRecord.FilterKey => Parent; - int IRecord.FilterKey => Parent; } internal const int Index = 0x0B; - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { records[i].Type = mr.ReadInt16(); records[i].Parent = mr.ReadHasConstant(); - records[i].Value = mr.ReadBlobIndex(); + records[i].Offset = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); } } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) { - mw.Write(records[i].Type); - mw.WriteHasConstant(records[i].Parent); - mw.WriteBlobIndex(records[i].Value); - } - } + // check that blob handle ends up the same + var b = module.Metadata.GetOrAddConstantBlob(records[i].Value); + Debug.Assert(b == records[i].Offset); - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(2) - .WriteHasConstant() - .WriteBlobIndex() - .Value; + // insert constant, and allow reencoding; should use same blob + var h = module.Metadata.AddConstant(MetadataTokens.EntityHandle(records[i].Parent), records[i].Value); + Debug.Assert(h == MetadataTokens.ConstantHandle(i + 1)); + } } internal void Fixup(ModuleBuilder moduleBuilder) @@ -98,7 +98,8 @@ internal object GetRawConstantValue(Module module, int parent) { foreach (var i in Filter(parent)) { - var br = module.GetBlob(module.Constant.records[i].Value); + var br = module.GetBlobReader(module.Constant.records[i].Offset); + switch (module.Constant.records[i].Type) { // see ModuleBuilder.AddConstant for the encodings diff --git a/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs b/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs index 1890479247..1239e20215 100644 --- a/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs +++ b/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs @@ -22,10 +22,11 @@ Jeroen Frijters */ using System; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -36,8 +37,8 @@ internal struct Record : IRecord { internal int Parent; - internal int Type; - internal int Value; + internal int Constructor; + internal BlobHandle Value; readonly int IRecord.SortKey => EncodeHasCustomAttribute(Parent); @@ -48,55 +49,49 @@ internal struct Record : IRecord internal const int Index = 0x0C; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Parent = mr.ReadHasCustomAttribute(); - records[i].Type = mr.ReadCustomAttributeType(); - records[i].Value = mr.ReadBlobIndex(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.WriteHasCustomAttribute(records[i].Parent); - mw.WriteCustomAttributeType(records[i].Type); - mw.WriteBlobIndex(records[i].Value); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteHasCustomAttribute() - .WriteCustomAttributeType() - .WriteBlobIndex() - .Value; - } - - internal void Fixup(ModuleBuilder moduleBuilder) - { - var genericParamFixup = moduleBuilder.GenericParam.GetIndexFixup(); - - for (int i = 0; i < rowCount; i++) - { - moduleBuilder.FixupPseudoToken(ref records[i].Type); - moduleBuilder.FixupPseudoToken(ref records[i].Parent); - if (records[i].Parent >> 24 == GenericParamTable.Index) - records[i].Parent = (GenericParamTable.Index << 24) + genericParamFixup[(records[i].Parent & 0xFFFFFF) - 1] + 1; - - // TODO if we ever add support for custom attributes on DeclSecurity or GenericParamConstraint - // we need to fix them up here (because they are sorted tables, like GenericParam) - } - - Sort(); - } - - internal static int EncodeHasCustomAttribute(int token) - { + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Parent = mr.ReadHasCustomAttribute(); + records[i].Constructor = mr.ReadCustomAttributeType(); + records[i].Value = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + { + var h = module.Metadata.AddCustomAttribute( + MetadataTokens.EntityHandle(records[i].Parent), + MetadataTokens.EntityHandle(records[i].Constructor), + records[i].Value); + + Debug.Assert(h == MetadataTokens.CustomAttributeHandle(i)); + } + } + + internal void Fixup(ModuleBuilder moduleBuilder) + { + var genericParamFixup = moduleBuilder.GenericParam.GetIndexFixup(); + + for (int i = 0; i < rowCount; i++) + { + moduleBuilder.FixupPseudoToken(ref records[i].Constructor); + moduleBuilder.FixupPseudoToken(ref records[i].Parent); + if (records[i].Parent >> 24 == GenericParamTable.Index) + records[i].Parent = (GenericParamTable.Index << 24) + genericParamFixup[(records[i].Parent & 0xFFFFFF) - 1] + 1; + + // TODO if we ever add support for custom attributes on DeclSecurity or GenericParamConstraint + // we need to fix them up here (because they are sorted tables, like GenericParam) + } + + Sort(); + } + + internal static int EncodeHasCustomAttribute(int token) + { return (token >> 24) switch { MethodDefTable.Index => (token & 0xFFFFFF) << 5 | 0, @@ -126,6 +121,6 @@ internal static int EncodeHasCustomAttribute(int token) }; } - } + } } diff --git a/src/IKVM.Reflection/Metadata/DeclSecurityTable.cs b/src/IKVM.Reflection/Metadata/DeclSecurityTable.cs index 178ef9894f..48a4cb6207 100644 --- a/src/IKVM.Reflection/Metadata/DeclSecurityTable.cs +++ b/src/IKVM.Reflection/Metadata/DeclSecurityTable.cs @@ -22,10 +22,11 @@ Jeroen Frijters */ using System; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -34,9 +35,10 @@ sealed class DeclSecurityTable : SortedTable internal struct Record : IRecord { + internal short Action; internal int Parent; - internal int PermissionSet; + internal BlobHandle PermissionSet; readonly int IRecord.SortKey => Parent; @@ -46,41 +48,35 @@ internal struct Record : IRecord internal const int Index = 0x0E; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Action = mr.ReadInt16(); - records[i].Parent = mr.ReadHasDeclSecurity(); - records[i].PermissionSet = mr.ReadBlobIndex(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.Write(records[i].Action); - mw.WriteHasDeclSecurity(records[i].Parent); - mw.WriteBlobIndex(records[i].PermissionSet); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(2) - .WriteHasDeclSecurity() - .WriteBlobIndex() - .Value; - } - - internal void Fixup(ModuleBuilder moduleBuilder) - { - for (int i = 0; i < rowCount; i++) - { - var token = records[i].Parent; - moduleBuilder.FixupPseudoToken(ref token); + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Action = mr.ReadInt16(); + records[i].Parent = mr.ReadHasDeclSecurity(); + records[i].PermissionSet = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + { + var h = module.Metadata.AddDeclarativeSecurityAttribute( + MetadataTokens.EntityHandle(records[i].Parent), + (System.Reflection.DeclarativeSecurityAction)records[i].Action, + records[i].PermissionSet); + + Debug.Assert(h == MetadataTokens.DeclarativeSecurityAttributeHandle(i + 1)); + } + } + + internal void Fixup(ModuleBuilder moduleBuilder) + { + for (int i = 0; i < rowCount; i++) + { + var token = records[i].Parent; + moduleBuilder.FixupPseudoToken(ref token); // do the HasDeclSecurity encoding, so that we can sort the table token = (token >> 24) switch @@ -90,12 +86,13 @@ internal void Fixup(ModuleBuilder moduleBuilder) AssemblyTable.Index => (token & 0xFFFFFF) << 2 | 2, _ => throw new InvalidOperationException(), }; + records[i].Parent = token; - } + } - Sort(); - } + Sort(); + } - } + } } diff --git a/src/IKVM.Reflection/Metadata/EventMapTable.cs b/src/IKVM.Reflection/Metadata/EventMapTable.cs index 4c5813b131..8058fb3db8 100644 --- a/src/IKVM.Reflection/Metadata/EventMapTable.cs +++ b/src/IKVM.Reflection/Metadata/EventMapTable.cs @@ -21,6 +21,9 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; using IKVM.Reflection.Writer; @@ -31,48 +34,34 @@ sealed class EventMapTable : SortedTable internal struct Record : IRecord { + internal int Parent; internal int EventList; - int IRecord.SortKey - { - get { return Parent; } - } + readonly int IRecord.SortKey => Parent; - int IRecord.FilterKey - { - get { return Parent; } - } + readonly int IRecord.FilterKey => Parent; } internal const int Index = 0x12; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Parent = mr.ReadTypeDef(); - records[i].EventList = mr.ReadEvent(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.WriteTypeDef(records[i].Parent); - mw.WriteEvent(records[i].EventList); - } - } + internal override void Read(Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Parent = mr.ReadTypeDef(); + records[i].EventList = mr.ReadEvent(); + } + } - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteTypeDef() - .WriteEvent() - .Value; - } + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + module.Metadata.AddEventMap( + System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].Parent), + System.Reflection.Metadata.Ecma335.MetadataTokens.EventDefinitionHandle(records[i].EventList)); + } - } + } } diff --git a/src/IKVM.Reflection/Metadata/EventTable.cs b/src/IKVM.Reflection/Metadata/EventTable.cs index 33116d24ce..56d87885a8 100644 --- a/src/IKVM.Reflection/Metadata/EventTable.cs +++ b/src/IKVM.Reflection/Metadata/EventTable.cs @@ -21,8 +21,11 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { @@ -32,42 +35,38 @@ sealed class EventTable : Table internal struct Record { + internal short EventFlags; - internal int Name; + internal StringHandle Name; internal int EventType; + } internal const int Index = 0x14; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].EventFlags = mr.ReadInt16(); - records[i].Name = mr.ReadStringIndex(); - records[i].EventType = mr.ReadTypeDefOrRef(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.Write(records[i].EventFlags); - mw.WriteStringIndex(records[i].Name); - mw.WriteTypeDefOrRef(records[i].EventType); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(2) - .WriteStringIndex() - .WriteTypeDefOrRef() - .Value; - } - - } + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].EventFlags = mr.ReadInt16(); + records[i].Name = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].EventType = mr.ReadTypeDefOrRef(); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + { + var h = module.Metadata.AddEvent( + (System.Reflection.EventAttributes)records[i].EventFlags, + records[i].Name, + MetadataTokens.EntityHandle(records[i].EventType)); + + Debug.Assert(h == MetadataTokens.EventDefinitionHandle(i + 1)); + } + } + + } } diff --git a/src/IKVM.Reflection/Metadata/ExportedTypeTable.cs b/src/IKVM.Reflection/Metadata/ExportedTypeTable.cs index 6028c0b90c..8d78de6375 100644 --- a/src/IKVM.Reflection/Metadata/ExportedTypeTable.cs +++ b/src/IKVM.Reflection/Metadata/ExportedTypeTable.cs @@ -21,9 +21,11 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -33,49 +35,44 @@ sealed class ExportedTypeTable : Table internal struct Record { + internal int Flags; internal int TypeDefId; - internal int TypeName; - internal int TypeNamespace; + internal StringHandle TypeName; + internal StringHandle TypeNamespace; internal int Implementation; + } internal const int Index = 0x27; - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { records[i].Flags = mr.ReadInt32(); records[i].TypeDefId = mr.ReadInt32(); - records[i].TypeName = mr.ReadStringIndex(); - records[i].TypeNamespace = mr.ReadStringIndex(); + records[i].TypeName = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].TypeNamespace = MetadataTokens.StringHandle(mr.ReadStringIndex()); records[i].Implementation = mr.ReadImplementation(); } } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) { - mw.Write(records[i].Flags); - mw.Write(records[i].TypeDefId); - mw.WriteStringIndex(records[i].TypeName); - mw.WriteStringIndex(records[i].TypeNamespace); - mw.WriteImplementation(records[i].Implementation); + var h = module.Metadata.AddExportedType( + (System.Reflection.TypeAttributes)records[i].Flags, + records[i].TypeNamespace, + records[i].TypeName, + MetadataTokens.EntityHandle(records[i].Implementation), + records[i].TypeDefId); + + Debug.Assert(h == MetadataTokens.ExportedTypeHandle(i + 1)); } } - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(8) - .WriteStringIndex() - .WriteStringIndex() - .WriteImplementation() - .Value; - } - internal int FindOrAddRecord(Record rec) { for (int i = 0; i < rowCount; i++) diff --git a/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs b/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs index 8422fdbfa4..7391747ff8 100644 --- a/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs +++ b/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs @@ -21,6 +21,8 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Reflection.Metadata.Ecma335; + using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; using IKVM.Reflection.Writer; @@ -44,40 +46,31 @@ internal struct Record : IRecord internal const int Index = 0x10; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Offset = mr.ReadInt32(); - records[i].Field = mr.ReadField(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.Write(records[i].Offset); - mw.WriteField(records[i].Field); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(4) - .WriteField() - .Value; - } - - internal void Fixup(ModuleBuilder moduleBuilder) - { - for (int i = 0; i < rowCount; i++) - records[i].Field = moduleBuilder.ResolvePseudoToken(records[i].Field) & 0xFFFFFF; - - Sort(); - } - - } + internal override void Read(Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Offset = mr.ReadInt32(); + records[i].Field = mr.ReadField(); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + module.Metadata.AddFieldLayout( + System.Reflection.Metadata.Ecma335.MetadataTokens.FieldDefinitionHandle(records[i].Field), + records[i].Offset); + } + + internal void Fixup(ModuleBuilder moduleBuilder) + { + for (int i = 0; i < rowCount; i++) + records[i].Field = moduleBuilder.ResolvePseudoToken(records[i].Field) & 0xFFFFFF; + + Sort(); + } + + } } diff --git a/src/IKVM.Reflection/Metadata/FieldMarshalTable.cs b/src/IKVM.Reflection/Metadata/FieldMarshalTable.cs index 99d3d0d149..0e415f263b 100644 --- a/src/IKVM.Reflection/Metadata/FieldMarshalTable.cs +++ b/src/IKVM.Reflection/Metadata/FieldMarshalTable.cs @@ -22,10 +22,10 @@ Jeroen Frijters */ using System; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -36,7 +36,7 @@ internal struct Record : IRecord { internal int Parent; - internal int NativeType; + internal BlobHandle NativeType; readonly int IRecord.SortKey => EncodeHasFieldMarshal(Parent); @@ -46,30 +46,21 @@ internal struct Record : IRecord internal const int Index = 0x0D; - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { records[i].Parent = mr.ReadHasFieldMarshal(); - records[i].NativeType = mr.ReadBlobIndex(); + records[i].NativeType = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); } } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) - { - mw.WriteHasFieldMarshal(records[i].Parent); - mw.WriteBlobIndex(records[i].NativeType); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteHasFieldMarshal() - .WriteBlobIndex() - .Value; + module.Metadata.AddMarshallingDescriptor( + MetadataTokens.EntityHandle(records[i].Parent), + records[i].NativeType); } internal void Fixup(ModuleBuilder moduleBuilder) diff --git a/src/IKVM.Reflection/Metadata/FieldRVATable.cs b/src/IKVM.Reflection/Metadata/FieldRVATable.cs index 1ca0df0a33..6f5642ff99 100644 --- a/src/IKVM.Reflection/Metadata/FieldRVATable.cs +++ b/src/IKVM.Reflection/Metadata/FieldRVATable.cs @@ -21,6 +21,8 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Reflection.Metadata.Ecma335; + using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; using IKVM.Reflection.Writer; @@ -44,7 +46,7 @@ internal struct Record : IRecord internal const int Index = 0x1D; - internal override void Read(MetadataReader mr) + internal override void Read(Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { @@ -53,28 +55,19 @@ internal override void Read(MetadataReader mr) } } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) - { - mw.Write(records[i].RVA); - mw.WriteField(records[i].Field); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(4) - .WriteField() - .Value; + module.Metadata.AddFieldRelativeVirtualAddress( + System.Reflection.Metadata.Ecma335.MetadataTokens.FieldDefinitionHandle(records[i].Field), + records[i].RVA); } - internal void Fixup(ModuleBuilder moduleBuilder, int sdataRVA, int cilRVA) + internal void Fixup(ModuleBuilder moduleBuilder) { for (int i = 0; i < rowCount; i++) { - records[i].RVA = records[i].RVA < 0 ? (records[i].RVA & 0x7fffffff) + cilRVA : sdataRVA; + //records[i].RVA = records[i].RVA < 0 ? (records[i].RVA & 0x7fffffff) + cilRVA : sdataRVA; moduleBuilder.FixupPseudoToken(ref records[i].Field); } diff --git a/src/IKVM.Reflection/Metadata/FieldTable.cs b/src/IKVM.Reflection/Metadata/FieldTable.cs index 4c9e02dee5..78ea185aeb 100644 --- a/src/IKVM.Reflection/Metadata/FieldTable.cs +++ b/src/IKVM.Reflection/Metadata/FieldTable.cs @@ -21,8 +21,10 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { @@ -33,37 +35,28 @@ internal struct Record { internal short Flags; - internal int Name; - internal int Signature; + internal StringHandle Name; + internal BlobHandle Signature; } internal const int Index = 0x04; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Flags = mr.ReadInt16(); - records[i].Name = mr.ReadStringIndex(); - records[i].Signature = mr.ReadBlobIndex(); - } - } - - internal override void Write(MetadataWriter mw) - { - mw.ModuleBuilder.WriteFieldTable(mw); - } + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Flags = mr.ReadInt16(); + records[i].Name = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].Signature = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); + } + } - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(2) - .WriteStringIndex() - .WriteBlobIndex() - .Value; - } + internal override void Write(ModuleBuilder module) + { + module.WriteFieldTable(); + } - } + } } diff --git a/src/IKVM.Reflection/Metadata/FileTable.cs b/src/IKVM.Reflection/Metadata/FileTable.cs index 5825374c19..918364b052 100644 --- a/src/IKVM.Reflection/Metadata/FileTable.cs +++ b/src/IKVM.Reflection/Metadata/FileTable.cs @@ -21,8 +21,11 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { @@ -30,46 +33,43 @@ namespace IKVM.Reflection.Metadata sealed class FileTable : Table { + internal struct Record { + internal StringHandle Name; + internal BlobHandle HashValue; internal int Flags; - internal int Name; - internal int HashValue; } internal const int Index = 0x26; + const int ContainsNoMetaData = 0x0001; + + + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Flags = mr.ReadInt32(); + records[i].Name = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].HashValue = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + { + var h = module.Metadata.AddAssemblyFile( + records[i].Name, + records[i].HashValue, + (records[i].Flags & ContainsNoMetaData) != 0); + + Debug.Assert(h == MetadataTokens.AssemblyFileHandle(i + 1)); + } + } - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Flags = mr.ReadInt32(); - records[i].Name = mr.ReadStringIndex(); - records[i].HashValue = mr.ReadBlobIndex(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.Write(records[i].Flags); - mw.WriteStringIndex(records[i].Name); - mw.WriteBlobIndex(records[i].HashValue); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(4) - .WriteStringIndex() - .WriteBlobIndex() - .Value; - } - - } + } } diff --git a/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs b/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs index 939ede43d6..41601ac069 100644 --- a/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs +++ b/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs @@ -21,9 +21,11 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; + using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -44,39 +46,36 @@ internal struct Record : IRecord internal const int Index = 0x2C; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Owner = mr.ReadGenericParam(); - records[i].Constraint = mr.ReadTypeDefOrRef(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.WriteGenericParam(records[i].Owner); - mw.WriteTypeDefOrRef(records[i].Constraint); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteGenericParam() - .WriteTypeDefOrRef() - .Value; - } - - internal void Fixup(ModuleBuilder moduleBuilder) - { - var fixups = moduleBuilder.GenericParam.GetIndexFixup(); - for (int i = 0; i < rowCount; i++) - records[i].Owner = fixups[records[i].Owner - 1] + 1; - - Sort(); - } - } + internal override void Read(Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Owner = mr.ReadGenericParam(); + records[i].Constraint = mr.ReadTypeDefOrRef(); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + { + var h = module.Metadata.AddGenericParameterConstraint( + System.Reflection.Metadata.Ecma335.MetadataTokens.GenericParameterHandle(records[i].Owner), + System.Reflection.Metadata.Ecma335.MetadataTokens.EntityHandle(records[i].Constraint)); + + Debug.Assert(h == System.Reflection.Metadata.Ecma335.MetadataTokens.GenericParameterConstraintHandle(i + 1)); + } + } + + internal void Fixup(ModuleBuilder moduleBuilder) + { + var fixups = moduleBuilder.GenericParam.GetIndexFixup(); + for (int i = 0; i < rowCount; i++) + records[i].Owner = fixups[records[i].Owner - 1] + 1; + + Sort(); + } + + } + } diff --git a/src/IKVM.Reflection/Metadata/GenericParamTable.cs b/src/IKVM.Reflection/Metadata/GenericParamTable.cs index cbdac3f8be..422574d85c 100644 --- a/src/IKVM.Reflection/Metadata/GenericParamTable.cs +++ b/src/IKVM.Reflection/Metadata/GenericParamTable.cs @@ -23,10 +23,11 @@ Jeroen Frijters */ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -40,7 +41,7 @@ internal struct Record : IRecord internal short Number; internal short Flags; internal int Owner; - internal int Name; + internal StringHandle Name; // not part of the table, we use it to be able to fixup the GenericParamConstraint table internal int unsortedIndex; @@ -53,43 +54,37 @@ internal struct Record : IRecord internal const int Index = 0x2A; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Number = mr.ReadInt16(); - records[i].Flags = mr.ReadInt16(); - records[i].Owner = mr.ReadTypeOrMethodDef(); - records[i].Name = mr.ReadStringIndex(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.Write(records[i].Number); - mw.Write(records[i].Flags); - mw.WriteTypeOrMethodDef(records[i].Owner); - mw.WriteStringIndex(records[i].Name); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(4) - .WriteTypeOrMethodDef() - .WriteStringIndex() - .Value; - } - - internal void Fixup(ModuleBuilder moduleBuilder) - { - for (int i = 0; i < rowCount; i++) - { - int token = records[i].Owner; - moduleBuilder.FixupPseudoToken(ref token); + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Number = mr.ReadInt16(); + records[i].Flags = mr.ReadInt16(); + records[i].Owner = mr.ReadTypeOrMethodDef(); + records[i].Name = MetadataTokens.StringHandle(mr.ReadStringIndex()); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + { + var h = module.Metadata.AddGenericParameter( + MetadataTokens.EntityHandle(records[i].Owner), + (System.Reflection.GenericParameterAttributes)records[i].Flags, + records[i].Name, + records[i].Number); + + Debug.Assert(h == MetadataTokens.GenericParameterHandle(i + 1)); + } + } + + internal void Fixup(ModuleBuilder moduleBuilder) + { + for (int i = 0; i < rowCount; i++) + { + int token = records[i].Owner; + moduleBuilder.FixupPseudoToken(ref token); // do the TypeOrMethodDef encoding, so that we can sort the table records[i].Owner = (token >> 24) switch @@ -100,41 +95,41 @@ internal void Fixup(ModuleBuilder moduleBuilder) }; records[i].unsortedIndex = i; - } + } - Array.Sort(records, 0, rowCount, this); - } + Array.Sort(records, 0, rowCount, this); + } - int IComparer.Compare(Record x, Record y) - { - if (x.Owner == y.Owner) - return x.Number == y.Number ? 0 : (x.Number > y.Number ? 1 : -1); + int IComparer.Compare(Record x, Record y) + { + if (x.Owner == y.Owner) + return x.Number == y.Number ? 0 : (x.Number > y.Number ? 1 : -1); - return x.Owner > y.Owner ? 1 : -1; - } + return x.Owner > y.Owner ? 1 : -1; + } - internal void PatchAttribute(int token, GenericParameterAttributes genericParameterAttributes) - { - records[(token & 0xFFFFFF) - 1].Flags = (short)genericParameterAttributes; - } + internal void PatchAttribute(int token, GenericParameterAttributes genericParameterAttributes) + { + records[(token & 0xFFFFFF) - 1].Flags = (short)genericParameterAttributes; + } - internal int[] GetIndexFixup() - { - var array = new int[rowCount]; - for (int i = 0; i < rowCount; i++) - array[records[i].unsortedIndex] = i; + internal int[] GetIndexFixup() + { + var array = new int[rowCount]; + for (int i = 0; i < rowCount; i++) + array[records[i].unsortedIndex] = i; - return array; - } + return array; + } - internal int FindFirstByOwner(int token) - { - foreach (int i in Filter(token)) - return i; + internal int FindFirstByOwner(int token) + { + foreach (int i in Filter(token)) + return i; - return -1; - } + return -1; + } - } + } } diff --git a/src/IKVM.Reflection/Metadata/ImplMapTable.cs b/src/IKVM.Reflection/Metadata/ImplMapTable.cs index 7bd70bd72c..bfe184cb43 100644 --- a/src/IKVM.Reflection/Metadata/ImplMapTable.cs +++ b/src/IKVM.Reflection/Metadata/ImplMapTable.cs @@ -21,9 +21,10 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -36,7 +37,7 @@ internal struct Record : IRecord internal short MappingFlags; internal int MemberForwarded; - internal int ImportName; + internal StringHandle ImportName; internal int ImportScope; readonly int IRecord.SortKey => MemberForwarded; @@ -47,46 +48,35 @@ internal struct Record : IRecord internal const int Index = 0x1C; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].MappingFlags = mr.ReadInt16(); - records[i].MemberForwarded = mr.ReadMemberForwarded(); - records[i].ImportName = mr.ReadStringIndex(); - records[i].ImportScope = mr.ReadModuleRef(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.Write(records[i].MappingFlags); - mw.WriteMemberForwarded(records[i].MemberForwarded); - mw.WriteStringIndex(records[i].ImportName); - mw.WriteModuleRef(records[i].ImportScope); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(2) - .WriteMemberForwarded() - .WriteStringIndex() - .WriteModuleRef() - .Value; - } - - internal void Fixup(ModuleBuilder moduleBuilder) - { - for (int i = 0; i < rowCount; i++) - moduleBuilder.FixupPseudoToken(ref records[i].MemberForwarded); - - Sort(); - } - - } + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].MappingFlags = mr.ReadInt16(); + records[i].MemberForwarded = mr.ReadMemberForwarded(); + records[i].ImportName = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].ImportScope = mr.ReadModuleRef(); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + module.Metadata.AddMethodImport( + MetadataTokens.MethodDefinitionHandle(records[i].MemberForwarded), + (System.Reflection.MethodImportAttributes)records[i].MappingFlags, + records[i].ImportName, + MetadataTokens.ModuleReferenceHandle(records[i].ImportScope)); + } + + internal void Fixup(ModuleBuilder moduleBuilder) + { + for (int i = 0; i < rowCount; i++) + moduleBuilder.FixupPseudoToken(ref records[i].MemberForwarded); + + Sort(); + } + + } } diff --git a/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs b/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs index 7ee448d608..b66bfbc4d5 100644 --- a/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs +++ b/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs @@ -22,9 +22,11 @@ Jeroen Frijters */ using System; +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; +using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -43,65 +45,60 @@ internal struct Record : IRecord int IRecord.FilterKey => Class; } - internal const int Index = 0x09; - - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Class = mr.ReadTypeDef(); - records[i].Interface = mr.ReadTypeDefOrRef(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.WriteTypeDef(records[i].Class); - mw.WriteEncodedTypeDefOrRef(records[i].Interface); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteTypeDef() - .WriteTypeDefOrRef() - .Value; - } - - internal void Fixup() - { - for (int i = 0; i < rowCount; i++) - { - var token = records[i].Interface; - switch (token >> 24) - { - case 0: - break; - case TypeDefTable.Index: - token = (token & 0xFFFFFF) << 2 | 0; - break; - case TypeRefTable.Index: - token = (token & 0xFFFFFF) << 2 | 1; - break; - case TypeSpecTable.Index: - token = (token & 0xFFFFFF) << 2 | 2; - break; - default: - throw new InvalidOperationException(); - } - - records[i].Interface = token; - } - - // LAMESPEC the CLI spec says that InterfaceImpl should be sorted by { Class, Interface }, - // but it appears to only be necessary to sort by Class (and csc emits InterfaceImpl records in - // source file order, so to be able to support round tripping, we need to retain ordering as well). - Sort(); - } - - } + internal const int Index = (int)TableIndex.InterfaceImpl; + + internal override void Read(Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Class = mr.ReadTypeDef(); + records[i].Interface = mr.ReadTypeDefOrRef(); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + { + var h = module.Metadata.AddInterfaceImplementation( + System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].Class), + System.Reflection.Metadata.Ecma335.MetadataTokens.EntityHandle(records[i].Interface)); + + Debug.Assert(h == System.Reflection.Metadata.Ecma335.MetadataTokens.InterfaceImplementationHandle(i + 1)); + } + } + + internal void Fixup() + { + for (int i = 0; i < rowCount; i++) + { + var token = records[i].Interface; + switch (token >> 24) + { + case 0: + break; + case TypeDefTable.Index: + token = (token & 0xFFFFFF) << 2 | 0; + break; + case TypeRefTable.Index: + token = (token & 0xFFFFFF) << 2 | 1; + break; + case TypeSpecTable.Index: + token = (token & 0xFFFFFF) << 2 | 2; + break; + default: + throw new InvalidOperationException(); + } + + records[i].Interface = token; + } + + // LAMESPEC the CLI spec says that InterfaceImpl should be sorted by { Class, Interface }, + // but it appears to only be necessary to sort by Class (and csc emits InterfaceImpl records in + // source file order, so to be able to support round tripping, we need to retain ordering as well). + Sort(); + } + + } } diff --git a/src/IKVM.Reflection/Metadata/ManifestResourceTable.cs b/src/IKVM.Reflection/Metadata/ManifestResourceTable.cs index 4b05f80c2a..ae3f46a217 100644 --- a/src/IKVM.Reflection/Metadata/ManifestResourceTable.cs +++ b/src/IKVM.Reflection/Metadata/ManifestResourceTable.cs @@ -21,9 +21,12 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -36,42 +39,36 @@ internal struct Record internal int Offset; internal int Flags; - internal int Name; + internal StringHandle Name; internal int Implementation; } internal const int Index = 0x28; - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { records[i].Offset = mr.ReadInt32(); records[i].Flags = mr.ReadInt32(); - records[i].Name = mr.ReadStringIndex(); + records[i].Name = MetadataTokens.StringHandle(mr.ReadStringIndex()); records[i].Implementation = mr.ReadImplementation(); } } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) { - mw.Write(records[i].Offset); - mw.Write(records[i].Flags); - mw.WriteStringIndex(records[i].Name); - mw.WriteImplementation(records[i].Implementation); - } - } + var h = module.Metadata.AddManifestResource( + (System.Reflection.ManifestResourceAttributes)records[i].Flags, + records[i].Name, + MetadataTokens.EntityHandle(records[i].Implementation), + (uint)records[i].Offset); - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(8) - .WriteStringIndex() - .WriteImplementation() - .Value; + Debug.Assert(h == MetadataTokens.ManifestResourceHandle(i + 1)); + } } internal void Fixup(ModuleBuilder moduleBuilder) diff --git a/src/IKVM.Reflection/Metadata/MemberRefTable.cs b/src/IKVM.Reflection/Metadata/MemberRefTable.cs index e2b95332f3..6e7dad9f97 100644 --- a/src/IKVM.Reflection/Metadata/MemberRefTable.cs +++ b/src/IKVM.Reflection/Metadata/MemberRefTable.cs @@ -21,9 +21,11 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -31,46 +33,45 @@ namespace IKVM.Reflection.Metadata sealed class MemberRefTable : Table { - internal const int Index = 0x0A; - internal struct Record { internal int Class; - internal int Name; - internal int Signature; + internal StringHandle Name; + internal BlobHandle Signature; } - internal override void Read(MetadataReader mr) + internal const int Index = 0x0A; + + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { records[i].Class = mr.ReadMemberRefParent(); - records[i].Name = mr.ReadStringIndex(); - records[i].Signature = mr.ReadBlobIndex(); + records[i].Name = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].Signature = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); } } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) { - mw.WriteMemberRefParent(records[i].Class); - mw.WriteStringIndex(records[i].Name); - mw.WriteBlobIndex(records[i].Signature); - } - } + var h = module.Metadata.AddMemberReference( + MetadataTokens.EntityHandle(records[i].Class), + records[i].Name, + records[i].Signature); - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteMemberRefParent() - .WriteStringIndex() - .WriteBlobIndex() - .Value; + Debug.Assert(h == MetadataTokens.MemberReferenceHandle(i + 1)); + } } + /// + /// Finds the specified record in the table and returns the row number. + /// + /// + /// internal int FindOrAddRecord(Record record) { for (int i = 0; i < rowCount; i++) diff --git a/src/IKVM.Reflection/Metadata/MethodDefTable.cs b/src/IKVM.Reflection/Metadata/MethodDefTable.cs index 44ad6348a1..62152f4fb7 100644 --- a/src/IKVM.Reflection/Metadata/MethodDefTable.cs +++ b/src/IKVM.Reflection/Metadata/MethodDefTable.cs @@ -21,8 +21,10 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { @@ -36,46 +38,30 @@ internal struct Record internal int RVA; internal short ImplFlags; internal short Flags; - internal int Name; - internal int Signature; + internal StringHandle Name; + internal BlobHandle Signature; internal int ParamList; } internal const int Index = 0x06; - int baseRVA; - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { records[i].RVA = mr.ReadInt32(); records[i].ImplFlags = mr.ReadInt16(); records[i].Flags = mr.ReadInt16(); - records[i].Name = mr.ReadStringIndex(); - records[i].Signature = mr.ReadBlobIndex(); + records[i].Name = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].Signature = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); records[i].ParamList = mr.ReadParam(); } } - internal override void Write(MetadataWriter mw) - { - mw.ModuleBuilder.WriteMethodDefTable(baseRVA, mw); - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(8) - .WriteStringIndex() - .WriteBlobIndex() - .WriteParam() - .Value; - } - - internal void Fixup(TextSection code) + internal override void Write(ModuleBuilder module) { - baseRVA = (int)code.MethodBodiesRVA; + module.WriteMethodDefTable(); } } diff --git a/src/IKVM.Reflection/Metadata/MethodImplTable.cs b/src/IKVM.Reflection/Metadata/MethodImplTable.cs index ae5fcb6909..153dcf5fc4 100644 --- a/src/IKVM.Reflection/Metadata/MethodImplTable.cs +++ b/src/IKVM.Reflection/Metadata/MethodImplTable.cs @@ -21,9 +21,11 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; + using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -46,45 +48,39 @@ internal struct Record : IRecord internal const int Index = 0x19; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Class = mr.ReadTypeDef(); - records[i].MethodBody = mr.ReadMethodDefOrRef(); - records[i].MethodDeclaration = mr.ReadMethodDefOrRef(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.WriteTypeDef(records[i].Class); - mw.WriteMethodDefOrRef(records[i].MethodBody); - mw.WriteMethodDefOrRef(records[i].MethodDeclaration); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteTypeDef() - .WriteMethodDefOrRef() - .WriteMethodDefOrRef() - .Value; - } - - internal void Fixup(ModuleBuilder moduleBuilder) - { - for (int i = 0; i < rowCount; i++) - { - moduleBuilder.FixupPseudoToken(ref records[i].MethodBody); - moduleBuilder.FixupPseudoToken(ref records[i].MethodDeclaration); - } - - Sort(); - } - } + internal override void Read(Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Class = mr.ReadTypeDef(); + records[i].MethodBody = mr.ReadMethodDefOrRef(); + records[i].MethodDeclaration = mr.ReadMethodDefOrRef(); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + { + var h = module.Metadata.AddMethodImplementation( + System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].Class), + System.Reflection.Metadata.Ecma335.MetadataTokens.EntityHandle(records[i].MethodBody), + System.Reflection.Metadata.Ecma335.MetadataTokens.EntityHandle(records[i].MethodDeclaration)); + + Debug.Assert(h == System.Reflection.Metadata.Ecma335.MetadataTokens.MethodImplementationHandle(i + 1)); + } + } + + internal void Fixup(ModuleBuilder moduleBuilder) + { + for (int i = 0; i < rowCount; i++) + { + moduleBuilder.FixupPseudoToken(ref records[i].MethodBody); + moduleBuilder.FixupPseudoToken(ref records[i].MethodDeclaration); + } + + Sort(); + } + } } diff --git a/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs b/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs index 80c1406fbb..d133d27341 100644 --- a/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs +++ b/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs @@ -23,6 +23,7 @@ Jeroen Frijters */ using System; using System.Collections.Generic; +using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; @@ -49,49 +50,39 @@ internal struct Record : IRecord internal const int Index = 0x18; - // semantics - internal const short Setter = 0x0001; - internal const short Getter = 0x0002; - internal const short Other = 0x0004; - internal const short AddOn = 0x0008; - internal const short RemoveOn = 0x0010; - internal const short Fire = 0x0020; - - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Semantics = mr.ReadInt16(); - records[i].Method = mr.ReadMethodDef(); - records[i].Association = mr.ReadHasSemantics(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.Write(records[i].Semantics); - mw.WriteMethodDef(records[i].Method); - mw.WriteHasSemantics(records[i].Association); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(2) - .WriteMethodDef() - .WriteHasSemantics() - .Value; - } - - internal void Fixup(ModuleBuilder moduleBuilder) - { - for (int i = 0; i < rowCount; i++) - { - moduleBuilder.FixupPseudoToken(ref records[i].Method); - int token = records[i].Association; + // semantics + internal const short Setter = 0x0001; + internal const short Getter = 0x0002; + internal const short Other = 0x0004; + internal const short AddOn = 0x0008; + internal const short RemoveOn = 0x0010; + internal const short Fire = 0x0020; + + internal override void Read(Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Semantics = mr.ReadInt16(); + records[i].Method = mr.ReadMethodDef(); + records[i].Association = mr.ReadHasSemantics(); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + module.Metadata.AddMethodSemantics( + System.Reflection.Metadata.Ecma335.MetadataTokens.EntityHandle(records[i].Association), + (System.Reflection.MethodSemanticsAttributes)records[i].Semantics, + System.Reflection.Metadata.Ecma335.MetadataTokens.MethodDefinitionHandle(records[i].Method)); + } + + internal void Fixup(ModuleBuilder moduleBuilder) + { + for (int i = 0; i < rowCount; i++) + { + moduleBuilder.FixupPseudoToken(ref records[i].Method); + int token = records[i].Association; // do the HasSemantics encoding, so that we can sort the table token = (token >> 24) switch { @@ -99,58 +90,59 @@ internal void Fixup(ModuleBuilder moduleBuilder) PropertyTable.Index => (token & 0xFFFFFF) << 1 | 1, _ => throw new InvalidOperationException(), }; + records[i].Association = token; - } - - Sort(); - } - - internal MethodInfo GetMethod(Module module, int token, bool nonPublic, short semantics) - { - foreach (int i in Filter(token)) - { - if ((records[i].Semantics & semantics) != 0) - { - var method = module.ResolveMethod((MethodDefTable.Index << 24) + records[i].Method); - if (nonPublic || method.IsPublic) - return (MethodInfo)method; - } - } - - return null; - } - - internal MethodInfo[] GetMethods(Module module, int token, bool nonPublic, short semantics) - { - var methods = new List(); - foreach (int i in Filter(token)) - { - if ((records[i].Semantics & semantics) != 0) - { - var method = (MethodInfo)module.ResolveMethod((MethodDefTable.Index << 24) + records[i].Method); - if (nonPublic || method.IsPublic) - methods.Add(method); - } - } - - return methods.ToArray(); - } - - internal void ComputeFlags(Module module, int token, out bool isPublic, out bool isNonPrivate, out bool isStatic) - { - isPublic = false; - isNonPrivate = false; - isStatic = false; - - foreach (int i in Filter(token)) - { - var method = module.ResolveMethod((MethodDefTable.Index << 24) + records[i].Method); - isPublic |= method.IsPublic; - isNonPrivate |= (method.Attributes & MethodAttributes.MemberAccessMask) > MethodAttributes.Private; - isStatic |= method.IsStatic; - } - } - - } + } + + Sort(); + } + + internal MethodInfo GetMethod(Module module, int token, bool nonPublic, short semantics) + { + foreach (int i in Filter(token)) + { + if ((records[i].Semantics & semantics) != 0) + { + var method = module.ResolveMethod((MethodDefTable.Index << 24) + records[i].Method); + if (nonPublic || method.IsPublic) + return (MethodInfo)method; + } + } + + return null; + } + + internal MethodInfo[] GetMethods(Module module, int token, bool nonPublic, short semantics) + { + var methods = new List(); + foreach (int i in Filter(token)) + { + if ((records[i].Semantics & semantics) != 0) + { + var method = (MethodInfo)module.ResolveMethod((MethodDefTable.Index << 24) + records[i].Method); + if (nonPublic || method.IsPublic) + methods.Add(method); + } + } + + return methods.ToArray(); + } + + internal void ComputeFlags(Module module, int token, out bool isPublic, out bool isNonPrivate, out bool isStatic) + { + isPublic = false; + isNonPrivate = false; + isStatic = false; + + foreach (int i in Filter(token)) + { + var method = module.ResolveMethod((MethodDefTable.Index << 24) + records[i].Method); + isPublic |= method.IsPublic; + isNonPrivate |= (method.Attributes & MethodAttributes.MemberAccessMask) > MethodAttributes.Private; + isStatic |= method.IsStatic; + } + } + + } } diff --git a/src/IKVM.Reflection/Metadata/MethodSpecTable.cs b/src/IKVM.Reflection/Metadata/MethodSpecTable.cs index 7a6853daa1..45affb391c 100644 --- a/src/IKVM.Reflection/Metadata/MethodSpecTable.cs +++ b/src/IKVM.Reflection/Metadata/MethodSpecTable.cs @@ -21,9 +21,11 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -35,36 +37,31 @@ internal struct Record { internal int Method; - internal int Instantiation; + internal BlobHandle Instantiation; } internal const int Index = 0x2B; - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { records[i].Method = mr.ReadMethodDefOrRef(); - records[i].Instantiation = mr.ReadBlobIndex(); + records[i].Instantiation = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); } } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) { - mw.WriteMethodDefOrRef(records[i].Method); - mw.WriteBlobIndex(records[i].Instantiation); - } - } + var h = module.Metadata.AddMethodSpecification( + MetadataTokens.EntityHandle(records[i].Method), + records[i].Instantiation); - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteMethodDefOrRef() - .WriteBlobIndex() - .Value; + Debug.Assert(h == MetadataTokens.MethodSpecificationHandle(i + 1)); + } } internal int FindOrAddRecord(Record record) diff --git a/src/IKVM.Reflection/Metadata/ModuleRefTable.cs b/src/IKVM.Reflection/Metadata/ModuleRefTable.cs index 56ae1c4d9d..049deece00 100644 --- a/src/IKVM.Reflection/Metadata/ModuleRefTable.cs +++ b/src/IKVM.Reflection/Metadata/ModuleRefTable.cs @@ -21,43 +21,44 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { - sealed class ModuleRefTable : Table + sealed class ModuleRefTable : Table { internal const int Index = 0x1A; - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) - records[i] = mr.ReadStringIndex(); + records[i] = MetadataTokens.StringHandle(mr.ReadStringIndex()); } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) - mw.WriteStringIndex(records[i]); - } + { + var h = module.Metadata.AddModuleReference( + records[i]); - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteStringIndex() - .Value; + Debug.Assert(h == MetadataTokens.ModuleReferenceHandle(i + 1)); + } } - internal int FindOrAddRecord(int str) + internal int FindOrAddRecord(StringHandle handle) { for (int i = 0; i < rowCount; i++) - if (records[i] == str) + if (records[i] == handle) return i + 1; - return AddRecord(str); + return AddRecord(handle); } } diff --git a/src/IKVM.Reflection/Metadata/ModuleTable.cs b/src/IKVM.Reflection/Metadata/ModuleTable.cs index 060fbde502..2c2c79c9d2 100644 --- a/src/IKVM.Reflection/Metadata/ModuleTable.cs +++ b/src/IKVM.Reflection/Metadata/ModuleTable.cs @@ -21,8 +21,11 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { @@ -33,61 +36,53 @@ internal struct Record { internal short Generation; - internal int Name; // -> StringHeap - internal int Mvid; // -> GuidHeap - internal int EncId; // -> GuidHeap - internal int EncBaseId; // -> GuidHeap + internal StringHandle Name; // -> StringHeap + internal GuidHandle Mvid; // -> GuidHeap + internal GuidHandle EncId; // -> GuidHeap + internal GuidHandle EncBaseId; // -> GuidHeap } internal const int Index = 0x00; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Generation = mr.ReadInt16(); - records[i].Name = mr.ReadStringIndex(); - records[i].Mvid = mr.ReadGuidIndex(); - records[i].EncId = mr.ReadGuidIndex(); - records[i].EncBaseId = mr.ReadGuidIndex(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.Write(records[i].Generation); - mw.WriteStringIndex(records[i].Name); - mw.WriteGuidIndex(records[i].Mvid); - mw.WriteGuidIndex(records[i].EncId); - mw.WriteGuidIndex(records[i].EncBaseId); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(2) - .WriteStringIndex() - .WriteGuidIndex() - .WriteGuidIndex() - .WriteGuidIndex() - .Value; - } - - internal void Add(short generation, int name, int mvid, int encid, int encbaseid) - { - var record = new Record(); - record.Generation = generation; - record.Name = name; - record.Mvid = mvid; - record.EncId = encid; - record.EncBaseId = encbaseid; - AddRecord(record); - } - - } + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Generation = mr.ReadInt16(); + records[i].Name = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].Mvid = MetadataTokens.GuidHandle(mr.ReadGuidIndex()); + records[i].EncId = MetadataTokens.GuidHandle(mr.ReadGuidIndex()); + records[i].EncBaseId = MetadataTokens.GuidHandle(mr.ReadGuidIndex()); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + { + var h = module.Metadata.AddModule( + records[i].Generation, + records[i].Name, + records[i].Mvid, + records[i].EncId, + records[i].EncBaseId); + + Debug.Assert(MetadataTokens.GetRowNumber(h) == i + 1); + } + } + + internal void Add(short generation, StringHandle name, GuidHandle mvid, GuidHandle encid, GuidHandle encbaseid) + { + var record = new Record(); + record.Generation = generation; + record.Name = name; + record.Mvid = mvid; + record.EncId = encid; + record.EncBaseId = encbaseid; + AddRecord(record); + } + + } } diff --git a/src/IKVM.Reflection/Metadata/NestedClassTable.cs b/src/IKVM.Reflection/Metadata/NestedClassTable.cs index 33adc31046..5ee6d6d6d1 100644 --- a/src/IKVM.Reflection/Metadata/NestedClassTable.cs +++ b/src/IKVM.Reflection/Metadata/NestedClassTable.cs @@ -22,9 +22,11 @@ Jeroen Frijters */ using System.Collections.Generic; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -45,7 +47,7 @@ internal struct Record : IRecord internal const int Index = 0x29; - internal override void Read(MetadataReader mr) + internal override void Read(Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { @@ -54,21 +56,12 @@ internal override void Read(MetadataReader mr) } } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) - { - mw.WriteTypeDef(records[i].NestedClass); - mw.WriteTypeDef(records[i].EnclosingClass); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteTypeDef() - .WriteTypeDef() - .Value; + module.Metadata.AddNestedType( + System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].NestedClass), + System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].EnclosingClass)); } internal List GetNestedClasses(int enclosingClass) diff --git a/src/IKVM.Reflection/Metadata/ParamTable.cs b/src/IKVM.Reflection/Metadata/ParamTable.cs index ea0eecaae8..e2255a686d 100644 --- a/src/IKVM.Reflection/Metadata/ParamTable.cs +++ b/src/IKVM.Reflection/Metadata/ParamTable.cs @@ -21,8 +21,10 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { @@ -35,33 +37,25 @@ internal struct Record internal short Flags; internal short Sequence; - internal int Name; + internal StringHandle Name; } internal const int Index = 0x08; - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { records[i].Flags = mr.ReadInt16(); records[i].Sequence = mr.ReadInt16(); - records[i].Name = mr.ReadStringIndex(); + records[i].Name = MetadataTokens.StringHandle(mr.ReadStringIndex()); } } - internal override void Write(MetadataWriter mw) - { - mw.ModuleBuilder.WriteParamTable(mw); - } - - protected override int GetRowSize(RowSizeCalc rsc) + internal override void Write(ModuleBuilder module) { - return rsc - .AddFixed(4) - .WriteStringIndex() - .Value; + module.WriteParamTable(); } } diff --git a/src/IKVM.Reflection/Metadata/PropertyMapTable.cs b/src/IKVM.Reflection/Metadata/PropertyMapTable.cs index b69e2b8943..71cafab7e5 100644 --- a/src/IKVM.Reflection/Metadata/PropertyMapTable.cs +++ b/src/IKVM.Reflection/Metadata/PropertyMapTable.cs @@ -21,13 +21,15 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { sealed class PropertyMapTable : SortedTable - { + { internal struct Record : IRecord { @@ -43,31 +45,22 @@ internal struct Record : IRecord internal const int Index = 0x15; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Parent = mr.ReadTypeDef(); - records[i].PropertyList = mr.ReadProperty(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.WriteTypeDef(records[i].Parent); - mw.WriteProperty(records[i].PropertyList); - } - } + internal override void Read(Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Parent = mr.ReadTypeDef(); + records[i].PropertyList = mr.ReadProperty(); + } + } - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteTypeDef() - .WriteProperty() - .Value; - } - } + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + module.Metadata.AddPropertyMap( + System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].Parent), + System.Reflection.Metadata.Ecma335.MetadataTokens.PropertyDefinitionHandle(records[i].PropertyList)); + } + } } diff --git a/src/IKVM.Reflection/Metadata/PropertyTable.cs b/src/IKVM.Reflection/Metadata/PropertyTable.cs index 06f3a8c9d6..4c610272e7 100644 --- a/src/IKVM.Reflection/Metadata/PropertyTable.cs +++ b/src/IKVM.Reflection/Metadata/PropertyTable.cs @@ -21,8 +21,11 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { @@ -34,42 +37,36 @@ internal struct Record { internal short Flags; - internal int Name; - internal int Type; + internal StringHandle Name; + internal BlobHandle Type; } internal const int Index = 0x17; - internal override void Read(MetadataReader mr) - { - for (int i = 0; i < records.Length; i++) - { - records[i].Flags = mr.ReadInt16(); - records[i].Name = mr.ReadStringIndex(); - records[i].Type = mr.ReadBlobIndex(); - } - } - - internal override void Write(MetadataWriter mw) - { - for (int i = 0; i < rowCount; i++) - { - mw.Write(records[i].Flags); - mw.WriteStringIndex(records[i].Name); - mw.WriteBlobIndex(records[i].Type); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(2) - .WriteStringIndex() - .WriteBlobIndex() - .Value; - } - - } + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) + { + records[i].Flags = mr.ReadInt16(); + records[i].Name = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].Type = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + { + var h = module.Metadata.AddProperty( + (System.Reflection.PropertyAttributes)records[i].Flags, + records[i].Name, + records[i].Type); + + Debug.Assert(h == MetadataTokens.PropertyDefinitionHandle(i + 1)); + } + } + + } } diff --git a/src/IKVM.Reflection/Metadata/RvaSize.cs b/src/IKVM.Reflection/Metadata/RvaSize.cs index cfebbfc312..2240af0940 100644 --- a/src/IKVM.Reflection/Metadata/RvaSize.cs +++ b/src/IKVM.Reflection/Metadata/RvaSize.cs @@ -40,12 +40,6 @@ internal void Read(BinaryReader br) Size = br.ReadUInt32(); } - internal void Write(MetadataWriter mw) - { - mw.Write(VirtualAddress); - mw.Write(Size); - } - } } diff --git a/src/IKVM.Reflection/Metadata/StandAloneSigTable.cs b/src/IKVM.Reflection/Metadata/StandAloneSigTable.cs index 9d64bc7f0a..f490ca2a7d 100644 --- a/src/IKVM.Reflection/Metadata/StandAloneSigTable.cs +++ b/src/IKVM.Reflection/Metadata/StandAloneSigTable.cs @@ -21,35 +21,38 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { - sealed class StandAloneSigTable : Table + sealed class StandAloneSigTable : Table { internal const int Index = 0x11; - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) - records[i] = mr.ReadBlobIndex(); + records[i] = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) - mw.WriteBlobIndex(records[i]); - } + { + var h = module.Metadata.AddStandaloneSignature( + records[i]); - protected override int GetRowSize(Table.RowSizeCalc rsc) - { - return rsc.WriteBlobIndex().Value; + Debug.Assert(h == MetadataTokens.StandaloneSignatureHandle(i + 1)); + } } - internal int FindOrAddRecord(int blob) + internal int FindOrAddRecord(BlobHandle blob) { for (int i = 0; i < rowCount; i++) if (records[i] == blob) diff --git a/src/IKVM.Reflection/Metadata/Table.cs b/src/IKVM.Reflection/Metadata/Table.cs index 9909fd7880..e1e686e647 100644 --- a/src/IKVM.Reflection/Metadata/Table.cs +++ b/src/IKVM.Reflection/Metadata/Table.cs @@ -23,8 +23,8 @@ Jeroen Frijters */ using System; +using IKVM.Reflection.Emit; using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -32,191 +32,15 @@ namespace IKVM.Reflection.Metadata internal abstract class Table { - protected sealed class RowSizeCalc - { - - readonly MetadataWriter mw; - int size; - - /// - /// Initializes a new instance. - /// - /// - internal RowSizeCalc(MetadataWriter mw) - { - this.mw = mw; - } - - internal RowSizeCalc AddFixed(int size) - { - this.size += size; - return this; - } - - internal RowSizeCalc WriteStringIndex() - { - size += mw.bigStrings ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteGuidIndex() - { - size += mw.bigGuids ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteBlobIndex() - { - size += mw.bigBlobs ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteTypeDefOrRef() - { - size += mw.bigTypeDefOrRef ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteField() - { - size += mw.bigField ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteMethodDef() - { - size += mw.bigMethodDef ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteParam() - { - size += mw.bigParam ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteResolutionScope() - { - size += mw.bigResolutionScope ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteMemberRefParent() - { - size += mw.bigMemberRefParent ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteHasCustomAttribute() - { - size += mw.bigHasCustomAttribute ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteCustomAttributeType() - { - size += mw.bigCustomAttributeType ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteHasConstant() - { - size += mw.bigHasConstant ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteTypeDef() - { - size += mw.bigTypeDef ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteMethodDefOrRef() - { - size += mw.bigMethodDefOrRef ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteEvent() - { - size += mw.bigEvent ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteProperty() - { - size += mw.bigProperty ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteHasSemantics() - { - size += mw.bigHasSemantics ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteImplementation() - { - size += mw.bigImplementation ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteTypeOrMethodDef() - { - size += mw.bigTypeOrMethodDef ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteGenericParam() - { - size += mw.bigGenericParam ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteHasDeclSecurity() - { - size += mw.bigHasDeclSecurity ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteMemberForwarded() - { - size += mw.bigMemberForwarded ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteModuleRef() - { - size += mw.bigModuleRef ? 4 : 2; - return this; - } - - internal RowSizeCalc WriteHasFieldMarshal() - { - size += mw.bigHasFieldMarshal ? 4 : 2; - return this; - } - - internal int Value - { - get { return size; } - } - - } - internal bool Sorted; internal bool IsBig => RowCount > 65535; internal abstract int RowCount { get; set; } - internal abstract void Write(MetadataWriter mw); - internal abstract void Read(MetadataReader mr); - internal int GetLength(MetadataWriter md) => RowCount * GetRowSize(new RowSizeCalc(md)); - - protected abstract int GetRowSize(RowSizeCalc rsc); + internal abstract void Write(ModuleBuilder module); } @@ -232,11 +56,6 @@ internal sealed override int RowCount set { rowCount = value; records = new T[value]; } } - protected override int GetRowSize(RowSizeCalc rsc) - { - throw new InvalidOperationException(); - } - internal int AddRecord(T newRecord) { if (rowCount == records.Length) @@ -251,9 +70,9 @@ internal int AddVirtualRecord() return ++rowCount; } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { - throw new InvalidOperationException(); + } } diff --git a/src/IKVM.Reflection/Metadata/TypeDefTable.cs b/src/IKVM.Reflection/Metadata/TypeDefTable.cs index 98ed8e8b2d..2cc00d42bc 100644 --- a/src/IKVM.Reflection/Metadata/TypeDefTable.cs +++ b/src/IKVM.Reflection/Metadata/TypeDefTable.cs @@ -21,8 +21,10 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { @@ -34,8 +36,8 @@ internal struct Record { internal int Flags; - internal int TypeName; - internal int TypeNamespace; + internal StringHandle TypeName; + internal StringHandle TypeNamespace; internal int Extends; internal int FieldList; internal int MethodList; @@ -44,22 +46,22 @@ internal struct Record internal const int Index = 0x02; - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { records[i].Flags = mr.ReadInt32(); - records[i].TypeName = mr.ReadStringIndex(); - records[i].TypeNamespace = mr.ReadStringIndex(); + records[i].TypeName = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].TypeNamespace = MetadataTokens.StringHandle(mr.ReadStringIndex()); records[i].Extends = mr.ReadTypeDefOrRef(); records[i].FieldList = mr.ReadField(); records[i].MethodList = mr.ReadMethodDef(); } } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { - mw.ModuleBuilder.WriteTypeDefTable(mw); + module.WriteTypeDefTable(); } internal int AllocToken() @@ -67,17 +69,6 @@ internal int AllocToken() return 0x02000000 + AddVirtualRecord(); } - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .AddFixed(4) - .WriteStringIndex() - .WriteStringIndex() - .WriteTypeDefOrRef() - .WriteField() - .WriteMethodDef() - .Value; - } } } diff --git a/src/IKVM.Reflection/Metadata/TypeRefTable.cs b/src/IKVM.Reflection/Metadata/TypeRefTable.cs index 5dc206bdd8..bc68e02bdf 100644 --- a/src/IKVM.Reflection/Metadata/TypeRefTable.cs +++ b/src/IKVM.Reflection/Metadata/TypeRefTable.cs @@ -21,9 +21,11 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -35,40 +37,34 @@ internal struct Record { internal int ResolutionScope; - internal int TypeName; - internal int TypeNamespace; + internal StringHandle TypeName; + internal StringHandle TypeNamespace; } internal const int Index = 0x01; - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { records[i].ResolutionScope = mr.ReadResolutionScope(); - records[i].TypeName = mr.ReadStringIndex(); - records[i].TypeNamespace = mr.ReadStringIndex(); + records[i].TypeName = MetadataTokens.StringHandle(mr.ReadStringIndex()); + records[i].TypeNamespace = MetadataTokens.StringHandle(mr.ReadStringIndex()); } } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) { - mw.WriteResolutionScope(records[i].ResolutionScope); - mw.WriteStringIndex(records[i].TypeName); - mw.WriteStringIndex(records[i].TypeNamespace); - } - } + var h = module.Metadata.AddTypeReference( + MetadataTokens.EntityHandle(records[i].ResolutionScope), + records[i].TypeNamespace, + records[i].TypeName); - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteResolutionScope() - .WriteStringIndex() - .WriteStringIndex() - .Value; + Debug.Assert(h == MetadataTokens.TypeReferenceHandle(i + 1)); + } } internal void Fixup(ModuleBuilder moduleBuilder) diff --git a/src/IKVM.Reflection/Metadata/TypeSpecTable.cs b/src/IKVM.Reflection/Metadata/TypeSpecTable.cs index d3f2486d40..1a3e7c6abc 100644 --- a/src/IKVM.Reflection/Metadata/TypeSpecTable.cs +++ b/src/IKVM.Reflection/Metadata/TypeSpecTable.cs @@ -21,32 +21,35 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { - sealed class TypeSpecTable : Table + sealed class TypeSpecTable : Table { internal const int Index = 0x1B; - internal override void Read(MetadataReader mr) + internal override void Read(IKVM.Reflection.Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) - records[i] = mr.ReadBlobIndex(); + records[i] = MetadataTokens.BlobHandle(mr.ReadBlobIndex()); } - internal override void Write(MetadataWriter mw) + internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) - mw.WriteBlobIndex(records[i]); - } + { + var h = module.Metadata.AddTypeSpecification( + records[i]); - protected override int GetRowSize(Table.RowSizeCalc rsc) - { - return rsc.WriteBlobIndex().Value; + Debug.Assert(h == MetadataTokens.TypeSpecificationHandle(i + 1)); + } } } diff --git a/src/IKVM.Reflection/MissingModule.cs b/src/IKVM.Reflection/MissingModule.cs index 9e0a14c99b..6bd65f4746 100644 --- a/src/IKVM.Reflection/MissingModule.cs +++ b/src/IKVM.Reflection/MissingModule.cs @@ -23,6 +23,7 @@ Jeroen Frijters */ using System; using System.Collections.Generic; +using System.Reflection.Metadata; namespace IKVM.Reflection { @@ -121,7 +122,7 @@ public override int __Subsystem get { throw new MissingModuleException(this); } } - internal override void ExportTypes(int fileToken, IKVM.Reflection.Emit.ModuleBuilder manifestModule) + internal override void ExportTypes(AssemblyFileHandle handle, IKVM.Reflection.Emit.ModuleBuilder manifestModule) { throw new MissingModuleException(this); } @@ -157,10 +158,10 @@ public override byte[] __ModuleHash { if (index == -1) throw new MissingModuleException(this); - if (assembly.ManifestModule.File.records[index].HashValue == 0) + if (assembly.ManifestModule.File.records[index].HashValue.IsNil) return null; - var br = assembly.ManifestModule.GetBlob(assembly.ManifestModule.File.records[index].HashValue); + var br = assembly.ManifestModule.GetBlobReader(assembly.ManifestModule.File.records[index].HashValue); return br.ReadBytes(br.Length); } } diff --git a/src/IKVM.Reflection/MissingType.cs b/src/IKVM.Reflection/MissingType.cs index 50ae6a004c..99ce241fec 100644 --- a/src/IKVM.Reflection/MissingType.cs +++ b/src/IKVM.Reflection/MissingType.cs @@ -53,12 +53,6 @@ internal MissingType(Module module, Type declaringType, string ns, string name) this.ns = ns; this.name = name; MarkKnownType(ns, name); - - // HACK we need to handle the Windows Runtime projected types that change from ValueType to Class or v.v. - if (WindowsRuntimeProjection.IsProjectedValueType(ns, name, module)) - typeFlags |= TypeFlags.ValueType; - else if (WindowsRuntimeProjection.IsProjectedReferenceType(ns, name, module)) - typeFlags |= TypeFlags.NotValueType; } internal override MethodBase FindMethod(string name, MethodSignature signature) @@ -130,21 +124,6 @@ protected override bool IsValueTypeImpl return true; case TypeFlags.NotValueType: return false; - case TypeFlags.ValueType | TypeFlags.NotValueType: - if (WindowsRuntimeProjection.IsProjectedValueType(ns, name, module)) - { - typeFlags &= ~TypeFlags.NotValueType; - return true; - } - else if (WindowsRuntimeProjection.IsProjectedReferenceType(ns, name, module)) - { - typeFlags &= ~TypeFlags.ValueType; - return false; - } - else - { - goto default; - } default: if (module.universe.ResolveMissingTypeIsValueType(this)) typeFlags |= TypeFlags.ValueType; diff --git a/src/IKVM.Reflection/Module.cs b/src/IKVM.Reflection/Module.cs index 774731fdc2..0668a67230 100644 --- a/src/IKVM.Reflection/Module.cs +++ b/src/IKVM.Reflection/Module.cs @@ -23,6 +23,7 @@ Jeroen Frijters */ using System; using System.Collections.Generic; +using System.Reflection.Metadata; using IKVM.Reflection.Metadata; using IKVM.Reflection.Reader; @@ -85,7 +86,7 @@ internal Module(Universe universe) internal Table[] GetTables() { - Table[] tables = new Table[64]; + var tables = new Table[64]; tables[ModuleTable.Index] = ModuleTable; tables[TypeRefTable.Index] = TypeRef; tables[TypeDefTable.Index] = TypeDef; @@ -518,7 +519,7 @@ public virtual System.Security.Cryptography.X509Certificates.X509Certificate Get internal abstract Type GetModuleType(); - internal abstract ByteReader GetBlob(int blobIndex); + internal abstract ByteReader GetBlobReader(BlobHandle handle); internal IList GetDeclarativeSecurity(int metadataToken) { @@ -534,12 +535,12 @@ internal virtual void Dispose() } - internal virtual void ExportTypes(int fileToken, IKVM.Reflection.Emit.ModuleBuilder manifestModule) + internal virtual void ExportTypes(AssemblyFileHandle handle, IKVM.Reflection.Emit.ModuleBuilder manifestModule) { } - internal virtual string GetString(int index) + internal virtual string GetString(StringHandle handle) { throw new NotSupportedException(); } @@ -579,7 +580,7 @@ internal sealed override Type GetModuleType() throw InvalidOperationException(); } - internal sealed override ByteReader GetBlob(int blobIndex) + internal sealed override ByteReader GetBlobReader(BlobHandle handle) { throw InvalidOperationException(); } diff --git a/src/IKVM.Reflection/Reader/AssemblyReader.cs b/src/IKVM.Reflection/Reader/AssemblyReader.cs index e5c0300ea0..b3379ffbe9 100644 --- a/src/IKVM.Reflection/Reader/AssemblyReader.cs +++ b/src/IKVM.Reflection/Reader/AssemblyReader.cs @@ -67,8 +67,8 @@ AssemblyName GetNameImpl(ref AssemblyTable.Record rec) var name = new AssemblyName(); name.Name = manifestModule.GetString(rec.Name); name.Version = new Version(rec.MajorVersion, rec.MinorVersion, rec.BuildNumber, rec.RevisionNumber); - name.SetPublicKey(rec.PublicKey != 0 ? manifestModule.GetBlobCopy(rec.PublicKey) : Array.Empty()); - name.CultureName = rec.Culture != 0 ? manifestModule.GetString(rec.Culture) : ""; + name.SetPublicKey(rec.PublicKey.IsNil == false ? manifestModule.GetBlobCopy(rec.PublicKey) : Array.Empty()); + name.CultureName = rec.Culture.IsNil == false ? manifestModule.GetString(rec.Culture) : ""; name.HashAlgorithm = (AssemblyHashAlgorithm)rec.HashAlgId; name.CodeBase = CodeBase; @@ -133,6 +133,7 @@ internal override Type FindType(TypeName typeName) type = GetModule(i).FindType(typeName); } } + return type; } @@ -197,35 +198,29 @@ public override Module[] GetModules(bool getResourceModules) public override Module GetModule(string name) { if (name.Equals(manifestModule.ScopeName, StringComparison.OrdinalIgnoreCase)) - { return manifestModule; - } - int index = GetModuleIndex(name); + + var index = GetModuleIndex(name); if (index != -1) - { return GetModule(index); - } + return null; } - private int GetModuleIndex(string name) + int GetModuleIndex(string name) { for (int i = 0; i < manifestModule.File.records.Length; i++) - { if (name.Equals(manifestModule.GetString(manifestModule.File.records[i].Name), StringComparison.OrdinalIgnoreCase)) - { return i; - } - } + return -1; } - private Module GetModule(int index) + Module GetModule(int index) { if (externalModules[index] != null) - { return externalModules[index]; - } + return LoadModule(index, null, manifestModule.GetString(manifestModule.File.records[index].Name)); } diff --git a/src/IKVM.Reflection/Reader/ByteReader.cs b/src/IKVM.Reflection/Reader/ByteReader.cs index 8632ae5ea2..4e099043e8 100644 --- a/src/IKVM.Reflection/Reader/ByteReader.cs +++ b/src/IKVM.Reflection/Reader/ByteReader.cs @@ -22,104 +22,106 @@ Jeroen Frijters */ using System; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Text; namespace IKVM.Reflection.Reader { sealed class ByteReader - { - - byte[] buffer; - int pos; - int end; - - /// - /// Initializes a new instance. - /// - /// - /// - /// - internal ByteReader(byte[] buffer, int offset, int length) - { - this.buffer = buffer; - this.pos = offset; - this.end = pos + length; - } - - internal static ByteReader FromBlob(byte[] blobHeap, int blob) - { - var br = new ByteReader(blobHeap, blob, 4); - var length = br.ReadCompressedUInt(); - br.end = br.pos + length; - return br; - } - - internal int Length - { - get { return end - pos; } - } - - internal byte PeekByte() - { - if (pos == end) - throw new BadImageFormatException(); - - return buffer[pos]; - } - - internal byte ReadByte() - { - if (pos == end) - throw new BadImageFormatException(); - - return buffer[pos++]; - } - - internal byte[] ReadBytes(int count) - { - if (count < 0) - throw new BadImageFormatException(); - if (end - pos < count) - throw new BadImageFormatException(); - - var buf = new byte[count]; - Buffer.BlockCopy(buffer, pos, buf, 0, count); - pos += count; - return buf; - } - - internal int ReadCompressedUInt() - { - var b1 = ReadByte(); - if (b1 <= 0x7F) - { - return b1; - } - else if ((b1 & 0xC0) == 0x80) - { - var b2 = ReadByte(); - return ((b1 & 0x3F) << 8) | b2; - } - else - { - var b2 = ReadByte(); - var b3 = ReadByte(); - var b4 = ReadByte(); - return ((b1 & 0x3F) << 24) + (b2 << 16) + (b3 << 8) + b4; - } - } - - internal int ReadCompressedInt() - { - var b1 = PeekByte(); - var value = ReadCompressedUInt(); - if ((value & 1) == 0) - { - return value >> 1; - } - else - { + { + + byte[] buffer; + int pos; + int end; + + /// + /// Initializes a new instance. + /// + /// + /// + /// + internal ByteReader(byte[] buffer, int offset, int length) + { + this.buffer = buffer; + this.pos = offset; + this.end = pos + length; + } + + internal static ByteReader FromBlob(byte[] blobHeap, BlobHandle blob) + { + var br = new ByteReader(blobHeap, MetadataTokens.GetHeapOffset(blob), 4); + var length = br.ReadCompressedUInt(); + br.end = br.pos + length; + return br; + } + + internal int Length + { + get { return end - pos; } + } + + internal byte PeekByte() + { + if (pos == end) + throw new BadImageFormatException(); + + return buffer[pos]; + } + + internal byte ReadByte() + { + if (pos == end) + throw new BadImageFormatException(); + + return buffer[pos++]; + } + + internal byte[] ReadBytes(int count) + { + if (count < 0) + throw new BadImageFormatException(); + if (end - pos < count) + throw new BadImageFormatException(); + + var buf = new byte[count]; + Buffer.BlockCopy(buffer, pos, buf, 0, count); + pos += count; + return buf; + } + + internal int ReadCompressedUInt() + { + var b1 = ReadByte(); + if (b1 <= 0x7F) + { + return b1; + } + else if ((b1 & 0xC0) == 0x80) + { + var b2 = ReadByte(); + return ((b1 & 0x3F) << 8) | b2; + } + else + { + var b2 = ReadByte(); + var b3 = ReadByte(); + var b4 = ReadByte(); + return ((b1 & 0x3F) << 24) + (b2 << 16) + (b3 << 8) + b4; + } + } + + internal int ReadCompressedInt() + { + var b1 = PeekByte(); + var value = ReadCompressedUInt(); + if ((value & 1) == 0) + { + return value >> 1; + } + else + { return (b1 & 0xC0) switch { 0 or 0x40 => (value >> 1) - 0x40, @@ -127,103 +129,103 @@ internal int ReadCompressedInt() _ => (value >> 1) - 0x10000000, }; } - } - - internal string ReadString() - { - if (PeekByte() == 0xFF) - { - pos++; - return null; - } - - var length = ReadCompressedUInt(); - var str = Encoding.UTF8.GetString(buffer, pos, length); - pos += length; - return str; - } - - internal char ReadChar() - { - return (char)ReadInt16(); - } - - internal sbyte ReadSByte() - { - return (sbyte)ReadByte(); - } - - internal short ReadInt16() - { - if (end - pos < 2) - throw new BadImageFormatException(); - - var b1 = buffer[pos++]; - var b2 = buffer[pos++]; - return (short)(b1 | (b2 << 8)); - } - - internal ushort ReadUInt16() - { - return (ushort)ReadInt16(); - } - - internal int ReadInt32() - { - if (end - pos < 4) - throw new BadImageFormatException(); - - var b1 = buffer[pos++]; - var b2 = buffer[pos++]; - var b3 = buffer[pos++]; - var b4 = buffer[pos++]; - return (int)(b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)); - } - - internal uint ReadUInt32() - { - return (uint)ReadInt32(); - } - - internal long ReadInt64() - { - ulong lo = ReadUInt32(); - ulong hi = ReadUInt32(); - return (long)(lo | (hi << 32)); - } - - internal ulong ReadUInt64() - { - return (ulong)ReadInt64(); - } - - internal float ReadSingle() - { - return SingleConverter.Int32BitsToSingle(ReadInt32()); - } - - internal double ReadDouble() - { - return BitConverter.Int64BitsToDouble(ReadInt64()); - } - - internal ByteReader Slice(int length) - { - if (end - pos < length) - throw new BadImageFormatException(); - - var br = new ByteReader(buffer, pos, length); - pos += length; - return br; - } - - // NOTE this method only works if the original offset was aligned and for alignments that are a power of 2 - internal void Align(int alignment) - { - alignment--; - pos = (pos + alignment) & ~alignment; - } - - } + } + + internal string ReadString() + { + if (PeekByte() == 0xFF) + { + pos++; + return null; + } + + var length = ReadCompressedUInt(); + var str = Encoding.UTF8.GetString(buffer, pos, length); + pos += length; + return str; + } + + internal char ReadChar() + { + return (char)ReadInt16(); + } + + internal sbyte ReadSByte() + { + return (sbyte)ReadByte(); + } + + internal short ReadInt16() + { + if (end - pos < 2) + throw new BadImageFormatException(); + + var b1 = buffer[pos++]; + var b2 = buffer[pos++]; + return (short)(b1 | (b2 << 8)); + } + + internal ushort ReadUInt16() + { + return (ushort)ReadInt16(); + } + + internal int ReadInt32() + { + if (end - pos < 4) + throw new BadImageFormatException(); + + var b1 = buffer[pos++]; + var b2 = buffer[pos++]; + var b3 = buffer[pos++]; + var b4 = buffer[pos++]; + return (int)(b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)); + } + + internal uint ReadUInt32() + { + return (uint)ReadInt32(); + } + + internal long ReadInt64() + { + ulong lo = ReadUInt32(); + ulong hi = ReadUInt32(); + return (long)(lo | (hi << 32)); + } + + internal ulong ReadUInt64() + { + return (ulong)ReadInt64(); + } + + internal float ReadSingle() + { + return SingleConverter.Int32BitsToSingle(ReadInt32()); + } + + internal double ReadDouble() + { + return BitConverter.Int64BitsToDouble(ReadInt64()); + } + + internal ByteReader Slice(int length) + { + if (end - pos < length) + throw new BadImageFormatException(); + + var br = new ByteReader(buffer, pos, length); + pos += length; + return br; + } + + // NOTE this method only works if the original offset was aligned and for alignments that are a power of 2 + internal void Align(int alignment) + { + alignment--; + pos = (pos + alignment) & ~alignment; + } + + } } diff --git a/src/IKVM.Reflection/Reader/Field.cs b/src/IKVM.Reflection/Reader/Field.cs index 79d1c1ab27..5eee7d0eb8 100644 --- a/src/IKVM.Reflection/Reader/Field.cs +++ b/src/IKVM.Reflection/Reader/Field.cs @@ -123,7 +123,7 @@ public override bool __TryGetFieldOffset(out int offset) internal override FieldSignature FieldSignature { - get { return lazyFieldSig ??= FieldSignature.ReadSig(module, module.GetBlob(module.Field.records[index].Signature), declaringType); } + get { return lazyFieldSig ??= FieldSignature.ReadSig(module, module.GetBlobReader(module.Field.records[index].Signature), declaringType); } } internal override int ImportTo(Emit.ModuleBuilder module) diff --git a/src/IKVM.Reflection/Reader/GenericTypeParameter.cs b/src/IKVM.Reflection/Reader/GenericTypeParameter.cs index 13d953ae35..48def99c44 100644 --- a/src/IKVM.Reflection/Reader/GenericTypeParameter.cs +++ b/src/IKVM.Reflection/Reader/GenericTypeParameter.cs @@ -121,7 +121,7 @@ public override CustomModifiers[] __GetGenericParameterConstraintCustomModifiers if ((metadataToken >> 24) == TypeSpecTable.Index) { var index = (metadataToken & 0xFFFFFF) - 1; - mods = CustomModifiers.Read(module, module.GetBlob(module.TypeSpec.records[index]), context); + mods = CustomModifiers.Read(module, module.GetBlobReader(module.TypeSpec.records[index]), context); } list.Add(mods); diff --git a/src/IKVM.Reflection/Reader/MethodDefImpl.cs b/src/IKVM.Reflection/Reader/MethodDefImpl.cs index f7a4ec38ec..d2a04e7ba4 100644 --- a/src/IKVM.Reflection/Reader/MethodDefImpl.cs +++ b/src/IKVM.Reflection/Reader/MethodDefImpl.cs @@ -228,7 +228,7 @@ public override Module Module internal override MethodSignature MethodSignature { - get { return lazyMethodSignature ?? (lazyMethodSignature = MethodSignature.ReadSig(module, module.GetBlob(module.MethodDef.records[index].Signature), this)); } + get { return lazyMethodSignature ?? (lazyMethodSignature = MethodSignature.ReadSig(module, module.GetBlobReader(module.MethodDef.records[index].Signature), this)); } } internal override int ImportTo(Emit.ModuleBuilder module) diff --git a/src/IKVM.Reflection/Reader/ModuleReader.cs b/src/IKVM.Reflection/Reader/ModuleReader.cs index a00889a975..9b215566c6 100644 --- a/src/IKVM.Reflection/Reader/ModuleReader.cs +++ b/src/IKVM.Reflection/Reader/ModuleReader.cs @@ -24,6 +24,8 @@ Jeroen Frijters using System; using System.Collections.Generic; using System.IO; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Text; using IKVM.Reflection.Metadata; @@ -89,7 +91,7 @@ internal Type GetType(ModuleReader module) FieldInfo[] fields; MethodBase[] methods; MemberInfo[] memberRefs; - Dictionary strings = new Dictionary(); + Dictionary strings = new Dictionary(); Dictionary types = new Dictionary(); Dictionary forwardedTypes = new Dictionary(); @@ -108,8 +110,6 @@ internal ModuleReader(AssemblyReader assembly, Universe universe, Stream stream, this.location = location; Read(stream, mapped); - if (universe != null && universe.WindowsRuntimeProjection && imageRuntimeVersion.StartsWith("WindowsRuntime ", StringComparison.Ordinal)) - WindowsRuntimeProjection.Patch(this, strings, ref imageRuntimeVersion, ref blobHeap); if (assembly == null && AssemblyTable.records.Length != 0) assembly = new AssemblyReader(location, this); @@ -285,19 +285,19 @@ void PopulateTypeDef() } } - internal override string GetString(int index) + internal override string GetString(StringHandle handle) { - if (index == 0) + if (handle.IsNil) return null; - if (!strings.TryGetValue(index, out var str)) + if (!strings.TryGetValue(handle, out var str)) { int len = 0; - while (stringHeap[index + len] != 0) + while (stringHeap[MetadataTokens.GetHeapOffset(handle) + len] != 0) len++; - str = Encoding.UTF8.GetString(stringHeap, index, len); - strings.Add(index, str); + str = Encoding.UTF8.GetString(stringHeap, MetadataTokens.GetHeapOffset(handle), len); + strings.Add(handle, str); } return str; @@ -324,26 +324,29 @@ static int ReadCompressedUInt(byte[] buffer, ref int offset) } } - internal byte[] GetBlobCopy(int blobIndex) + internal byte[] GetBlobCopy(BlobHandle handle) { - var len = ReadCompressedUInt(blobHeap, ref blobIndex); + var idx = MetadataTokens.GetHeapOffset(handle); + var len = ReadCompressedUInt(blobHeap, ref idx); var buf = new byte[len]; - Buffer.BlockCopy(blobHeap, blobIndex, buf, 0, len); + Buffer.BlockCopy(blobHeap, idx, buf, 0, len); return buf; } - internal override ByteReader GetBlob(int blobIndex) + internal override ByteReader GetBlobReader(BlobHandle handle) { - return ByteReader.FromBlob(blobHeap, blobIndex); + return ByteReader.FromBlob(blobHeap, handle); } public override string ResolveString(int metadataToken) { - if (!strings.TryGetValue(metadataToken, out var str)) - { - if ((metadataToken >> 24) != 0x70) - throw TokenOutOfRangeException(metadataToken); + if ((metadataToken >> 24) != 0x70) + throw TokenOutOfRangeException(metadataToken); + + var h = MetadataTokens.StringHandle(metadataToken); + if (strings.TryGetValue(h, out var str) == false) + { lazyUserStringHeap ??= ReadHeap(GetStream(), userStringHeapOffset, userStringHeapSize); var index = metadataToken & 0xFFFFFF; @@ -356,7 +359,7 @@ public override string ResolveString(int metadataToken) } str = sb.ToString(); - strings.Add(metadataToken, str); + strings.Add(h, str); } return str; } @@ -467,7 +470,7 @@ internal override Type ResolveType(int metadataToken, IGenericContext context) } } - Module ResolveModuleRef(int moduleNameIndex) + Module ResolveModuleRef(StringHandle moduleNameIndex) { var moduleName = GetString(moduleNameIndex); return assembly.GetModule(moduleName) ?? throw new FileNotFoundException(moduleName); @@ -507,7 +510,7 @@ public Type GetGenericMethodArgument(int index) } - TypeName GetTypeName(int typeNamespace, int typeName) + TypeName GetTypeName(StringHandle typeNamespace, StringHandle typeName) { return new TypeName(GetString(typeNamespace), GetString(typeName)); } @@ -529,14 +532,14 @@ Assembly ResolveAssemblyRefImpl(ref AssemblyRefTable.Record rec) rec.MinorVersion, rec.BuildNumber, rec.RevisionNumber, - rec.Culture == 0 ? "neutral" : GetString(rec.Culture), - rec.PublicKeyOrToken == 0 ? Array.Empty() : (rec.Flags & PublicKey) == 0 ? GetBlobCopy(rec.PublicKeyOrToken) : AssemblyName.ComputePublicKeyToken(GetBlobCopy(rec.PublicKeyOrToken)), + rec.Culture.IsNil ? "neutral" : GetString(rec.Culture), + rec.PublicKeyOrToken.IsNil ? Array.Empty() : (rec.Flags & PublicKey) == 0 ? GetBlobCopy(rec.PublicKeyOrToken) : AssemblyName.ComputePublicKeyToken(GetBlobCopy(rec.PublicKeyOrToken)), rec.Flags); return universe.Load(name, this, true); } - public override Guid ModuleVersionId => GuidFromSpan(guidHeap.AsSpan(16 * (ModuleTable.records[0].Mvid - 1), 16)); + public override Guid ModuleVersionId => GuidFromSpan(guidHeap.AsSpan(16 * (MetadataTokens.GetHeapOffset(ModuleTable.records[0].Mvid) - 1), 16)); /// /// Creates a new from a span. Optimized for .NET. @@ -725,8 +728,8 @@ public override Type[] __ResolveOptionalParameterTypes(int metadataToken, Type[] } else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount) { - int sig = MemberRef.records[index].Signature; - return Signature.ReadOptionalParameterTypes(this, GetBlob(sig), new GenericContext(genericTypeArguments, genericMethodArguments), out customModifiers); + var sig = MemberRef.records[index].Signature; + return Signature.ReadOptionalParameterTypes(this, GetBlobReader(sig), new GenericContext(genericTypeArguments, genericMethodArguments), out customModifiers); } else if ((metadataToken >> 24) == MethodDefTable.Index && index < MethodDef.RowCount) { @@ -782,7 +785,7 @@ private MemberInfo GetMemberRef(int index, Type[] genericTypeArguments, Type[] g if (memberRefs[index] == null) { int owner = MemberRef.records[index].Class; - int sig = MemberRef.records[index].Signature; + var sig = MemberRef.records[index].Signature; string name = GetString(MemberRef.records[index].Name); switch (owner >> 24) { @@ -1002,17 +1005,18 @@ internal Stream GetManifestResourceStream(string resourceName) public override AssemblyName[] __GetReferencedAssemblies() { - List list = new List(); + var list = new List(); for (int i = 0; i < AssemblyRef.records.Length; i++) { - AssemblyName name = new AssemblyName(); + var name = new AssemblyName(); name.Name = GetString(AssemblyRef.records[i].Name); name.Version = new Version( AssemblyRef.records[i].MajorVersion, AssemblyRef.records[i].MinorVersion, AssemblyRef.records[i].BuildNumber, AssemblyRef.records[i].RevisionNumber); - if (AssemblyRef.records[i].PublicKeyOrToken != 0) + + if (AssemblyRef.records[i].PublicKeyOrToken.IsNil == false) { byte[] keyOrToken = GetBlobCopy(AssemblyRef.records[i].PublicKeyOrToken); const int PublicKey = 0x0001; @@ -1029,18 +1033,15 @@ public override AssemblyName[] __GetReferencedAssemblies() { name.SetPublicKeyToken(Array.Empty()); } - if (AssemblyRef.records[i].Culture != 0) - { + + if (AssemblyRef.records[i].Culture.IsNil == false) name.CultureName = GetString(AssemblyRef.records[i].Culture); - } else - { name.CultureName = ""; - } - if (AssemblyRef.records[i].HashValue != 0) - { + + if (AssemblyRef.records[i].HashValue.IsNil == false) name.hash = GetBlobCopy(AssemblyRef.records[i].HashValue); - } + name.RawFlags = (AssemblyNameFlags)AssemblyRef.records[i].Flags; list.Add(name); } @@ -1237,7 +1238,7 @@ internal override void Dispose() } } - internal override void ExportTypes(int fileToken, IKVM.Reflection.Emit.ModuleBuilder manifestModule) + internal override void ExportTypes(AssemblyFileHandle fileToken, IKVM.Reflection.Emit.ModuleBuilder manifestModule) { PopulateTypeDef(); manifestModule.ExportTypes(typeDefs, fileToken); diff --git a/src/IKVM.Reflection/Reader/PropertyInfoImpl.cs b/src/IKVM.Reflection/Reader/PropertyInfoImpl.cs index 5d34078d39..3781d3e6a0 100644 --- a/src/IKVM.Reflection/Reader/PropertyInfoImpl.cs +++ b/src/IKVM.Reflection/Reader/PropertyInfoImpl.cs @@ -58,7 +58,7 @@ public override bool Equals(object obj) public override int GetHashCode() => declaringType.GetHashCode() * 77 + index; - internal override PropertySignature PropertySignature => sig ??= PropertySignature.ReadSig(module, module.GetBlob(module.Property.records[index].Type), declaringType); + internal override PropertySignature PropertySignature => sig ??= PropertySignature.ReadSig(module, module.GetBlobReader(module.Property.records[index].Type), declaringType); public override PropertyAttributes Attributes => (PropertyAttributes)module.Property.records[index].Flags; diff --git a/src/IKVM.Reflection/Reader/ResourceModule.cs b/src/IKVM.Reflection/Reader/ResourceModule.cs index cb4216fc1e..7fe2614a64 100644 --- a/src/IKVM.Reflection/Reader/ResourceModule.cs +++ b/src/IKVM.Reflection/Reader/ResourceModule.cs @@ -87,7 +87,7 @@ public override byte[] __ModuleHash get { var blob = manifest.File.records[index].HashValue; - return blob == 0 ? Array.Empty() : manifest.GetBlobCopy(blob); + return blob.IsNil ? Array.Empty() : manifest.GetBlobCopy(blob); } } diff --git a/src/IKVM.Reflection/WindowsRuntimeProjection.cs b/src/IKVM.Reflection/WindowsRuntimeProjection.cs deleted file mode 100644 index b5f6bb230a..0000000000 --- a/src/IKVM.Reflection/WindowsRuntimeProjection.cs +++ /dev/null @@ -1,581 +0,0 @@ -/* - Copyright (C) 2013 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 IKVM.Reflection.Metadata; -using IKVM.Reflection.Reader; - -namespace IKVM.Reflection -{ - - sealed class WindowsRuntimeProjection - { - - static readonly Dictionary projections = new Dictionary(); - - readonly ModuleReader module; - readonly Dictionary strings; - readonly Dictionary added = new Dictionary(); - readonly int[] assemblyRefTokens = new int[(int)ProjectionAssembly.Count]; - int typeofSystemAttribute = -1; - int typeofSystemAttributeUsageAttribute = -1; - int typeofSystemEnum = -1; - int typeofSystemIDisposable = -1; - int typeofSystemMulticastDelegate = -1; - int typeofWindowsFoundationMetadataAllowMultipleAttribute = -1; - bool[] projectedTypeRefs; - - enum ProjectionAssembly - { - - System_Runtime, - System_Runtime_InteropServices_WindowsRuntime, - System_ObjectModel, - System_Runtime_WindowsRuntime, - System_Runtime_WindowsRuntime_UI_Xaml, - Count - - } - - sealed class Mapping - { - - internal readonly ProjectionAssembly Assembly; - internal readonly string TypeNamespace; - internal readonly string TypeName; - - /// - /// Initializes a new instance. - /// - /// - /// - /// - internal Mapping(ProjectionAssembly assembly, string typeNamespace, string typeName) - { - Assembly = assembly; - TypeNamespace = typeNamespace; - TypeName = typeName; - } - } - - static WindowsRuntimeProjection() - { - projections.Add(new TypeName("System", "Attribute"), new Mapping(ProjectionAssembly.System_Runtime, "System", "Attribute")); - projections.Add(new TypeName("System", "MulticastDelegate"), new Mapping(ProjectionAssembly.System_Runtime, "System", "MulticastDelegate")); - projections.Add(new TypeName("Windows.Foundation", "DateTime"), new Mapping(ProjectionAssembly.System_Runtime, "System", "DateTimeOffset")); - projections.Add(new TypeName("Windows.Foundation", "EventHandler`1"), new Mapping(ProjectionAssembly.System_Runtime, "System", "EventHandler`1")); - projections.Add(new TypeName("Windows.Foundation", "EventRegistrationToken"), new Mapping(ProjectionAssembly.System_Runtime_InteropServices_WindowsRuntime, "System.Runtime.InteropServices.WindowsRuntime", "EventRegistrationToken")); - projections.Add(new TypeName("Windows.Foundation", "HResult"), new Mapping(ProjectionAssembly.System_Runtime, "System", "Exception")); - projections.Add(new TypeName("Windows.Foundation", "IClosable"), new Mapping(ProjectionAssembly.System_Runtime, "System", "IDisposable")); - projections.Add(new TypeName("Windows.Foundation", "IReference`1"), new Mapping(ProjectionAssembly.System_Runtime, "System", "Nullable`1")); - projections.Add(new TypeName("Windows.Foundation", "Point"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime, "Windows.Foundation", "Point")); - projections.Add(new TypeName("Windows.Foundation", "Rect"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime, "Windows.Foundation", "Rect")); - projections.Add(new TypeName("Windows.Foundation", "Size"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime, "Windows.Foundation", "Size")); - projections.Add(new TypeName("Windows.Foundation", "TimeSpan"), new Mapping(ProjectionAssembly.System_Runtime, "System", "TimeSpan")); - projections.Add(new TypeName("Windows.Foundation", "Uri"), new Mapping(ProjectionAssembly.System_Runtime, "System", "Uri")); - projections.Add(new TypeName("Windows.Foundation.Collections", "IIterable`1"), new Mapping(ProjectionAssembly.System_Runtime, "System.Collections.Generic", "IEnumerable`1")); - projections.Add(new TypeName("Windows.Foundation.Collections", "IKeyValuePair`2"), new Mapping(ProjectionAssembly.System_Runtime, "System.Collections.Generic", "KeyValuePair`2")); - projections.Add(new TypeName("Windows.Foundation.Collections", "IMap`2"), new Mapping(ProjectionAssembly.System_Runtime, "System.Collections.Generic", "IDictionary`2")); - projections.Add(new TypeName("Windows.Foundation.Collections", "IMapView`2"), new Mapping(ProjectionAssembly.System_Runtime, "System.Collections.Generic", "IReadOnlyDictionary`2")); - projections.Add(new TypeName("Windows.Foundation.Collections", "IVector`1"), new Mapping(ProjectionAssembly.System_Runtime, "System.Collections.Generic", "IList`1")); - projections.Add(new TypeName("Windows.Foundation.Collections", "IVectorView`1"), new Mapping(ProjectionAssembly.System_Runtime, "System.Collections.Generic", "IReadOnlyList`1")); - projections.Add(new TypeName("Windows.Foundation.Metadata", "AttributeTargets"), new Mapping(ProjectionAssembly.System_Runtime, "System", "AttributeTargets")); - projections.Add(new TypeName("Windows.Foundation.Metadata", "AttributeUsageAttribute"), new Mapping(ProjectionAssembly.System_Runtime, "System", "AttributeUsageAttribute")); - projections.Add(new TypeName("Windows.UI", "Color"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime, "Windows.UI", "Color")); - projections.Add(new TypeName("Windows.UI.Xaml", "CornerRadius"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime_UI_Xaml, "Windows.UI.Xaml", "CornerRadius")); - projections.Add(new TypeName("Windows.UI.Xaml", "Duration"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime_UI_Xaml, "Windows.UI.Xaml", "Duration")); - projections.Add(new TypeName("Windows.UI.Xaml", "DurationType"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime_UI_Xaml, "Windows.UI.Xaml", "DurationType")); - projections.Add(new TypeName("Windows.UI.Xaml", "GridLength"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime_UI_Xaml, "Windows.UI.Xaml", "GridLength")); - projections.Add(new TypeName("Windows.UI.Xaml", "GridUnitType"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime_UI_Xaml, "Windows.UI.Xaml", "GridUnitType")); - projections.Add(new TypeName("Windows.UI.Xaml", "Thickness"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime_UI_Xaml, "Windows.UI.Xaml", "Thickness")); - projections.Add(new TypeName("Windows.UI.Xaml.Controls.Primitives", "GeneratorPosition"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime_UI_Xaml, "Windows.UI.Xaml.Controls.Primitives", "GeneratorPosition")); - projections.Add(new TypeName("Windows.UI.Xaml.Data", "INotifyPropertyChanged"), new Mapping(ProjectionAssembly.System_ObjectModel, "System.ComponentModel", "INotifyPropertyChanged")); - projections.Add(new TypeName("Windows.UI.Xaml.Data", "PropertyChangedEventArgs"), new Mapping(ProjectionAssembly.System_ObjectModel, "System.ComponentModel", "PropertyChangedEventArgs")); - projections.Add(new TypeName("Windows.UI.Xaml.Data", "PropertyChangedEventHandler"), new Mapping(ProjectionAssembly.System_ObjectModel, "System.ComponentModel", "PropertyChangedEventHandler")); - projections.Add(new TypeName("Windows.UI.Xaml.Input", "ICommand"), new Mapping(ProjectionAssembly.System_ObjectModel, "System.Windows.Input", "ICommand")); - projections.Add(new TypeName("Windows.UI.Xaml.Interop", "IBindableIterable"), new Mapping(ProjectionAssembly.System_Runtime, "System.Collections", "IEnumerable")); - projections.Add(new TypeName("Windows.UI.Xaml.Interop", "IBindableVector"), new Mapping(ProjectionAssembly.System_Runtime, "System.Collections", "IList")); - projections.Add(new TypeName("Windows.UI.Xaml.Interop", "NotifyCollectionChangedAction"), new Mapping(ProjectionAssembly.System_ObjectModel, "System.Collections.Specialized", "NotifyCollectionChangedAction")); - projections.Add(new TypeName("Windows.UI.Xaml.Interop", "NotifyCollectionChangedEventArgs"), new Mapping(ProjectionAssembly.System_ObjectModel, "System.Collections.Specialized", "NotifyCollectionChangedEventArgs")); - projections.Add(new TypeName("Windows.UI.Xaml.Interop", "NotifyCollectionChangedEventHandler"), new Mapping(ProjectionAssembly.System_ObjectModel, "System.Collections.Specialized", "NotifyCollectionChangedEventHandler")); - projections.Add(new TypeName("Windows.UI.Xaml.Interop", "TypeName"), new Mapping(ProjectionAssembly.System_Runtime, "System", "Type")); - projections.Add(new TypeName("Windows.UI.Xaml.Media", "Matrix"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime_UI_Xaml, "Windows.UI.Xaml.Media", "Matrix")); - projections.Add(new TypeName("Windows.UI.Xaml.Media.Animation", "KeyTime"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime_UI_Xaml, "Windows.UI.Xaml.Media.Animation", "KeyTime")); - projections.Add(new TypeName("Windows.UI.Xaml.Media.Animation", "RepeatBehavior"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime_UI_Xaml, "Windows.UI.Xaml.Media.Animation", "RepeatBehavior")); - projections.Add(new TypeName("Windows.UI.Xaml.Media.Animation", "RepeatBehaviorType"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime_UI_Xaml, "Windows.UI.Xaml.Media.Animation", "RepeatBehaviorType")); - projections.Add(new TypeName("Windows.UI.Xaml.Media.Media3D", "Matrix3D"), new Mapping(ProjectionAssembly.System_Runtime_WindowsRuntime_UI_Xaml, "Windows.UI.Xaml.Media.Media3D", "Matrix3D")); - - // hidden types - projections.Add(new TypeName("Windows.Foundation", "IPropertyValue"), null); - projections.Add(new TypeName("Windows.Foundation", "IReferenceArray`1"), null); - projections.Add(new TypeName("Windows.Foundation.Metadata", "GCPressureAmount"), null); - projections.Add(new TypeName("Windows.Foundation.Metadata", "GCPressureAttribute"), null); - projections.Add(new TypeName("Windows.UI.Xaml", "CornerRadiusHelper"), null); - projections.Add(new TypeName("Windows.UI.Xaml", "DurationHelper"), null); - projections.Add(new TypeName("Windows.UI.Xaml", "GridLengthHelper"), null); - projections.Add(new TypeName("Windows.UI.Xaml", "ThicknessHelper"), null); - projections.Add(new TypeName("Windows.UI.Xaml.Controls.Primitives", "GeneratorPositionHelper"), null); - projections.Add(new TypeName("Windows.UI.Xaml.Interop", "INotifyCollectionChanged"), null); - projections.Add(new TypeName("Windows.UI.Xaml.Media", "MatrixHelper"), null); - projections.Add(new TypeName("Windows.UI.Xaml.Media.Animation", "KeyTimeHelper"), null); - projections.Add(new TypeName("Windows.UI.Xaml.Media.Animation", "RepeatBehaviorHelper"), null); - projections.Add(new TypeName("Windows.UI.Xaml.Media.Media3D", "Matrix3DHelper"), null); - } - - /// - /// Initializes a new instance. - /// - /// - /// - WindowsRuntimeProjection(ModuleReader module, Dictionary strings) - { - this.module = module; - this.strings = strings; - } - - internal static void Patch(ModuleReader module, Dictionary strings, ref string imageRuntimeVersion, ref byte[] blobHeap) - { - if (!module.CustomAttribute.Sorted) - { - // HasAllowMultipleAttribute requires this - throw new NotImplementedException("CustomAttribute table must be sorted"); - } - - var clr = imageRuntimeVersion.Contains(";"); - if (clr) - { - imageRuntimeVersion = imageRuntimeVersion.Substring(imageRuntimeVersion.IndexOf(';') + 1); - if (imageRuntimeVersion.StartsWith("CLR", StringComparison.OrdinalIgnoreCase)) - imageRuntimeVersion = imageRuntimeVersion.Substring(3); - - imageRuntimeVersion = imageRuntimeVersion.TrimStart(' '); - } - else - { - var mscorlib = module.universe.CoreLib; - imageRuntimeVersion = mscorlib.__IsMissing ? "v4.0.30319" : mscorlib.ImageRuntimeVersion; - } - - var obj = new WindowsRuntimeProjection(module, strings); - obj.PatchAssemblyRef(ref blobHeap); - obj.PatchTypeRef(); - obj.PatchTypes(clr); - obj.PatchMethodImpl(); - obj.PatchCustomAttribute(ref blobHeap); - } - - void PatchAssemblyRef(ref byte[] blobHeap) - { - var assemblyRefs = module.AssemblyRef; - for (int i = 0; i < assemblyRefs.records.Length; i++) - { - if (module.GetString(assemblyRefs.records[i].Name) == "mscorlib") - { - var ver = GetMscorlibVersion(); - assemblyRefs.records[i].MajorVersion = (ushort)ver.Major; - assemblyRefs.records[i].MinorVersion = (ushort)ver.Minor; - assemblyRefs.records[i].BuildNumber = (ushort)ver.Build; - assemblyRefs.records[i].RevisionNumber = (ushort)ver.Revision; - break; - } - } - - int publicKeyTokenMicrosoft = AddBlob(ref blobHeap, new byte[] { 0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A }); - int publicKeyTokenEcma = AddBlob(ref blobHeap, new byte[] { 0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89 }); - assemblyRefTokens[(int)ProjectionAssembly.System_Runtime] = AddAssemblyReference("System.Runtime", publicKeyTokenMicrosoft); - assemblyRefTokens[(int)ProjectionAssembly.System_Runtime_InteropServices_WindowsRuntime] = AddAssemblyReference("System.Runtime.InteropServices.WindowsRuntime", publicKeyTokenMicrosoft); - assemblyRefTokens[(int)ProjectionAssembly.System_ObjectModel] = AddAssemblyReference("System.ObjectModel", publicKeyTokenMicrosoft); - assemblyRefTokens[(int)ProjectionAssembly.System_Runtime_WindowsRuntime] = AddAssemblyReference("System.Runtime.WindowsRuntime", publicKeyTokenEcma); - assemblyRefTokens[(int)ProjectionAssembly.System_Runtime_WindowsRuntime_UI_Xaml] = AddAssemblyReference("System.Runtime.WindowsRuntime.UI.Xaml", publicKeyTokenEcma); - } - - void PatchTypeRef() - { - var typeRefs = module.TypeRef.records; - projectedTypeRefs = new bool[typeRefs.Length]; - for (int i = 0; i < typeRefs.Length; i++) - { - var typeName = GetTypeRefName(i); - if (projections.TryGetValue(typeName, out var mapping) && mapping != null) - { - typeRefs[i].ResolutionScope = assemblyRefTokens[(int)mapping.Assembly]; - typeRefs[i].TypeNamespace = GetString(mapping.TypeNamespace); - typeRefs[i].TypeName = GetString(mapping.TypeName); - projectedTypeRefs[i] = true; - } - - switch (typeName.Namespace) - { - case "System": - switch (typeName.Name) - { - case "Attribute": - typeofSystemAttribute = (TypeRefTable.Index << 24) + i + 1; - break; - case "Enum": - typeofSystemEnum = (TypeRefTable.Index << 24) + i + 1; - break; - case "MulticastDelegate": - typeofSystemMulticastDelegate = (TypeRefTable.Index << 24) + i + 1; - break; - } - break; - case "Windows.Foundation": - switch (typeName.Name) - { - case "IClosable": - typeofSystemIDisposable = (TypeRefTable.Index << 24) + i + 1; - break; - } - break; - case "Windows.Foundation.Metadata": - switch (typeName.Name) - { - case "AllowMultipleAttribute": - typeofWindowsFoundationMetadataAllowMultipleAttribute = (TypeRefTable.Index << 24) + i + 1; - break; - case "AttributeUsageAttribute": - typeofSystemAttributeUsageAttribute = (TypeRefTable.Index << 24) + i + 1; - break; - } - break; - } - } - } - - void PatchTypes(bool clr) - { - var types = module.TypeDef.records; - var methods = module.MethodDef.records; - var fields = module.Field.records; - for (int i = 0; i < types.Length; i++) - { - var attr = (TypeAttributes)types[i].Flags; - if ((attr & TypeAttributes.WindowsRuntime) != 0) - { - if (clr && (attr & (TypeAttributes.VisibilityMask | TypeAttributes.WindowsRuntime | TypeAttributes.Interface)) == (TypeAttributes.Public | TypeAttributes.WindowsRuntime)) - { - types[i].TypeName = GetString("" + module.GetString(types[i].TypeName)); - types[i].Flags &= (int)~TypeAttributes.Public; - } - - if (types[i].Extends != typeofSystemAttribute && (!clr || (attr & TypeAttributes.Interface) == 0)) - types[i].Flags |= (int)TypeAttributes.Import; - - if (projections.ContainsKey(GetTypeDefName(i))) - types[i].Flags &= (int)~TypeAttributes.Public; - - int endOfMethodList = i == types.Length - 1 ? methods.Length : types[i + 1].MethodList - 1; - for (int j = types[i].MethodList - 1; j < endOfMethodList; j++) - { - if (types[i].Extends == typeofSystemMulticastDelegate) - { - if (module.GetString(methods[j].Name) == ".ctor") - { - methods[j].Flags &= (int)~MethodAttributes.MemberAccessMask; - methods[j].Flags |= (int)MethodAttributes.Public; - } - } - else if (methods[j].RVA == 0) - { - methods[j].ImplFlags = (int)(MethodImplAttributes.Runtime | MethodImplAttributes.Managed | MethodImplAttributes.InternalCall); - } - } - - if (types[i].Extends == typeofSystemEnum) - { - int endOfFieldList = i == types.Length - 1 ? fields.Length : types[i + 1].FieldList - 1; - for (int j = types[i].FieldList - 1; j < endOfFieldList; j++) - { - fields[j].Flags &= (int)~FieldAttributes.FieldAccessMask; - fields[j].Flags |= (int)FieldAttributes.Public; - } - } - } - else if (clr && (attr & (TypeAttributes.VisibilityMask | TypeAttributes.SpecialName)) == (TypeAttributes.NotPublic | TypeAttributes.SpecialName)) - { - string name = module.GetString(types[i].TypeName); - if (name.StartsWith("", StringComparison.Ordinal)) - { - types[i].TypeName = GetString(name.Substring(5)); - types[i].Flags |= (int)TypeAttributes.Public; - types[i].Flags &= (int)~TypeAttributes.SpecialName; - } - } - } - } - - void PatchMethodImpl() - { - var methodImpls = module.MethodImpl.records; - var memberRefs = module.MemberRef.records; - var methods = module.MethodDef.records; - var typeSpecs = module.TypeSpec.records; - - for (int i = 0; i < methodImpls.Length; i++) - { - int methodDefOrMemberRef = methodImpls[i].MethodDeclaration; - if ((methodDefOrMemberRef >> 24) == MemberRefTable.Index) - { - int typeDefOrRef = memberRefs[(methodDefOrMemberRef & 0xFFFFFF) - 1].Class; - if ((typeDefOrRef >> 24) == TypeSpecTable.Index) - typeDefOrRef = ReadTypeSpec(module.GetBlob(typeSpecs[(typeDefOrRef & 0xFFFFFF) - 1])); - - if ((typeDefOrRef >> 24) == TypeRefTable.Index) - { - if (typeDefOrRef == typeofSystemIDisposable) - { - int dispose = GetString("Dispose"); - methods[(methodImpls[i].MethodBody & 0xFFFFFF) - 1].Name = dispose; - memberRefs[(methodImpls[i].MethodDeclaration & 0xFFFFFF) - 1].Name = dispose; - } - else if (projectedTypeRefs[(typeDefOrRef & 0xFFFFFF) - 1]) - { - methods[(methodImpls[i].MethodBody & 0xFFFFFF) - 1].Flags &= (int)~MethodAttributes.MemberAccessMask; - methods[(methodImpls[i].MethodBody & 0xFFFFFF) - 1].Flags |= (int)MethodAttributes.Private; - methodImpls[i].MethodBody = 0; - methodImpls[i].MethodDeclaration = 0; - } - } - else if ((typeDefOrRef >> 24) == TypeDefTable.Index) - { - } - else if ((typeDefOrRef >> 24) == TypeSpecTable.Index) - { - throw new NotImplementedException(); - } - else - { - throw new BadImageFormatException(); - } - } - } - } - - void PatchCustomAttribute(ref byte[] blobHeap) - { - var memberRefs = module.MemberRef.records; - int ctorSystemAttributeUsageAttribute = -1; - int ctorWindowsFoundationMetadataAllowMultipleAttribute = -1; - for (int i = 0; i < memberRefs.Length; i++) - { - if (memberRefs[i].Class == typeofSystemAttributeUsageAttribute && module.GetString(memberRefs[i].Name) == ".ctor") - ctorSystemAttributeUsageAttribute = (MemberRefTable.Index << 24) + i + 1; - else if (memberRefs[i].Class == typeofWindowsFoundationMetadataAllowMultipleAttribute && module.GetString(memberRefs[i].Name) == ".ctor") - ctorWindowsFoundationMetadataAllowMultipleAttribute = (MemberRefTable.Index << 24) + i + 1; - } - - if (ctorSystemAttributeUsageAttribute != -1) - { - var customAttributes = module.CustomAttribute.records; - var map = new Dictionary(); - for (int i = 0; i < customAttributes.Length; i++) - { - if (customAttributes[i].Type == ctorSystemAttributeUsageAttribute) - { - var br = module.GetBlob(customAttributes[i].Value); - br.ReadInt16(); - - var targets = MapAttributeTargets(br.ReadInt32()); - if ((targets & AttributeTargets.Method) != 0) - { - // apart from the two types special cased below, Method implies Constructor - targets |= AttributeTargets.Constructor; - if (customAttributes[i].Parent >> 24 == TypeDefTable.Index) - { - var typeName = GetTypeDefName((customAttributes[i].Parent & 0xFFFFFF) - 1); - if (typeName.Namespace == "Windows.Foundation.Metadata" && (typeName.Name == "OverloadAttribute" || typeName.Name == "DefaultOverloadAttribute")) - targets &= ~AttributeTargets.Constructor; - } - } - - customAttributes[i].Value = GetAttributeUsageAttributeBlob(ref blobHeap, map, targets, HasAllowMultipleAttribute(customAttributes, i, ctorWindowsFoundationMetadataAllowMultipleAttribute)); - } - } - } - } - - int AddAssemblyReference(string name, int publicKeyToken) - { - var rec = new AssemblyRefTable.Record(); - var ver = GetMscorlibVersion(); - rec.MajorVersion = (ushort)ver.Major; - rec.MinorVersion = (ushort)ver.Minor; - rec.BuildNumber = (ushort)ver.Build; - rec.RevisionNumber = (ushort)ver.Revision; - rec.Flags = 0; - rec.PublicKeyOrToken = publicKeyToken; - rec.Name = GetString(name); - rec.Culture = 0; - rec.HashValue = 0; - int token = 0x23000000 | module.AssemblyRef.FindOrAddRecord(rec); - Array.Resize(ref module.AssemblyRef.records, module.AssemblyRef.RowCount); - return token; - } - - TypeName GetTypeRefName(int index) - { - return new TypeName(module.GetString(module.TypeRef.records[index].TypeNamespace), module.GetString(module.TypeRef.records[index].TypeName)); - } - - TypeName GetTypeDefName(int index) - { - return new TypeName(module.GetString(module.TypeDef.records[index].TypeNamespace), module.GetString(module.TypeDef.records[index].TypeName)); - } - - int GetString(string str) - { - if (!added.TryGetValue(str, out var index)) - { - index = -(added.Count + 1); - added.Add(str, index); - strings.Add(index, str); - } - - return index; - } - - Version GetMscorlibVersion() - { - var mscorlib = module.universe.CoreLib; - return mscorlib.__IsMissing ? new Version(4, 0, 0, 0) : mscorlib.GetName().Version; - } - - static bool HasAllowMultipleAttribute(CustomAttributeTable.Record[] customAttributes, int i, int ctorWindowsFoundationMetadataAllowMultipleAttribute) - { - // we can assume that the CustomAttribute table is sorted, because we've checked the Sorted flag earlier - int owner = customAttributes[i].Parent; - while (i > 0 && customAttributes[i - 1].Parent == owner) - i--; - - while (i < customAttributes.Length && customAttributes[i].Parent == owner) - { - if (customAttributes[i].Type == ctorWindowsFoundationMetadataAllowMultipleAttribute) - return true; - - i++; - } - - return false; - } - - private static AttributeTargets MapAttributeTargets(int targets) - { - if (targets == -1) - return AttributeTargets.All; - - AttributeTargets result = 0; - if ((targets & 1) != 0) - result |= AttributeTargets.Delegate; - if ((targets & 2) != 0) - result |= AttributeTargets.Enum; - if ((targets & 4) != 0) - result |= AttributeTargets.Event; - if ((targets & 8) != 0) - result |= AttributeTargets.Field; - if ((targets & 16) != 0) - result |= AttributeTargets.Interface; - if ((targets & 64) != 0) - result |= AttributeTargets.Method; - if ((targets & 128) != 0) - result |= AttributeTargets.Parameter; - if ((targets & 256) != 0) - result |= AttributeTargets.Property; - if ((targets & 512) != 0) - result |= AttributeTargets.Class; - if ((targets & 1024) != 0) - result |= AttributeTargets.Struct; - - return result; - } - - static int GetAttributeUsageAttributeBlob(ref byte[] blobHeap, Dictionary map, AttributeTargets targets, bool allowMultiple) - { - var key = (int)targets; - if (allowMultiple) - key |= unchecked((int)0x80000000); - - if (map.TryGetValue(key, out var blob) == false) - map.Add(key, blob = AddBlob(ref blobHeap, new byte[] { - 0x01, 0x00, - (byte)targets, - (byte)((int)targets >> 8), - (byte)((int)targets >> 16), - (byte)((int)targets >> 24), - 0x01, 0x00, 0x54, 0x02, 0x0D, 0x41, 0x6C, 0x6C, 0x6F, 0x77, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x6C, 0x65, - allowMultiple ? (byte)0x01 : (byte)0x00 })); - - return blob; - } - - static int ReadTypeSpec(ByteReader br) - { - if (br.ReadByte() != Signature.ELEMENT_TYPE_GENERICINST) - throw new NotImplementedException("Expected ELEMENT_TYPE_GENERICINST"); - - switch (br.ReadByte()) - { - case Signature.ELEMENT_TYPE_CLASS: - case Signature.ELEMENT_TYPE_VALUETYPE: - break; - default: - throw new NotImplementedException("Expected ELEMENT_TYPE_CLASS or ELEMENT_TYPE_VALUETYPE"); - } - - int encoded = br.ReadCompressedUInt(); - return (encoded & 3) switch - { - 0 => (TypeDefTable.Index << 24) + (encoded >> 2), - 1 => (TypeRefTable.Index << 24) + (encoded >> 2), - 2 => (TypeSpecTable.Index << 24) + (encoded >> 2), - _ => throw new BadImageFormatException(), - }; - } - - static int AddBlob(ref byte[] blobHeap, byte[] blob) - { - if (blob.Length > 127) - throw new NotImplementedException(); - - int offset = blobHeap.Length; - Array.Resize(ref blobHeap, offset + blob.Length + 1); - blobHeap[offset] = (byte)blob.Length; - Buffer.BlockCopy(blob, 0, blobHeap, offset + 1, blob.Length); - return offset; - } - - internal static bool IsProjectedValueType(string ns, string name, Module module) - { - return ((ns == "System.Collections.Generic" && name == "KeyValuePair`2") || (ns == "System" && name == "Nullable`1")) && module.Assembly.GetName().Name == "System.Runtime"; - } - - internal static bool IsProjectedReferenceType(string ns, string name, Module module) - { - return ((ns == "System" && name == "Exception") || (ns == "System" && name == "Type")) && module.Assembly.GetName().Name == "System.Runtime"; - } - - } - -} diff --git a/src/IKVM.Reflection/Writer/BlobHeap.cs b/src/IKVM.Reflection/Writer/BlobHeap.cs deleted file mode 100644 index e309fcaad5..0000000000 --- a/src/IKVM.Reflection/Writer/BlobHeap.cs +++ /dev/null @@ -1,117 +0,0 @@ -/* - Copyright (C) 2008 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.Diagnostics; - -namespace IKVM.Reflection.Writer -{ - - sealed class BlobHeap : SimpleHeap - { - - Key[] map = new Key[8179]; - readonly ByteBuffer buf = new ByteBuffer(32); - - struct Key - { - - internal Key[] next; - internal int len; - internal int hash; - internal int offset; - - } - - internal BlobHeap() - { - buf.Write((byte)0); - } - - internal int Add(ByteBuffer bb) - { - Debug.Assert(!frozen); - - var bblen = bb.Length; - if (bblen == 0) - return 0; - - var lenlen = MetadataWriter.GetCompressedUIntLength(bblen); - var hash = bb.Hash(); - var index = (hash & 0x7FFFFFFF) % map.Length; - var keys = map; - int last = index; - while (keys[index].offset != 0) - { - if (keys[index].hash == hash && keys[index].len == bblen && buf.Match(keys[index].offset + lenlen, bb, 0, bblen)) - return keys[index].offset; - - if (index == last) - { - if (keys[index].next == null) - { - keys[index].next = new Key[4]; - keys = keys[index].next; - index = 0; - break; - } - - keys = keys[index].next; - index = -1; - last = keys.Length - 1; - } - - index++; - } - - var offset = buf.Position; - buf.WriteCompressedUInt(bblen); - buf.Write(bb); - keys[index].len = bblen; - keys[index].hash = hash; - keys[index].offset = offset; - return offset; - } - - protected override int GetLength() - { - return buf.Position; - } - - protected override void WriteImpl(MetadataWriter mw) - { - mw.Write(buf); - } - - internal bool IsEmpty - { - get { return buf.Position == 1; } - } - - internal IKVM.Reflection.Reader.ByteReader GetBlob(int blobIndex) - { - return buf.GetBlob(blobIndex); - } - - } - -} diff --git a/src/IKVM.Reflection/Writer/ByteBuffer.cs b/src/IKVM.Reflection/Writer/ByteBuffer.cs index 4b3bbb0ec2..8679b2c987 100644 --- a/src/IKVM.Reflection/Writer/ByteBuffer.cs +++ b/src/IKVM.Reflection/Writer/ByteBuffer.cs @@ -373,11 +373,6 @@ internal int Hash() return hash; } - internal IKVM.Reflection.Reader.ByteReader GetBlob(int offset) - { - return IKVM.Reflection.Reader.ByteReader.FromBlob(buffer, offset); - } - } } diff --git a/src/IKVM.Reflection/Writer/GuidHeap.cs b/src/IKVM.Reflection/Writer/GuidHeap.cs deleted file mode 100644 index 21d3915410..0000000000 --- a/src/IKVM.Reflection/Writer/GuidHeap.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - Copyright (C) 2008 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; - -namespace IKVM.Reflection.Writer -{ - - sealed class GuidHeap : SimpleHeap - { - - readonly List list = new List(); - - /// - /// Initializes a new instance. - /// - internal GuidHeap() - { - - } - - internal int Add(Guid guid) - { - Debug.Assert(!frozen); - list.Add(guid); - return list.Count; - } - - protected override int GetLength() - { - return list.Count * 16; - } - - protected override void WriteImpl(MetadataWriter mw) - { - foreach (var guid in list) - mw.Write(guid.ToByteArray()); - } - - } - -} diff --git a/src/IKVM.Reflection/Writer/Heap.cs b/src/IKVM.Reflection/Writer/Heap.cs deleted file mode 100644 index 3d1a3dc00a..0000000000 --- a/src/IKVM.Reflection/Writer/Heap.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - Copyright (C) 2008 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.Diagnostics; - -namespace IKVM.Reflection.Writer -{ - - abstract class Heap - { - - protected bool frozen; - protected int unalignedlength; - - internal void Write(MetadataWriter mw) - { - var pos = mw.Position; - WriteImpl(mw); - - Debug.Assert(mw.Position == pos + unalignedlength); - var align = Length - unalignedlength; - for (int i = 0; i < align; i++) - mw.Write((byte)0); - } - - internal bool IsBig => Length > 65535; - - internal int Length - { - get - { - if (!frozen) - throw new InvalidOperationException(); - - return (unalignedlength + 3) & ~3; - } - } - - protected abstract void WriteImpl(MetadataWriter mw); - - } - -} diff --git a/src/IKVM.Reflection/Writer/MetadataWriter.cs b/src/IKVM.Reflection/Writer/MetadataWriter.cs index 28f7a0bf60..2e3adc3b3f 100644 --- a/src/IKVM.Reflection/Writer/MetadataWriter.cs +++ b/src/IKVM.Reflection/Writer/MetadataWriter.cs @@ -21,125 +21,12 @@ Jeroen Frijters jeroen@frijters.net */ -using System; -using System.IO; - -using IKVM.Reflection.Emit; -using IKVM.Reflection.Metadata; - namespace IKVM.Reflection.Writer { - sealed class MetadataWriter : MetadataRW + static class MetadataWriter { - readonly ModuleBuilder moduleBuilder; - readonly Stream stream; - readonly byte[] buffer = new byte[8]; - - /// - /// Initializes a new instance. - /// - /// - /// - internal MetadataWriter(ModuleBuilder module, Stream stream) : base(module, module.Strings.IsBig, module.Guids.IsBig, module.Blobs.IsBig) - { - this.moduleBuilder = module; - this.stream = stream; - } - - internal ModuleBuilder ModuleBuilder => moduleBuilder; - - internal uint Position => (uint)stream.Position; - - internal void Write(ByteBuffer bb) => bb.WriteTo(stream); - - internal void WriteAsciiz(string value) - { - foreach (var c in value) - stream.WriteByte((byte)c); - - stream.WriteByte(0); - } - - internal void Write(byte[] value) - { - stream.Write(value, 0, value.Length); - } - - internal void Write(byte[] buffer, int offset, int count) - { - stream.Write(buffer, offset, count); - } - - internal void Write(byte value) - { - stream.WriteByte(value); - } - - internal void Write(ushort value) - { - Write((short)value); - } - - internal void Write(short value) - { - stream.WriteByte((byte)value); - stream.WriteByte((byte)(value >> 8)); - } - - internal void Write(uint value) - { - Write((int)value); - } - - internal void Write(int value) - { - buffer[0] = (byte)value; - buffer[1] = (byte)(value >> 8); - buffer[2] = (byte)(value >> 16); - buffer[3] = (byte)(value >> 24); - stream.Write(buffer, 0, 4); - } - - internal void Write(ulong value) - { - Write((long)value); - } - - internal void Write(long value) - { - buffer[0] = (byte)value; - buffer[1] = (byte)(value >> 8); - buffer[2] = (byte)(value >> 16); - buffer[3] = (byte)(value >> 24); - buffer[4] = (byte)(value >> 32); - buffer[5] = (byte)(value >> 40); - buffer[6] = (byte)(value >> 48); - buffer[7] = (byte)(value >> 56); - stream.Write(buffer, 0, 8); - } - - internal void WriteCompressedUInt(int value) - { - if (value <= 0x7F) - { - Write((byte)value); - } - else if (value <= 0x3FFF) - { - Write((byte)(0x80 | (value >> 8))); - Write((byte)value); - } - else - { - Write((byte)(0xC0 | (value >> 24))); - Write((byte)(value >> 16)); - Write((byte)(value >> 8)); - Write((byte)value); - } - } - internal static int GetCompressedUIntLength(int value) { return value switch @@ -150,286 +37,6 @@ internal static int GetCompressedUIntLength(int value) }; } - internal void WriteStringIndex(int index) - { - if (bigStrings) - Write(index); - else - Write((short)index); - } - - internal void WriteGuidIndex(int index) - { - if (bigGuids) - Write(index); - else - Write((short)index); - } - - internal void WriteBlobIndex(int index) - { - if (bigBlobs) - Write(index); - else - Write((short)index); - } - - internal void WriteTypeDefOrRef(int token) - { - switch (token >> 24) - { - case 0: - break; - case TypeDefTable.Index: - token = (token & 0xFFFFFF) << 2 | 0; - break; - case TypeRefTable.Index: - token = (token & 0xFFFFFF) << 2 | 1; - break; - case TypeSpecTable.Index: - token = (token & 0xFFFFFF) << 2 | 2; - break; - default: - throw new InvalidOperationException(); - } - - if (bigTypeDefOrRef) - Write(token); - else - Write((short)token); - } - - internal void WriteEncodedTypeDefOrRef(int encodedToken) - { - if (bigTypeDefOrRef) - Write(encodedToken); - else - Write((short)encodedToken); - } - - internal void WriteHasCustomAttribute(int token) - { - var encodedToken = CustomAttributeTable.EncodeHasCustomAttribute(token); - if (bigHasCustomAttribute) - Write(encodedToken); - else - Write((short)encodedToken); - } - - internal void WriteCustomAttributeType(int token) - { - token = (token >> 24) switch - { - MethodDefTable.Index => (token & 0xFFFFFF) << 3 | 2, - MemberRefTable.Index => (token & 0xFFFFFF) << 3 | 3, - _ => throw new InvalidOperationException(), - }; - - if (bigCustomAttributeType) - Write(token); - else - Write((short)token); - } - - internal void WriteField(int index) - { - if (bigField) - Write(index & 0xFFFFFF); - else - Write((short)index); - } - - internal void WriteMethodDef(int index) - { - if (bigMethodDef) - Write(index & 0xFFFFFF); - else - Write((short)index); - } - - internal void WriteParam(int index) - { - if (bigParam) - Write(index & 0xFFFFFF); - else - Write((short)index); - } - - internal void WriteTypeDef(int index) - { - if (bigTypeDef) - Write(index & 0xFFFFFF); - else - Write((short)index); - } - - internal void WriteEvent(int index) - { - if (bigEvent) - Write(index & 0xFFFFFF); - else - Write((short)index); - } - - internal void WriteProperty(int index) - { - if (bigProperty) - Write((index & 0xFFFFFF)); - else - Write((short)index); - } - - internal void WriteGenericParam(int index) - { - if (bigGenericParam) - Write((index & 0xFFFFFF)); - else - Write((short)index); - } - - internal void WriteModuleRef(int index) - { - if (bigModuleRef) - Write(index & 0xFFFFFF); - else - Write((short)index); - } - - internal void WriteResolutionScope(int token) - { - token = (token >> 24) switch - { - ModuleTable.Index => (token & 0xFFFFFF) << 2 | 0, - ModuleRefTable.Index => (token & 0xFFFFFF) << 2 | 1, - AssemblyRefTable.Index => (token & 0xFFFFFF) << 2 | 2, - TypeRefTable.Index => (token & 0xFFFFFF) << 2 | 3, - _ => throw new InvalidOperationException(), - }; - - if (bigResolutionScope) - Write(token); - else - Write((short)token); - } - - internal void WriteMemberRefParent(int token) - { - token = (token >> 24) switch - { - TypeDefTable.Index => (token & 0xFFFFFF) << 3 | 0, - TypeRefTable.Index => (token & 0xFFFFFF) << 3 | 1, - ModuleRefTable.Index => (token & 0xFFFFFF) << 3 | 2, - MethodDefTable.Index => (token & 0xFFFFFF) << 3 | 3, - TypeSpecTable.Index => (token & 0xFFFFFF) << 3 | 4, - _ => throw new InvalidOperationException(), - }; - - if (bigMemberRefParent) - Write(token); - else - Write((short)token); - } - - internal void WriteMethodDefOrRef(int token) - { - token = (token >> 24) switch - { - MethodDefTable.Index => (token & 0xFFFFFF) << 1 | 0, - MemberRefTable.Index => (token & 0xFFFFFF) << 1 | 1, - _ => throw new InvalidOperationException(), - }; - - if (bigMethodDefOrRef) - Write(token); - else - Write((short)token); - } - - internal void WriteHasConstant(int token) - { - var encodedToken = ConstantTable.EncodeHasConstant(token); - if (bigHasConstant) - Write(encodedToken); - else - Write((short)encodedToken); - } - - internal void WriteHasSemantics(int encodedToken) - { - // because we've already had to do the encoding (to be able to sort the table) here we simple write the value - if (bigHasSemantics) - Write(encodedToken); - else - Write((short)encodedToken); - } - - internal void WriteImplementation(int token) - { - switch (token >> 24) - { - case 0: - break; - case FileTable.Index: - token = (token & 0xFFFFFF) << 2 | 0; - break; - case AssemblyRefTable.Index: - token = (token & 0xFFFFFF) << 2 | 1; - break; - case ExportedTypeTable.Index: - token = (token & 0xFFFFFF) << 2 | 2; - break; - default: - throw new InvalidOperationException(); - } - - if (bigImplementation) - Write(token); - else - Write((short)token); - } - - internal void WriteTypeOrMethodDef(int encodedToken) - { - // because we've already had to do the encoding (to be able to sort the table) here we simple write the value - if (bigTypeOrMethodDef) - Write(encodedToken); - else - Write((short)encodedToken); - } - - internal void WriteHasDeclSecurity(int encodedToken) - { - // because we've already had to do the encoding (to be able to sort the table) here we simple write the value - if (bigHasDeclSecurity) - Write(encodedToken); - else - Write((short)encodedToken); - } - - internal void WriteMemberForwarded(int token) - { - token = (token >> 24) switch - { - FieldTable.Index => (token & 0xFFFFFF) << 1 | 0, - MethodDefTable.Index => (token & 0xFFFFFF) << 1 | 1, - _ => throw new InvalidOperationException(), - }; - - if (bigMemberForwarded) - Write(token); - else - Write((short)token); - } - - internal void WriteHasFieldMarshal(int token) - { - var encodedToken = FieldMarshalTable.EncodeHasFieldMarshal(token); - if (bigHasFieldMarshal) - Write(encodedToken); - else - Write((short)encodedToken); - } - } } diff --git a/src/IKVM.Reflection/Writer/ModuleWriter.cs b/src/IKVM.Reflection/Writer/ModuleWriter.cs index d74adf0c7c..d2618447fb 100644 --- a/src/IKVM.Reflection/Writer/ModuleWriter.cs +++ b/src/IKVM.Reflection/Writer/ModuleWriter.cs @@ -22,11 +22,15 @@ Jeroen Frijters */ using System; +using System.Collections.Generic; using System.IO; +using System.Reflection.Emit; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; using System.Security.Cryptography; using IKVM.Reflection.Emit; -using IKVM.Reflection.Metadata; namespace IKVM.Reflection.Writer { @@ -34,12 +38,35 @@ namespace IKVM.Reflection.Writer static class ModuleWriter { - internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, int entryPointToken) + /// + /// Writes the module specified by . + /// + /// + /// + /// + /// + /// + /// + /// + /// + internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, MethodDefinitionHandle entryPointToken) { WriteModule(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, null); } - internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, int entryPointToken, Stream stream) + /// + /// Writes the module specified by to the specified . + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, MethodDefinitionHandle entryPointToken, Stream stream) { if (stream == null) { @@ -59,7 +86,10 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, Mo } using (var fs = new FileStream(fileName, FileMode.Create)) - WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, fs); + { + var entryPoint = entryPointToken.IsNil == false ? entryPointToken : default; + WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPoint, fs); + } // if we're running on Mono, mark the module as executable by using a Mono private API extension if (mono) @@ -67,284 +97,291 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, Mo } else { - WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, stream); + var entryPoint = entryPointToken.IsNil == false ? entryPointToken : default; + WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPoint, stream); } } - static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, int entryPointToken, Stream stream) + /// + /// Implementation of module writing to output stream. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, MethodDefinitionHandle entryPoint, Stream stream) { moduleBuilder.ApplyUnmanagedExports(imageFileMachine); moduleBuilder.FixupMethodBodyTokens(); - int moduleVersionIdIndex = moduleBuilder.Guids.Add(moduleBuilder.GetModuleVersionIdOrEmpty()); + // for compatibility with Reflection.Emit, if there aren't any user strings, we add one moduleBuilder.Metadata.GetOrAddUserString(""); - if (moduleBuilder.UserStrings.IsEmpty) + if (resources != null) + resources.Finish(); + +#if NETFRAMEWORK + if (moduleBuilder.symbolWriter != null) { - // for compat with Ref.Emit, if there aren't any user strings, we add one - moduleBuilder.UserStrings.Add(" "); + moduleBuilder.WriteSymbolTokenMap(); + moduleBuilder.symbolWriter.Close(); } +#endif - if (resources != null) - resources.Finish(); + // write the module content + WriteModuleImpl(moduleBuilder); + + // initialize PE header builder + var peHeaderBuilder = new PEHeaderBuilder( + machine: GetMachine(imageFileMachine), + fileAlignment: moduleBuilder.__FileAlignment, + imageBase: (ulong)moduleBuilder.__ImageBase, + subsystem: GetSubsystem(fileKind), + dllCharacteristics: (System.Reflection.PortableExecutable.DllCharacteristics)(int)moduleBuilder.__DllCharacteristics, + imageCharacteristics: GetImageCharacteristics(imageFileMachine, fileKind), + sizeOfStackReserve: moduleBuilder.GetStackReserve(1048576)); + + // initialize PE builder + var peBuilder = new ManagedPEBuilder( + peHeaderBuilder, + new MetadataRootBuilder(moduleBuilder.Metadata), + moduleBuilder.ILStream, + entryPoint: entryPoint, + flags: GetCorFlags(portableExecutableKind, keyPair), + deterministicIdProvider: GetDeterministicIdProvider(moduleBuilder)); + + // serialize the image + var pe = new BlobBuilder(); + peBuilder.Serialize(pe); + + // strong name specified, sign the blobs + if (keyPair != null) + peBuilder.Sign(pe, blobs => GetSignature(keyPair, blobs)); + + // write the final content to the output stream + pe.WriteContentTo(stream); + } + + /// + /// Writes the managed metadata to the . + /// + /// + static void WriteModuleImpl(IKVM.Reflection.Emit.ModuleBuilder moduleBuilder) + { + // now that we're ready to start writing, we need to do some fix ups + moduleBuilder.TypeRef.Fixup(moduleBuilder); + moduleBuilder.MethodImpl.Fixup(moduleBuilder); + moduleBuilder.MethodSemantics.Fixup(moduleBuilder); + moduleBuilder.InterfaceImpl.Fixup(); + moduleBuilder.ResolveInterfaceImplPseudoTokens(); + moduleBuilder.MemberRef.Fixup(moduleBuilder); + moduleBuilder.Constant.Fixup(moduleBuilder); + moduleBuilder.FieldMarshal.Fixup(moduleBuilder); + moduleBuilder.DeclSecurity.Fixup(moduleBuilder); + moduleBuilder.GenericParam.Fixup(moduleBuilder); + moduleBuilder.CustomAttribute.Fixup(moduleBuilder); + moduleBuilder.FieldLayout.Fixup(moduleBuilder); + moduleBuilder.FieldRVA.Fixup(moduleBuilder); + moduleBuilder.ImplMap.Fixup(moduleBuilder); + moduleBuilder.ExportedType.Fixup(moduleBuilder); + moduleBuilder.ManifestResource.Fixup(moduleBuilder); + moduleBuilder.MethodSpec.Fixup(moduleBuilder); + moduleBuilder.GenericParamConstraint.Fixup(moduleBuilder); + + //// Import Address Table + //AssertRVA(mw, ImportAddressTableRVA); + //if (ImportAddressTableLength != 0) + //{ + // WriteRVA(mw, ImportHintNameTableRVA); + // WriteRVA(mw, 0); + //} + + //// CLI Header + //AssertRVA(mw, ComDescriptorRVA); + //cliHeader.MetaData.VirtualAddress = MetadataRVA; + //cliHeader.MetaData.Size = MetadataLength; + //if (ResourcesLength != 0) + //{ + // cliHeader.Resources.VirtualAddress = ResourcesRVA; + // cliHeader.Resources.Size = ResourcesLength; + //} + //if (StrongNameSignatureLength != 0) + //{ + // cliHeader.StrongNameSignature.VirtualAddress = StrongNameSignatureRVA; + // cliHeader.StrongNameSignature.Size = StrongNameSignatureLength; + //} + //if (VTableFixupsLength != 0) + //{ + // cliHeader.VTableFixups.VirtualAddress = VTableFixupsRVA; + // cliHeader.VTableFixups.Size = VTableFixupsLength; + //} + //cliHeader.Write(mw); + + //// alignment padding + //for (int i = (int)(MethodBodiesRVA - (ComDescriptorRVA + ComDescriptorLength)); i > 0; i--) + // mw.Write((byte)0); + + // Method Bodies + //mw.Write(moduleBuilder.methodBodies); + moduleBuilder.ILStream.WriteBytes(moduleBuilder.methodBodies.ToArray()); + + // Resources + //moduleBuilder.WriteResources(mw); + + // The strong name signature live here (if it exists), but it will written later + // and the following alignment padding will take care of reserving the space. + + //// alignment padding + //for (int i = (int)(MetadataRVA - (ResourcesRVA + ResourcesLength)); i > 0; i--) + // mw.Write((byte)0); + + // Metadata + //AssertRVA(mw, MetadataRVA); + moduleBuilder.WriteMetadata(); + + //// alignment padding + //for (int i = (int)(VTableFixupsRVA - (MetadataRVA + MetadataLength)); i > 0; i--) + // mw.Write((byte)0); + + //// VTableFixups + //AssertRVA(mw, VTableFixupsRVA); + //WriteVTableFixups(mw, sdataRVA); + + //// Debug Directory + //AssertRVA(mw, DebugDirectoryRVA); + //WriteDebugDirectory(mw); + + //// Export Directory + //AssertRVA(mw, ExportDirectoryRVA); + //WriteExportDirectory(mw); + + //// Export Tables + //AssertRVA(mw, ExportTablesRVA); + //WriteExportTables(mw, sdataRVA); + + //// Import Directory + //AssertRVA(mw, ImportDirectoryRVA); + //if (ImportDirectoryLength != 0) + // WriteImportDirectory(mw); + } + + /// + /// Translates the parameter into a value. + /// + /// + /// + /// + static Machine GetMachine(ImageFileMachine imageFileMachine) + { + return imageFileMachine switch + { + ImageFileMachine.I386 => Machine.I386, + ImageFileMachine.ARM => Machine.Arm, + ImageFileMachine.AMD64 => Machine.Amd64, + ImageFileMachine.IA64 => Machine.IA64, + ImageFileMachine.ARM64 => Machine.Arm64, + _ => throw new ArgumentOutOfRangeException("imageFileMachine"), + }; + } + + /// + /// Obtains the appropriate value for a given . + /// + /// + /// + static Subsystem GetSubsystem(IKVM.Reflection.Emit.PEFileKinds fileKind) => fileKind switch + { + IKVM.Reflection.Emit.PEFileKinds.WindowApplication => Subsystem.WindowsGui, + _ => Subsystem.WindowsCui, + }; + + /// + /// Obtains the appropriate value for the given and . + /// + /// + /// + /// + /// + static Characteristics GetImageCharacteristics(ImageFileMachine imageFileMachine, IKVM.Reflection.Emit.PEFileKinds fileKind) + { + var characteristics = default(Characteristics); - var writer = new PEWriter(stream); - writer.Headers.OptionalHeader.FileAlignment = (uint)moduleBuilder.__FileAlignment; switch (imageFileMachine) { case ImageFileMachine.I386: - writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386; - writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE; - writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x100000); + characteristics |= Characteristics.Bit32Machine; break; case ImageFileMachine.ARM: - writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM; - writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE; - writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x100000); - writer.Headers.OptionalHeader.SectionAlignment = 0x1000; + characteristics |= Characteristics.Bit32Machine | Characteristics.LargeAddressAware; break; case ImageFileMachine.AMD64: - writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64; - writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE; - writer.Headers.FileHeader.SizeOfOptionalHeader = 0xF0; - writer.Headers.OptionalHeader.Magic = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC; - writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x400000); - writer.Headers.OptionalHeader.SizeOfStackCommit = 0x4000; - writer.Headers.OptionalHeader.SizeOfHeapCommit = 0x2000; - break; case ImageFileMachine.IA64: - writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64; - writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE; - writer.Headers.FileHeader.SizeOfOptionalHeader = 0xF0; - writer.Headers.OptionalHeader.Magic = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC; - writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x400000); - writer.Headers.OptionalHeader.SizeOfStackCommit = 0x4000; - writer.Headers.OptionalHeader.SizeOfHeapCommit = 0x2000; - break; case ImageFileMachine.ARM64: - writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM64; - writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE; - writer.Headers.FileHeader.SizeOfOptionalHeader = 0xF0; - writer.Headers.OptionalHeader.Magic = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC; - writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x400000); - writer.Headers.OptionalHeader.SizeOfStackCommit = 0x4000; - writer.Headers.OptionalHeader.SizeOfHeapCommit = 0x2000; + characteristics |= Characteristics.LargeAddressAware; break; default: throw new ArgumentOutOfRangeException("imageFileMachine"); } - if (fileKind == PEFileKinds.Dll) - writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_DLL; + if (fileKind == IKVM.Reflection.Emit.PEFileKinds.Dll) + characteristics |= Characteristics.Dll; - writer.Headers.OptionalHeader.Subsystem = fileKind switch - { - PEFileKinds.WindowApplication => IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_GUI, - _ => IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_CUI, - }; - - writer.Headers.OptionalHeader.DllCharacteristics = (ushort)moduleBuilder.__DllCharacteristics; + return characteristics; + } - var cliHeader = new CliHeader(); - cliHeader.Cb = 0x48; - cliHeader.MajorRuntimeVersion = 2; - cliHeader.MinorRuntimeVersion = moduleBuilder.MDStreamVersion < 0x20000 ? (ushort)0 : (ushort)5; + /// + /// Obtains the appropriate value for the given and . + /// + /// + /// + /// + static CorFlags GetCorFlags(PortableExecutableKinds portableExecutableKind, StrongNameKeyPair keyPair) + { + var flags = default(CorFlags); if ((portableExecutableKind & PortableExecutableKinds.ILOnly) != 0) - cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_ILONLY; - + flags |= CorFlags.ILOnly; if ((portableExecutableKind & PortableExecutableKinds.Required32Bit) != 0) - cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED; - + flags |= CorFlags.Requires32Bit; if ((portableExecutableKind & PortableExecutableKinds.Preferred32Bit) != 0) - cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED; - + flags |= CorFlags.Requires32Bit | CorFlags.Prefers32Bit; if (keyPair != null) - cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_STRONGNAMESIGNED; - - if (ModuleBuilder.IsPseudoToken(entryPointToken)) - entryPointToken = moduleBuilder.ResolvePseudoToken(entryPointToken); - - cliHeader.EntryPointToken = (uint)entryPointToken; - - moduleBuilder.Strings.Freeze(); - moduleBuilder.UserStrings.Freeze(); - moduleBuilder.Guids.Freeze(); - moduleBuilder.Blobs.Freeze(); - var mw = new MetadataWriter(moduleBuilder, stream); - moduleBuilder.Tables.Freeze(mw); - - var code = new TextSection(writer, cliHeader, moduleBuilder, ComputeStrongNameSignatureLength(publicKey)); - - // Export Directory - if (code.ExportDirectoryLength != 0) - { - writer.Headers.OptionalHeader.DataDirectory[0].VirtualAddress = code.ExportDirectoryRVA; - writer.Headers.OptionalHeader.DataDirectory[0].Size = code.ExportDirectoryLength; - } - - // Import Directory - if (code.ImportDirectoryLength != 0) - { - writer.Headers.OptionalHeader.DataDirectory[1].VirtualAddress = code.ImportDirectoryRVA; - writer.Headers.OptionalHeader.DataDirectory[1].Size = code.ImportDirectoryLength; - } - - // Import Address Table Directory - if (code.ImportAddressTableLength != 0) - { - writer.Headers.OptionalHeader.DataDirectory[12].VirtualAddress = code.ImportAddressTableRVA; - writer.Headers.OptionalHeader.DataDirectory[12].Size = code.ImportAddressTableLength; - } - - // COM Descriptor Directory - writer.Headers.OptionalHeader.DataDirectory[14].VirtualAddress = code.ComDescriptorRVA; - writer.Headers.OptionalHeader.DataDirectory[14].Size = code.ComDescriptorLength; - - // Debug Directory - if (code.DebugDirectoryLength != 0) - { - writer.Headers.OptionalHeader.DataDirectory[6].VirtualAddress = code.DebugDirectoryRVA; - writer.Headers.OptionalHeader.DataDirectory[6].Size = code.DebugDirectoryLength; - } - - // Set the PE File timestamp - writer.Headers.FileHeader.TimeDateStamp = moduleBuilder.GetTimeDateStamp(); - - // we need to start by computing the number of sections, because code.PointerToRawData depends on that - writer.Headers.FileHeader.NumberOfSections = 2; - - if (moduleBuilder.initializedData.Length != 0) - { - // .sdata - writer.Headers.FileHeader.NumberOfSections++; - } - - if (resources != null) - { - // .rsrc - writer.Headers.FileHeader.NumberOfSections++; - } + flags |= CorFlags.StrongNameSigned; - var text = new SectionHeader(); - text.Name = ".text"; - text.VirtualAddress = code.BaseRVA; - text.VirtualSize = (uint)code.Length; - text.PointerToRawData = code.PointerToRawData; - text.SizeOfRawData = writer.ToFileAlignment((uint)code.Length); - text.Characteristics = SectionHeader.IMAGE_SCN_CNT_CODE | SectionHeader.IMAGE_SCN_MEM_EXECUTE | SectionHeader.IMAGE_SCN_MEM_READ; - - var sdata = new SectionHeader(); - sdata.Name = ".sdata"; - sdata.VirtualAddress = text.VirtualAddress + writer.ToSectionAlignment(text.VirtualSize); - sdata.VirtualSize = (uint)moduleBuilder.initializedData.Length; - sdata.PointerToRawData = text.PointerToRawData + text.SizeOfRawData; - sdata.SizeOfRawData = writer.ToFileAlignment((uint)moduleBuilder.initializedData.Length); - sdata.Characteristics = SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_MEM_WRITE; - - var rsrc = new SectionHeader(); - rsrc.Name = ".rsrc"; - rsrc.VirtualAddress = sdata.VirtualAddress + writer.ToSectionAlignment(sdata.VirtualSize); - rsrc.PointerToRawData = sdata.PointerToRawData + sdata.SizeOfRawData; - rsrc.VirtualSize = resources == null ? 0 : (uint)resources.Length; - rsrc.SizeOfRawData = writer.ToFileAlignment(rsrc.VirtualSize); - rsrc.Characteristics = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA; - - if (rsrc.SizeOfRawData != 0) - { - // Resource Directory - writer.Headers.OptionalHeader.DataDirectory[2].VirtualAddress = rsrc.VirtualAddress; - writer.Headers.OptionalHeader.DataDirectory[2].Size = rsrc.VirtualSize; - } - - var reloc = new SectionHeader(); - reloc.Name = ".reloc"; - reloc.VirtualAddress = rsrc.VirtualAddress + writer.ToSectionAlignment(rsrc.VirtualSize); - reloc.VirtualSize = code.PackRelocations(); - reloc.PointerToRawData = rsrc.PointerToRawData + rsrc.SizeOfRawData; - reloc.SizeOfRawData = writer.ToFileAlignment(reloc.VirtualSize); - reloc.Characteristics = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_DISCARDABLE; - - if (reloc.SizeOfRawData != 0) - { - // Base Relocation Directory - writer.Headers.OptionalHeader.DataDirectory[5].VirtualAddress = reloc.VirtualAddress; - writer.Headers.OptionalHeader.DataDirectory[5].Size = reloc.VirtualSize; - } - - writer.Headers.OptionalHeader.SizeOfCode = text.SizeOfRawData; - writer.Headers.OptionalHeader.SizeOfInitializedData = sdata.SizeOfRawData + rsrc.SizeOfRawData + reloc.SizeOfRawData; - writer.Headers.OptionalHeader.SizeOfUninitializedData = 0; - writer.Headers.OptionalHeader.SizeOfImage = reloc.VirtualAddress + writer.ToSectionAlignment(reloc.VirtualSize); - writer.Headers.OptionalHeader.SizeOfHeaders = text.PointerToRawData; - writer.Headers.OptionalHeader.BaseOfCode = code.BaseRVA; - writer.Headers.OptionalHeader.BaseOfData = sdata.VirtualAddress; - writer.Headers.OptionalHeader.ImageBase = (ulong)moduleBuilder.__ImageBase; + return flags; + } - if (imageFileMachine == ImageFileMachine.IA64) - { - // apparently for IA64 AddressOfEntryPoint points to the address of the entry point - // (i.e. there is an additional layer of indirection), so we add the offset to the pointer - writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA + 0x20; - } + /// + /// Gets the appropriate ID provider for the generation of the module version ID. + /// + /// + /// + static Func, BlobContentId> GetDeterministicIdProvider(Emit.ModuleBuilder moduleBuilder) + { + if (moduleBuilder.GetModuleVersionIdOrEmpty() is Guid mvid && mvid != Guid.Empty) + return e => new BlobContentId(mvid, 1); + else if (moduleBuilder.universe.Deterministic) + return e => BlobContentId.FromHash(GetSHA1Hash(e)); else - { - writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA + writer.Thumb; - } - - writer.WritePEHeaders(); - writer.WriteSectionHeader(text); - if (sdata.SizeOfRawData != 0) - writer.WriteSectionHeader(sdata); - if (rsrc.SizeOfRawData != 0) - writer.WriteSectionHeader(rsrc); - if (reloc.SizeOfRawData != 0) - writer.WriteSectionHeader(reloc); + return BlobContentId.GetTimeBasedProvider(); - stream.Seek(text.PointerToRawData, SeekOrigin.Begin); - code.Write(mw, sdata.VirtualAddress, out var guidHeapOffset); - - if (sdata.SizeOfRawData != 0) - { - stream.Seek(sdata.PointerToRawData, SeekOrigin.Begin); - mw.Write(moduleBuilder.initializedData); - } - - if (rsrc.SizeOfRawData != 0) - { - stream.Seek(rsrc.PointerToRawData, SeekOrigin.Begin); - resources.Write(mw, rsrc.VirtualAddress); - } - - if (reloc.SizeOfRawData != 0) - { - stream.Seek(reloc.PointerToRawData, SeekOrigin.Begin); - code.WriteRelocations(mw); - } - - // file alignment - stream.SetLength(reloc.PointerToRawData + reloc.SizeOfRawData); - - // if we don't have a guid, generate one based on the contents of the assembly - if (moduleBuilder.universe.Deterministic && moduleBuilder.GetModuleVersionIdOrEmpty() == Guid.Empty) - { - var guid = GenerateModuleVersionId(stream); - stream.Position = guidHeapOffset + (moduleVersionIdIndex - 1) * 16; - stream.Write(guid.ToByteArray(), 0, 16); - moduleBuilder.__SetModuleVersionId(guid); - } - - // do the strong naming - 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 BlobContentId DeterministicIdProvider(IEnumerable enumerable) + { + throw new NotImplementedException(); } static int ComputeStrongNameSignatureLength(byte[] publicKey) @@ -366,147 +403,40 @@ static int ComputeStrongNameSignatureLength(byte[] publicKey) } } - static void StrongName(Stream stream, StrongNameKeyPair keyPair, uint headerLength, uint textSectionFileOffset, uint strongNameSignatureFileOffset, uint strongNameSignatureLength) - { - byte[] hash; - using (var sha1 = SHA1.Create()) - { - stream.Seek(0, SeekOrigin.Begin); - var skipStream = new SkipStream(stream, strongNameSignatureFileOffset, strongNameSignatureLength); - skipStream = new SkipStream(skipStream, headerLength, textSectionFileOffset - headerLength); - hash = sha1.ComputeHash(skipStream); - } - - using (var rsa = keyPair.CreateRSA()) - { - var signature = rsa.SignHash(hash, "1.3.14.3.2.26"); - Array.Reverse(signature); - if (signature.Length != strongNameSignatureLength) - throw new InvalidOperationException("Signature length mismatch"); - - stream.Seek(strongNameSignatureFileOffset, SeekOrigin.Begin); - stream.Write(signature, 0, signature.Length); - } - - // compute the PE checksum - stream.Seek(0, SeekOrigin.Begin); - var count = (int)stream.Length / 4; - var br = new BinaryReader(stream); - - long sum = 0; - for (int i = 0; i < count; i++) - { - sum += br.ReadUInt32(); - int carry = (int)(sum >> 32); - sum &= 0xFFFFFFFFU; - sum += carry; - } - - while ((sum >> 16) != 0) - sum = (sum & 0xFFFF) + (sum >> 16); - - sum += stream.Length; - - // write the PE checksum, note that it is always at offset 0xD8 in the file - var bb = new ByteBuffer(4); - bb.Write((int)sum); - stream.Seek(0xD8, SeekOrigin.Begin); - bb.WriteTo(stream); - } - -#if NET7_0_OR_GREATER - /// - /// Hashes the entire output stream to generate the MVID. Sets the GUID type to "version 4" (random). + /// Gets a hash of the specified blobs. /// - /// + /// /// - static unsafe Guid GenerateModuleVersionId(Stream stream) + static byte[] GetSHA1Hash(IEnumerable blobs) { - var hash = (Span)stackalloc byte[20]; + using var sha1 = SHA1.Create(); - var indx = stream.Position; - try - { - stream.Seek(0, SeekOrigin.Begin); - SHA1.HashData(stream, hash); - } - finally + foreach (var blob in blobs) { - stream.Seek(indx, SeekOrigin.Begin); + var data = blob.GetBytes(); + sha1.TransformBlock(data.Array, data.Offset, data.Count, null, 0); } - var mvid = hash.Slice(0, 16); - mvid[7] &= 0x0F; - mvid[7] |= 0x40; - mvid[8] &= 0x3F; - mvid[8] |= 0x80; - return GuidFromSpan(mvid); - } - -#else + sha1.TransformFinalBlock(Array.Empty(), 0, 0); - /// - /// Computes a hash for the seekable stream. - /// - /// - /// - static byte[] ComputeSHA1Array(Stream stream) - { - var indx = stream.Position; - try - { - using var hash = SHA1.Create(); - stream.Seek(0, SeekOrigin.Begin); - return hash.ComputeHash(stream); - } - finally - { - stream.Seek(indx, SeekOrigin.Begin); - } + return sha1.Hash; } /// - /// Hashes the entire output stream to generate the MVID. Sets the GUID type to "version 4" (random). + /// Calculates the strong name signature for the specified blobs. /// - /// + /// /// - static Guid GenerateModuleVersionId(Stream stream) + /// + static byte[] GetSignature(StrongNameKeyPair keyPair, IEnumerable blobs) { - var hash = ComputeSHA1Array(stream); - var mvid = hash.AsSpan().Slice(0, 16); - mvid[7] &= 0x0F; - mvid[7] |= 0x40; - mvid[8] &= 0x3F; - mvid[8] |= 0x80; - return GuidFromSpan(mvid); - } + // sign the hash with the keypair + using var rsa = keyPair.CreateRSA(); + var signature = rsa.SignHash(GetSHA1Hash(blobs), "1.3.14.3.2.26"); + Array.Reverse(signature); -#endif - - /// - /// Creates a new from a span. Optimized for .NET. - /// - /// - /// - static Guid GuidFromSpan(ReadOnlySpan b) - { -#if NETFRAMEWORK - var _a = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]; - var _b = (short)((b[5] << 8) | b[4]); - var _c = (short)((b[7] << 8) | b[6]); - var _d = b[8]; - var _e = b[9]; - var _f = b[10]; - var _g = b[11]; - var _h = b[12]; - var _i = b[13]; - var _j = b[14]; - var _k = b[15]; - return new Guid(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k); -#else - return new Guid(b); -#endif + return signature; } } diff --git a/src/IKVM.Reflection/Writer/PEWriter.cs b/src/IKVM.Reflection/Writer/PEWriter.cs deleted file mode 100644 index 676f922e33..0000000000 --- a/src/IKVM.Reflection/Writer/PEWriter.cs +++ /dev/null @@ -1,138 +0,0 @@ -/* - Copyright (C) 2008-2013 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.IO; - -namespace IKVM.Reflection.Writer -{ - - sealed class PEWriter - { - - readonly BinaryWriter bw; - readonly IMAGE_NT_HEADERS hdr = new IMAGE_NT_HEADERS(); - - /// - /// Initializes a new instance. - /// - /// - internal PEWriter(Stream stream) - { - bw = new BinaryWriter(stream); - WriteMSDOSHeader(); - } - - public IMAGE_NT_HEADERS Headers => hdr; - - public uint HeaderSize - { - get - { - return (uint) - ((8 * 16) + // MSDOS header - 4 + // signature - 20 + // IMAGE_FILE_HEADER - hdr.FileHeader.SizeOfOptionalHeader + - hdr.FileHeader.NumberOfSections * 40); - } - } - - private void WriteMSDOSHeader() - { - bw.Write(new byte[] { - 0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, - 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, - 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, - 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, - 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, - 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }); - } - - internal void WritePEHeaders() - { - bw.Write(hdr.Signature); - - // IMAGE_FILE_HEADER - bw.Write(hdr.FileHeader.Machine); - bw.Write(hdr.FileHeader.NumberOfSections); - bw.Write(hdr.FileHeader.TimeDateStamp); - bw.Write(hdr.FileHeader.PointerToSymbolTable); - bw.Write(hdr.FileHeader.NumberOfSymbols); - bw.Write(hdr.FileHeader.SizeOfOptionalHeader); - bw.Write(hdr.FileHeader.Characteristics); - - // IMAGE_OPTIONAL_HEADER - hdr.OptionalHeader.Write(bw); - } - - internal void WriteSectionHeader(SectionHeader sectionHeader) - { - var name = new byte[8]; - System.Text.Encoding.UTF8.GetBytes(sectionHeader.Name, 0, sectionHeader.Name.Length, name, 0); - bw.Write(name); - bw.Write(sectionHeader.VirtualSize); - bw.Write(sectionHeader.VirtualAddress); - bw.Write(sectionHeader.SizeOfRawData); - bw.Write(sectionHeader.PointerToRawData); - bw.Write(sectionHeader.PointerToRelocations); - bw.Write(sectionHeader.PointerToLinenumbers); - bw.Write(sectionHeader.NumberOfRelocations); - bw.Write(sectionHeader.NumberOfLinenumbers); - bw.Write(sectionHeader.Characteristics); - } - - internal uint ToFileAlignment(uint p) - { - return (p + (Headers.OptionalHeader.FileAlignment - 1)) & ~(Headers.OptionalHeader.FileAlignment - 1); - } - - internal uint ToSectionAlignment(uint p) - { - return (p + (Headers.OptionalHeader.SectionAlignment - 1)) & ~(Headers.OptionalHeader.SectionAlignment - 1); - } - - internal bool Is32Bit - { - get { return (Headers.FileHeader.Characteristics & IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE) != 0; } - } - - internal uint Thumb - { - // On ARM we need to set the least significant bit of the program counter to select the Thumb instruction set - get { return Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM ? 1u : 0u; } - } - - } - -} diff --git a/src/IKVM.Reflection/Writer/ResourceSection.cs b/src/IKVM.Reflection/Writer/ResourceSection.cs index 10a9255299..9e5c326988 100644 --- a/src/IKVM.Reflection/Writer/ResourceSection.cs +++ b/src/IKVM.Reflection/Writer/ResourceSection.cs @@ -124,17 +124,6 @@ internal int Length get { return bb.Length; } } - internal void Write(MetadataWriter mw, uint rva) - { - foreach (int offset in linkOffsets) - { - bb.Position = offset; - bb.Write(bb.GetInt32AtCurrentPosition() + (int)rva); - } - - mw.Write(bb); - } - } } diff --git a/src/IKVM.Reflection/Writer/SimpleHeap.cs b/src/IKVM.Reflection/Writer/SimpleHeap.cs deleted file mode 100644 index 673467d110..0000000000 --- a/src/IKVM.Reflection/Writer/SimpleHeap.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright (C) 2008 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; - -namespace IKVM.Reflection.Writer -{ - - abstract class SimpleHeap : Heap - { - - internal void Freeze() - { - if (frozen) - throw new InvalidOperationException(); - - frozen = true; - unalignedlength = GetLength(); - } - - protected abstract int GetLength(); - - } - -} diff --git a/src/IKVM.Reflection/Writer/StringHeap.cs b/src/IKVM.Reflection/Writer/StringHeap.cs deleted file mode 100644 index ff6845a087..0000000000 --- a/src/IKVM.Reflection/Writer/StringHeap.cs +++ /dev/null @@ -1,90 +0,0 @@ -/* - Copyright (C) 2008 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.Collections.Generic; -using System.Diagnostics; - -namespace IKVM.Reflection.Writer -{ - - sealed class StringHeap : SimpleHeap - { - - readonly List list = new List(); - readonly Dictionary strings = new Dictionary(); - int nextOffset; - - /// - /// Initializes a new instance. - /// - internal StringHeap() - { - Add(""); - } - - /// - /// Adds a new string to the heap. - /// - /// - /// - internal int Add(string str) - { - Debug.Assert(frozen == false); - - if (strings.TryGetValue(str, out var offset) == false) - { - offset = nextOffset; - nextOffset += System.Text.Encoding.UTF8.GetByteCount(str) + 1; - list.Add(str); - strings.Add(str, offset); - } - - return offset; - } - - internal string Find(int index) - { - foreach (var kv in strings) - if (kv.Value == index) - return kv.Key; - - return null; - } - - protected override int GetLength() - { - return nextOffset; - } - - protected override void WriteImpl(MetadataWriter mw) - { - foreach (var str in list) - { - mw.Write(System.Text.Encoding.UTF8.GetBytes(str)); - mw.Write((byte)0); - } - } - - } - -} diff --git a/src/IKVM.Reflection/Writer/TableHeap.cs b/src/IKVM.Reflection/Writer/TableHeap.cs deleted file mode 100644 index 7a145dc168..0000000000 --- a/src/IKVM.Reflection/Writer/TableHeap.cs +++ /dev/null @@ -1,117 +0,0 @@ -/* - Copyright (C) 2008 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.Diagnostics; - -namespace IKVM.Reflection.Writer -{ - - sealed class TableHeap : Heap - { - - internal void Freeze(MetadataWriter mw) - { - if (frozen) - throw new InvalidOperationException(); - - frozen = true; - unalignedlength = GetLength(mw); - } - - protected override void WriteImpl(MetadataWriter mw) - { - var tables = mw.ModuleBuilder.GetTables(); - - // Header - mw.Write(0); // Reserved - - int ver = mw.ModuleBuilder.MDStreamVersion; - mw.Write((byte)(ver >> 16)); // MajorVersion - mw.Write((byte)ver); // MinorVersion - - byte heapSizes = 0; - if (mw.ModuleBuilder.Strings.IsBig) - heapSizes |= 0x01; - if (mw.ModuleBuilder.Guids.IsBig) - heapSizes |= 0x02; - if (mw.ModuleBuilder.Blobs.IsBig) - heapSizes |= 0x04; - mw.Write(heapSizes); // HeapSizes - - // LAMESPEC spec says reserved, but .NET 2.0 Ref.Emit sets it to 0x10 - mw.Write((byte)0x10); // Reserved - - long bit = 1; - long valid = 0; - foreach (var table in tables) - { - if (table != null && table.RowCount > 0) - valid |= bit; - - bit <<= 1; - } - - mw.Write(valid); // Valid - mw.Write(0x0016003301FA00L); // Sorted - - // Rows - foreach (var table in tables) - if (table != null && table.RowCount > 0) - mw.Write(table.RowCount); - - // Tables - foreach (var table in tables) - { - if (table != null && table.RowCount > 0) - { - var pos = mw.Position; - table.Write(mw); - Debug.Assert(mw.Position - pos == table.GetLength(mw)); - } - } - - // unexplained extra padding - mw.Write((byte)0); - } - - static int GetLength(MetadataWriter mw) - { - int len = 4 + 4 + 8 + 8; - - foreach (var table in mw.ModuleBuilder.GetTables()) - { - if (table != null && table.RowCount > 0) - { - len += 4; // row count - len += table.GetLength(mw); - } - } - - // note that we pad one extra (unexplained) byte - return len + 1; - } - - } - -} diff --git a/src/IKVM.Reflection/Writer/TextSection.cs b/src/IKVM.Reflection/Writer/TextSection.cs index 8acd4165f4..1926b623fe 100644 --- a/src/IKVM.Reflection/Writer/TextSection.cs +++ b/src/IKVM.Reflection/Writer/TextSection.cs @@ -1,808 +1,415 @@ -/* - Copyright (C) 2008-2013 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 +///* +// Copyright (C) 2008-2013 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; +//*/ +//using System; +//using System.Collections.Generic; +//using System.Diagnostics; -using IKVM.Reflection.Emit; -using IKVM.Reflection.Impl; -using IKVM.Reflection.Metadata; +//using IKVM.Reflection.Emit; +//using IKVM.Reflection.Impl; +//using IKVM.Reflection.Metadata; -namespace IKVM.Reflection.Writer -{ +//namespace IKVM.Reflection.Writer +//{ - sealed class TextSection - { +// sealed class TextSection +// { - readonly PEWriter peWriter; - readonly CliHeader cliHeader; - readonly ModuleBuilder moduleBuilder; - readonly uint strongNameSignatureLength; - readonly uint manifestResourcesLength; - readonly ExportTables exportTables; - readonly List relocations = new List(); +// readonly PEWriter peWriter; +// readonly CliHeader cliHeader; +// readonly ModuleBuilder moduleBuilder; +// readonly uint strongNameSignatureLength; +// readonly uint manifestResourcesLength; +// readonly ExportTables exportTables; +// readonly List relocations = new List(); - /// - /// Initializes a new instance. - /// - /// - /// - /// - /// - internal TextSection(PEWriter peWriter, CliHeader cliHeader, ModuleBuilder moduleBuilder, int strongNameSignatureLength) - { - this.peWriter = peWriter; - this.cliHeader = cliHeader; - this.moduleBuilder = moduleBuilder; - this.strongNameSignatureLength = (uint)strongNameSignatureLength; - this.manifestResourcesLength = (uint)moduleBuilder.GetManifestResourcesLength(); - if (moduleBuilder.unmanagedExports.Count != 0) - this.exportTables = new ExportTables(this); - } - - internal uint PointerToRawData => peWriter.ToFileAlignment(peWriter.HeaderSize); - - internal uint BaseRVA => peWriter.Headers.OptionalHeader.SectionAlignment; - - internal uint ImportAddressTableRVA => BaseRVA; - - internal uint ImportAddressTableLength => peWriter.Is32Bit ? 8u : 16u; - - internal uint ComDescriptorRVA => ImportAddressTableRVA + ImportAddressTableLength; - - internal uint ComDescriptorLength => cliHeader.Cb; - - internal uint MethodBodiesRVA => (ComDescriptorRVA + ComDescriptorLength + 7) & ~7U; - - uint MethodBodiesLength => (uint)moduleBuilder.methodBodies.Length; - - uint ResourcesRVA => peWriter.Headers.FileHeader.Machine switch - { - IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386 or IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM => (MethodBodiesRVA + MethodBodiesLength + 3) & ~3U, - _ => (MethodBodiesRVA + MethodBodiesLength + 15) & ~15U, - }; - - uint ResourcesLength => manifestResourcesLength; - - internal uint StrongNameSignatureRVA => (ResourcesRVA + ResourcesLength + 3) & ~3U; - - internal uint StrongNameSignatureLength => strongNameSignatureLength; - - uint MetadataRVA => (StrongNameSignatureRVA + StrongNameSignatureLength + 3) & ~3U; - - uint MetadataLength => (uint)moduleBuilder.MetadataLength; - - uint VTableFixupsRVA => (MetadataRVA + MetadataLength + 7) & ~7U; - - uint VTableFixupsLength => (uint)moduleBuilder.vtablefixups.Count * 8; - - internal uint DebugDirectoryRVA - { - get { return VTableFixupsRVA + VTableFixupsLength; } - } - - internal uint DebugDirectoryLength => DebugDirectoryContentsLength != 0 ? 28 : (uint)0; - - 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; - } - } - - internal uint ExportDirectoryRVA => (DebugDirectoryRVA + DebugDirectoryLength + DebugDirectoryContentsLength + 15) & ~15U; - - internal uint ExportDirectoryLength => moduleBuilder.unmanagedExports.Count == 0 ? 0U : 40U; - - uint ExportTablesRVA => ExportDirectoryRVA + ExportDirectoryLength; - - uint ExportTablesLength => exportTables == null ? 0U : exportTables.Length; - - internal uint ImportDirectoryRVA - { - // on AMD64 (and probably IA64) the import directory needs to be 16 byte aligned (on I386 4 byte alignment is sufficient) - get { return (ExportTablesRVA + ExportTablesLength + 15) & ~15U; } - } - - internal uint ImportDirectoryLength => (ImportHintNameTableRVA - ImportDirectoryRVA) + 27; - - uint ImportHintNameTableRVA => peWriter.Is32Bit - ? (ImportDirectoryRVA + 48 + 15) & ~15U - : (ImportDirectoryRVA + 52 + 15) & ~15U; - - internal uint StartupStubRVA - { - get - { - if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64) - { - // note that the alignment is driven by the requirement that the two relocation fixups are in a single page - return (ImportDirectoryRVA + ImportDirectoryLength + 15U) & ~15U; - } - else - { - // the additional 2 bytes padding are to align the address in the jump (which is a relocation fixup) - return 2 + ((ImportDirectoryRVA + ImportDirectoryLength + 3U) & ~3U); - } - } - } - - internal uint StartupStubLength => peWriter.Headers.FileHeader.Machine switch - { - IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386 => 6, - IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64 or IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM => 12, - IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64 => 48, - _ => throw new NotSupportedException(), - }; - - void WriteRVA(MetadataWriter mw, uint rva) - { - switch (peWriter.Headers.FileHeader.Machine) - { - case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386: - case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM: - mw.Write(rva); - break; - default: - mw.Write((ulong)rva); - break; - } - } - - internal void Write(MetadataWriter mw, uint sdataRVA, out uint guidHeapOffset) - { - // Now that we're ready to start writing, we need to do some fix ups - moduleBuilder.TypeRef.Fixup(moduleBuilder); - moduleBuilder.MethodDef.Fixup(this); - moduleBuilder.MethodImpl.Fixup(moduleBuilder); - moduleBuilder.MethodSemantics.Fixup(moduleBuilder); - moduleBuilder.InterfaceImpl.Fixup(); - moduleBuilder.ResolveInterfaceImplPseudoTokens(); - moduleBuilder.MemberRef.Fixup(moduleBuilder); - moduleBuilder.Constant.Fixup(moduleBuilder); - moduleBuilder.FieldMarshal.Fixup(moduleBuilder); - moduleBuilder.DeclSecurity.Fixup(moduleBuilder); - moduleBuilder.GenericParam.Fixup(moduleBuilder); - moduleBuilder.CustomAttribute.Fixup(moduleBuilder); - moduleBuilder.FieldLayout.Fixup(moduleBuilder); - moduleBuilder.FieldRVA.Fixup(moduleBuilder, (int)sdataRVA, (int)this.MethodBodiesRVA); - moduleBuilder.ImplMap.Fixup(moduleBuilder); - moduleBuilder.ExportedType.Fixup(moduleBuilder); - moduleBuilder.ManifestResource.Fixup(moduleBuilder); - moduleBuilder.MethodSpec.Fixup(moduleBuilder); - moduleBuilder.GenericParamConstraint.Fixup(moduleBuilder); - - // Import Address Table - AssertRVA(mw, ImportAddressTableRVA); - if (ImportAddressTableLength != 0) - { - WriteRVA(mw, ImportHintNameTableRVA); - WriteRVA(mw, 0); - } - - // CLI Header - AssertRVA(mw, ComDescriptorRVA); - cliHeader.MetaData.VirtualAddress = MetadataRVA; - cliHeader.MetaData.Size = MetadataLength; - if (ResourcesLength != 0) - { - cliHeader.Resources.VirtualAddress = ResourcesRVA; - cliHeader.Resources.Size = ResourcesLength; - } - if (StrongNameSignatureLength != 0) - { - cliHeader.StrongNameSignature.VirtualAddress = StrongNameSignatureRVA; - cliHeader.StrongNameSignature.Size = StrongNameSignatureLength; - } - if (VTableFixupsLength != 0) - { - cliHeader.VTableFixups.VirtualAddress = VTableFixupsRVA; - cliHeader.VTableFixups.Size = VTableFixupsLength; - } - cliHeader.Write(mw); - - // alignment padding - for (int i = (int)(MethodBodiesRVA - (ComDescriptorRVA + ComDescriptorLength)); i > 0; i--) - mw.Write((byte)0); - - // Method Bodies - mw.Write(moduleBuilder.methodBodies); - - // alignment padding - for (int i = (int)(ResourcesRVA - (MethodBodiesRVA + MethodBodiesLength)); i > 0; i--) - mw.Write((byte)0); - - // Resources - moduleBuilder.WriteResources(mw); - - // The strong name signature live here (if it exists), but it will written later - // and the following alignment padding will take care of reserving the space. - - // alignment padding - for (int i = (int)(MetadataRVA - (ResourcesRVA + ResourcesLength)); i > 0; i--) - mw.Write((byte)0); - - // Metadata - AssertRVA(mw, MetadataRVA); - moduleBuilder.WriteMetadata(mw, out guidHeapOffset); - - // alignment padding - for (int i = (int)(VTableFixupsRVA - (MetadataRVA + MetadataLength)); i > 0; i--) - mw.Write((byte)0); - - // VTableFixups - AssertRVA(mw, VTableFixupsRVA); - WriteVTableFixups(mw, sdataRVA); - - // Debug Directory - AssertRVA(mw, DebugDirectoryRVA); - WriteDebugDirectory(mw); - - // alignment padding - for (int i = (int)(ExportDirectoryRVA - (DebugDirectoryRVA + DebugDirectoryLength + DebugDirectoryContentsLength)); i > 0; i--) - mw.Write((byte)0); - - // Export Directory - AssertRVA(mw, ExportDirectoryRVA); - WriteExportDirectory(mw); - - // Export Tables - AssertRVA(mw, ExportTablesRVA); - WriteExportTables(mw, sdataRVA); - - // alignment padding - for (int i = (int)(ImportDirectoryRVA - (ExportTablesRVA + ExportTablesLength)); i > 0; i--) - mw.Write((byte)0); - - // Import Directory - AssertRVA(mw, ImportDirectoryRVA); - if (ImportDirectoryLength != 0) - WriteImportDirectory(mw); - - // alignment padding - for (int i = (int)(StartupStubRVA - (ImportDirectoryRVA + ImportDirectoryLength)); i > 0; i--) - mw.Write((byte)0); - - // Startup Stub - AssertRVA(mw, StartupStubRVA); - if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64) - { - /* - * 48 A1 00 20 40 00 00 00 00 00 mov rax,qword ptr [0000000000402000h] - * FF E0 jmp rax - */ - mw.Write((ushort)0xA148); - mw.Write(peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA); - mw.Write((ushort)0xE0FF); - } - else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64) - { - mw.Write(new byte[] { - 0x0B, 0x48, 0x00, 0x02, 0x18, 0x10, 0xA0, 0x40, 0x24, 0x30, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, - 0x10, 0x08, 0x00, 0x12, 0x18, 0x10, 0x60, 0x50, 0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0x80, 0x00 - }); - mw.Write(peWriter.Headers.OptionalHeader.ImageBase + StartupStubRVA); - mw.Write(peWriter.Headers.OptionalHeader.ImageBase + BaseRVA); - } - else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386) - { - mw.Write((ushort)0x25FF); - mw.Write((uint)peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA); - } - else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM) - { - var rva = (uint)peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA; - var lo = (ushort)rva; - var hi = (ushort)(rva >> 16); - mw.Write((ushort)(0xF240 + (lo >> 12))); - mw.Write((ushort)(0x0C00 + ((lo << 4) & 0xF000) + (lo & 0xFF))); - mw.Write((ushort)(0xF2C0 + (hi >> 12))); - mw.Write((ushort)(0x0C00 + ((hi << 4) & 0xF000) + (hi & 0xFF))); - mw.Write((ushort)0xF8DC); - mw.Write((ushort)0xF000); - } - else - { - throw new NotSupportedException(); - } - } - - [Conditional("DEBUG")] - void AssertRVA(MetadataWriter mw, uint rva) - { - Debug.Assert(mw.Position - PointerToRawData + BaseRVA == rva); - } - - void WriteVTableFixups(MetadataWriter mw, uint sdataRVA) - { - foreach (ModuleBuilder.VTableFixups fixups in moduleBuilder.vtablefixups) - { - mw.Write(fixups.initializedDataOffset + sdataRVA); - mw.Write(fixups.count); - mw.Write(fixups.type); - } - } - - void WriteDebugDirectory(MetadataWriter mw) - { - if (DebugDirectoryLength != 0) - { -#if NETFRAMEWORK - IMAGE_DEBUG_DIRECTORY idd = new IMAGE_DEBUG_DIRECTORY(); - idd.Characteristics = 0; - idd.TimeDateStamp = peWriter.Headers.FileHeader.TimeDateStamp; - byte[] buf = SymbolSupport.GetDebugInfo(moduleBuilder.symbolWriter, ref idd); - idd.PointerToRawData = (DebugDirectoryRVA - BaseRVA) + DebugDirectoryLength + PointerToRawData; - idd.AddressOfRawData = DebugDirectoryRVA + DebugDirectoryLength; - mw.Write(idd.Characteristics); - mw.Write(idd.TimeDateStamp); - mw.Write(idd.MajorVersion); - mw.Write(idd.MinorVersion); - mw.Write(idd.Type); - mw.Write(idd.SizeOfData); - mw.Write(idd.AddressOfRawData); - mw.Write(idd.PointerToRawData); - mw.Write(buf); -#else - throw new NotSupportedException(); -#endif - } - } - - sealed class ExportTables - { - - readonly TextSection text; - internal readonly uint entries; - internal readonly uint ordinalBase; - internal readonly uint nameCount; - internal readonly uint namesLength; - internal readonly uint exportAddressTableRVA; - internal readonly uint exportNamePointerTableRVA; - internal readonly uint exportOrdinalTableRVA; - internal readonly uint namesRVA; - internal readonly uint stubsRVA; - readonly uint stubLength; - - /// - /// Initializes a new instance. - /// - /// - /// - internal ExportTables(TextSection text) - { - this.text = text; - ordinalBase = GetOrdinalBase(out entries); - namesLength = GetExportNamesLength(out nameCount); - exportAddressTableRVA = text.ExportTablesRVA; - exportNamePointerTableRVA = exportAddressTableRVA + 4 * entries; - exportOrdinalTableRVA = exportNamePointerTableRVA + 4 * nameCount; - namesRVA = exportOrdinalTableRVA + 2 * nameCount; - stubsRVA = (namesRVA + namesLength + 15) & ~15U; - - // note that we align the stubs to avoid having to deal with the relocation crossing a page boundary - stubLength = text.peWriter.Headers.FileHeader.Machine switch - { - IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386 => 8, - IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64 or IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM => 16, - _ => throw new NotSupportedException(), - }; - } - - internal uint Length => stubsRVA + stubLength * (uint)text.moduleBuilder.unmanagedExports.Count - text.ExportTablesRVA; - - uint GetOrdinalBase(out uint entries) - { - var min = uint.MaxValue; - var max = uint.MinValue; - foreach (var exp in text.moduleBuilder.unmanagedExports) - { - var ordinal = (uint)exp.ordinal; - min = Math.Min(min, ordinal); - max = Math.Max(max, ordinal); - } - - entries = 1 + (max - min); - return min; - } - - uint GetExportNamesLength(out uint nameCount) - { - nameCount = 0; - - // the first name in the names list is the module name (the Export Directory contains a name of the current module) - var length = (uint)text.moduleBuilder.fileName.Length + 1; - foreach (var exp in text.moduleBuilder.unmanagedExports) - { - if (exp.name != null) - { - nameCount++; - length += (uint)exp.name.Length + 1; - } - } - - return length; - } - - internal void Write(MetadataWriter mw, uint sdataRVA) - { - // sort the exports by ordinal - text.moduleBuilder.unmanagedExports.Sort(CompareUnmanagedExportOrdinals); - - // Now write the Export Address Table - text.AssertRVA(mw, exportAddressTableRVA); - for (int i = 0, pos = 0; i < entries; i++) - { - if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase) - { - mw.Write(text.peWriter.Thumb + stubsRVA + (uint)pos * stubLength); - pos++; - } - else - { - mw.Write(0); - } - } - - // sort the exports by name - text.moduleBuilder.unmanagedExports.Sort(CompareUnmanagedExportNames); - - // Now write the Export Name Pointer Table - text.AssertRVA(mw, exportNamePointerTableRVA); - uint nameOffset = (uint)text.moduleBuilder.fileName.Length + 1; - foreach (var exp in text.moduleBuilder.unmanagedExports) - { - if (exp.name != null) - { - mw.Write(namesRVA + nameOffset); - nameOffset += (uint)exp.name.Length + 1; - } - } - - // Now write the Export Ordinal Table - text.AssertRVA(mw, exportOrdinalTableRVA); - foreach (var exp in text.moduleBuilder.unmanagedExports) - if (exp.name != null) - mw.Write((ushort)(exp.ordinal - ordinalBase)); - - // Now write the actual names - text.AssertRVA(mw, namesRVA); - mw.WriteAsciiz(text.moduleBuilder.fileName); - foreach (var exp in text.moduleBuilder.unmanagedExports) - { - if (exp.name != null) - mw.WriteAsciiz(exp.name); - } - - text.AssertRVA(mw, namesRVA + namesLength); - - // alignment padding - for (int i = (int)(stubsRVA - (namesRVA + namesLength)); i > 0; i--) - mw.Write((byte)0); - - // sort the exports by ordinal - text.moduleBuilder.unmanagedExports.Sort(CompareUnmanagedExportOrdinals); - - // Now write the stubs - text.AssertRVA(mw, stubsRVA); - - for (int i = 0, pos = 0; i < entries; i++) - { - if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase) - { - switch (text.peWriter.Headers.FileHeader.Machine) - { - case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386: - mw.Write((byte)0xFF); - mw.Write((byte)0x25); - mw.Write((uint)text.peWriter.Headers.OptionalHeader.ImageBase + text.moduleBuilder.unmanagedExports[pos].rva.initializedDataOffset + sdataRVA); - mw.Write((short)0); // alignment - break; - case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: - mw.Write((byte)0x48); - mw.Write((byte)0xA1); - mw.Write(text.peWriter.Headers.OptionalHeader.ImageBase + text.moduleBuilder.unmanagedExports[pos].rva.initializedDataOffset + sdataRVA); - mw.Write((byte)0xFF); - mw.Write((byte)0xE0); - mw.Write(0); // alignment - break; - case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM: - mw.Write((ushort)0xF8DF); - mw.Write((ushort)0xC008); - mw.Write((ushort)0xF8DC); - mw.Write((ushort)0xC000); - mw.Write((ushort)0x4760); - mw.Write((ushort)0xDEFE); - mw.Write((uint)text.peWriter.Headers.OptionalHeader.ImageBase + text.moduleBuilder.unmanagedExports[pos].rva.initializedDataOffset + sdataRVA); - break; - default: - throw new NotSupportedException(); - } - pos++; - } - } - } - - static int CompareUnmanagedExportNames(UnmanagedExport x, UnmanagedExport y) - { - if (x.name == null) - return y.name == null ? 0 : 1; - if (y.name == null) - return -1; - - return string.CompareOrdinal(x.name, y.name); - } - - static int CompareUnmanagedExportOrdinals(UnmanagedExport x, UnmanagedExport y) - { - return x.ordinal.CompareTo(y.ordinal); - } - - internal void GetRelocations(List list) - { - ushort type; - uint rva; - switch (text.peWriter.Headers.FileHeader.Machine) - { - case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386: - type = 0x3000; - rva = stubsRVA + 2; - break; - case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: - type = 0xA000; - rva = stubsRVA + 2; - break; - case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM: - type = 0x3000; - rva = stubsRVA + 12; - break; - default: - throw new NotSupportedException(); - } - - // we assume that unmanagedExports is still sorted by ordinal - for (int i = 0, pos = 0; i < entries; i++) - { - if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase) - { - list.Add(new Relocation(type, rva + (uint)pos * stubLength)); - pos++; - } - } - } - } - - uint GetOrdinalBase(out uint entries) - { - var min = uint.MaxValue; - var max = uint.MinValue; - foreach (var exp in moduleBuilder.unmanagedExports) - { - var ordinal = (uint)exp.ordinal; - min = Math.Min(min, ordinal); - max = Math.Max(max, ordinal); - } - - entries = 1 + (max - min); - return min; - } - - uint GetExportNamesLength(out uint nameCount) - { - nameCount = 0; - - uint length = 0; - foreach (var exp in moduleBuilder.unmanagedExports) - { - if (exp.name != null) - { - nameCount++; - length += (uint)exp.name.Length + 1; - } - } - - return length; - } - - void WriteExportDirectory(MetadataWriter mw) - { - if (ExportDirectoryLength != 0) - { - // Flags - mw.Write(0); - // Date/Time Stamp - mw.Write(peWriter.Headers.FileHeader.TimeDateStamp); - // Major Version - mw.Write((short)0); - // Minor Version - mw.Write((short)0); - // Name RVA - mw.Write(exportTables.namesRVA); - // Ordinal Base - mw.Write(exportTables.ordinalBase); - // Address Table Entries - mw.Write(exportTables.entries); - // Number of Name Pointers - mw.Write(exportTables.nameCount); - // Export Address Table RVA - mw.Write(exportTables.exportAddressTableRVA); - // Name Pointer RVA - mw.Write(exportTables.exportNamePointerTableRVA); - // Ordinal Table RVA - mw.Write(exportTables.exportOrdinalTableRVA); - } - } - - void WriteExportTables(MetadataWriter mw, uint sdataRVA) - { - exportTables?.Write(mw, sdataRVA); - } - - void WriteImportDirectory(MetadataWriter mw) - { - mw.Write(ImportDirectoryRVA + 40); // ImportLookupTable - mw.Write(0); // DateTimeStamp - mw.Write(0); // ForwarderChain - mw.Write(ImportHintNameTableRVA + 14); // Name - mw.Write(ImportAddressTableRVA); - mw.Write(new byte[20]); - // Import Lookup Table - mw.Write(ImportHintNameTableRVA); // Hint/Name Table RVA - int size = 48; - if (!peWriter.Is32Bit) - { - size += 4; - mw.Write(0); - } - mw.Write(0); - - // alignment padding - for (int i = (int)(ImportHintNameTableRVA - (ImportDirectoryRVA + size)); i > 0; i--) - mw.Write((byte)0); - - // Hint/Name Table - AssertRVA(mw, ImportHintNameTableRVA); - mw.Write((ushort)0); // Hint - if ((peWriter.Headers.FileHeader.Characteristics & IMAGE_FILE_HEADER.IMAGE_FILE_DLL) != 0) - mw.WriteAsciiz("_CorDllMain"); - else - mw.WriteAsciiz("_CorExeMain"); - - // Name - mw.WriteAsciiz("mscoree.dll"); - mw.Write((byte)0); - } - - internal int Length - { - get { return (int)(StartupStubRVA - BaseRVA + StartupStubLength); } - } - - struct Relocation : IComparable - { - - internal readonly uint rva; - internal readonly ushort type; - - /// - /// Initializes a new instance. - /// - /// - /// - internal Relocation(ushort type, uint rva) - { - this.type = type; - this.rva = rva; - } - - readonly int IComparable.CompareTo(Relocation other) => rva.CompareTo(other.rva); - - } - - struct RelocationBlock - { - - internal readonly uint PageRVA; - internal readonly ushort[] TypeOffset; - - /// - /// Initializes a new instance. - /// - /// - /// - internal RelocationBlock(uint pageRva, ushort[] typeOffset) - { - PageRVA = pageRva; - TypeOffset = typeOffset; - } - - } - - internal void WriteRelocations(MetadataWriter mw) - { - foreach (var block in relocations) - { - mw.Write(block.PageRVA); - mw.Write(8 + block.TypeOffset.Length * 2); - foreach (var typeOffset in block.TypeOffset) - mw.Write(typeOffset); - } - } - - internal uint PackRelocations() - { - var list = new List(); - switch (peWriter.Headers.FileHeader.Machine) - { - case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386: - list.Add(new Relocation(0x3000, this.StartupStubRVA + 2)); - break; - case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: - list.Add(new Relocation(0xA000, this.StartupStubRVA + 2)); - break; - case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64: - list.Add(new Relocation(0xA000, this.StartupStubRVA + 0x20)); - list.Add(new Relocation(0xA000, this.StartupStubRVA + 0x28)); - break; - case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM: - list.Add(new Relocation(0x7000, this.StartupStubRVA)); - break; - default: - throw new NotSupportedException(); - } - - exportTables?.GetRelocations(list); - - list.Sort(); - uint size = 0; - for (int i = 0; i < list.Count;) - { - uint pageRVA = list[i].rva & ~0xFFFU; - int count = 1; - while (i + count < list.Count && (list[i + count].rva & ~0xFFFU) == pageRVA) - count++; - - var typeOffset = new ushort[(count + 1) & ~1]; - for (int j = 0; j < count; j++, i++) - typeOffset[j] = (ushort)(list[i].type + (list[i].rva - pageRVA)); - - relocations.Add(new RelocationBlock(pageRVA, typeOffset)); - size += (uint)(8 + typeOffset.Length * 2); - } - - return size; - } - - } - -} +// /// +// /// Initializes a new instance. +// /// +// /// +// /// +// /// +// /// +// internal TextSection(PEWriter peWriter, CliHeader cliHeader, ModuleBuilder moduleBuilder, int strongNameSignatureLength) +// { +// this.peWriter = peWriter; +// this.cliHeader = cliHeader; +// this.moduleBuilder = moduleBuilder; +// this.strongNameSignatureLength = (uint)strongNameSignatureLength; +// this.manifestResourcesLength = (uint)moduleBuilder.GetManifestResourcesLength(); +// if (moduleBuilder.unmanagedExports.Count != 0) +// this.exportTables = new ExportTables(this); +// } + +// internal uint PointerToRawData => peWriter.ToFileAlignment(peWriter.HeaderSize); + +// internal uint BaseRVA => peWriter.Headers.OptionalHeader.SectionAlignment; + +// internal uint ImportAddressTableRVA => BaseRVA; + +// internal uint ImportAddressTableLength => peWriter.Is32Bit ? 8u : 16u; + +// internal uint ComDescriptorRVA => ImportAddressTableRVA + ImportAddressTableLength; + +// internal uint ComDescriptorLength => cliHeader.Cb; + +// internal uint MethodBodiesRVA => (ComDescriptorRVA + ComDescriptorLength + 7) & ~7U; + +// uint MethodBodiesLength => (uint)moduleBuilder.methodBodies.Length; + +// uint ResourcesRVA => peWriter.Headers.FileHeader.Machine switch +// { +// IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386 or IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM => (MethodBodiesRVA + MethodBodiesLength + 3) & ~3U, +// _ => (MethodBodiesRVA + MethodBodiesLength + 15) & ~15U, +// }; + +// uint ResourcesLength => manifestResourcesLength; + +// internal uint StrongNameSignatureRVA => (ResourcesRVA + ResourcesLength + 3) & ~3U; + +// internal uint StrongNameSignatureLength => strongNameSignatureLength; + +// uint MetadataRVA => (StrongNameSignatureRVA + StrongNameSignatureLength + 3) & ~3U; + +// //uint MetadataLength => (uint)moduleBuilder.MetadataLength; + +// //uint VTableFixupsRVA => (MetadataRVA + MetadataLength + 7) & ~7U; + +// uint VTableFixupsLength => (uint)moduleBuilder.vtablefixups.Count * 8; + +// //internal uint DebugDirectoryRVA +// //{ +// // get { return VTableFixupsRVA + VTableFixupsLength; } +// //} + +// internal uint DebugDirectoryLength => DebugDirectoryContentsLength != 0 ? 28 : (uint)0; + +// 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; +// } +// } + +// //internal uint ExportDirectoryRVA => (DebugDirectoryRVA + DebugDirectoryLength + DebugDirectoryContentsLength + 15) & ~15U; + +// internal uint ExportDirectoryLength => moduleBuilder.unmanagedExports.Count == 0 ? 0U : 40U; + +// //uint ExportTablesRVA => ExportDirectoryRVA + ExportDirectoryLength; + +// uint ExportTablesLength => exportTables == null ? 0U : exportTables.Length; + +// //internal uint ImportDirectoryRVA +// //{ +// // // on AMD64 (and probably IA64) the import directory needs to be 16 byte aligned (on I386 4 byte alignment is sufficient) +// // //get { return (ExportTablesRVA + ExportTablesLength + 15) & ~15U; } +// //} + +// //internal uint ImportDirectoryLength => (ImportHintNameTableRVA - ImportDirectoryRVA) + 27; + +// //uint ImportHintNameTableRVA => peWriter.Is32Bit +// // ? (ImportDirectoryRVA + 48 + 15) & ~15U +// // : (ImportDirectoryRVA + 52 + 15) & ~15U; + +// //internal uint StartupStubRVA +// //{ +// // get +// // { +// // if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64) +// // { +// // // note that the alignment is driven by the requirement that the two relocation fixups are in a single page +// // return (ImportDirectoryRVA + ImportDirectoryLength + 15U) & ~15U; +// // } +// // else +// // { +// // // the additional 2 bytes padding are to align the address in the jump (which is a relocation fixup) +// // return 2 + ((ImportDirectoryRVA + ImportDirectoryLength + 3U) & ~3U); +// // } +// // } +// //} + +// internal uint StartupStubLength => peWriter.Headers.FileHeader.Machine switch +// { +// IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386 => 6, +// IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64 or IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM => 12, +// IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64 => 48, +// _ => throw new NotSupportedException(), +// }; + +// sealed class ExportTables +// { + +// readonly TextSection text; +// internal readonly uint entries; +// internal readonly uint ordinalBase; +// internal readonly uint nameCount; +// internal readonly uint namesLength; +// internal readonly uint exportAddressTableRVA; +// internal readonly uint exportNamePointerTableRVA; +// internal readonly uint exportOrdinalTableRVA; +// internal readonly uint namesRVA; +// internal readonly uint stubsRVA; +// readonly uint stubLength; + +// /// +// /// Initializes a new instance. +// /// +// /// +// /// +// internal ExportTables(TextSection text) +// { +// this.text = text; +// ordinalBase = GetOrdinalBase(out entries); +// namesLength = GetExportNamesLength(out nameCount); +// exportAddressTableRVA = text.ExportTablesRVA; +// exportNamePointerTableRVA = exportAddressTableRVA + 4 * entries; +// exportOrdinalTableRVA = exportNamePointerTableRVA + 4 * nameCount; +// namesRVA = exportOrdinalTableRVA + 2 * nameCount; +// stubsRVA = (namesRVA + namesLength + 15) & ~15U; + +// // note that we align the stubs to avoid having to deal with the relocation crossing a page boundary +// stubLength = text.peWriter.Headers.FileHeader.Machine switch +// { +// IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386 => 8, +// IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64 or IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM => 16, +// _ => throw new NotSupportedException(), +// }; +// } + +// internal uint Length => stubsRVA + stubLength * (uint)text.moduleBuilder.unmanagedExports.Count - text.ExportTablesRVA; + +// uint GetOrdinalBase(out uint entries) +// { +// var min = uint.MaxValue; +// var max = uint.MinValue; +// foreach (var exp in text.moduleBuilder.unmanagedExports) +// { +// var ordinal = (uint)exp.ordinal; +// min = Math.Min(min, ordinal); +// max = Math.Max(max, ordinal); +// } + +// entries = 1 + (max - min); +// return min; +// } + +// uint GetExportNamesLength(out uint nameCount) +// { +// nameCount = 0; + +// // the first name in the names list is the module name (the Export Directory contains a name of the current module) +// var length = (uint)text.moduleBuilder.fileName.Length + 1; +// foreach (var exp in text.moduleBuilder.unmanagedExports) +// { +// if (exp.name != null) +// { +// nameCount++; +// length += (uint)exp.name.Length + 1; +// } +// } + +// return length; +// } + +// static int CompareUnmanagedExportNames(UnmanagedExport x, UnmanagedExport y) +// { +// if (x.name == null) +// return y.name == null ? 0 : 1; +// if (y.name == null) +// return -1; + +// return string.CompareOrdinal(x.name, y.name); +// } + +// static int CompareUnmanagedExportOrdinals(UnmanagedExport x, UnmanagedExport y) +// { +// return x.ordinal.CompareTo(y.ordinal); +// } + +// internal void GetRelocations(List list) +// { +// ushort type; +// uint rva; +// switch (text.peWriter.Headers.FileHeader.Machine) +// { +// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386: +// type = 0x3000; +// rva = stubsRVA + 2; +// break; +// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: +// type = 0xA000; +// rva = stubsRVA + 2; +// break; +// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM: +// type = 0x3000; +// rva = stubsRVA + 12; +// break; +// default: +// throw new NotSupportedException(); +// } + +// // we assume that unmanagedExports is still sorted by ordinal +// for (int i = 0, pos = 0; i < entries; i++) +// { +// if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase) +// { +// list.Add(new Relocation(type, rva + (uint)pos * stubLength)); +// pos++; +// } +// } +// } +// } + +// uint GetOrdinalBase(out uint entries) +// { +// var min = uint.MaxValue; +// var max = uint.MinValue; +// foreach (var exp in moduleBuilder.unmanagedExports) +// { +// var ordinal = (uint)exp.ordinal; +// min = Math.Min(min, ordinal); +// max = Math.Max(max, ordinal); +// } + +// entries = 1 + (max - min); +// return min; +// } + +// uint GetExportNamesLength(out uint nameCount) +// { +// nameCount = 0; + +// uint length = 0; +// foreach (var exp in moduleBuilder.unmanagedExports) +// { +// if (exp.name != null) +// { +// nameCount++; +// length += (uint)exp.name.Length + 1; +// } +// } + +// return length; +// } + +// internal int Length +// { +// get { return (int)(StartupStubRVA - BaseRVA + StartupStubLength); } +// } + +// struct Relocation : IComparable +// { + +// internal readonly uint rva; +// internal readonly ushort type; + +// /// +// /// Initializes a new instance. +// /// +// /// +// /// +// internal Relocation(ushort type, uint rva) +// { +// this.type = type; +// this.rva = rva; +// } + +// readonly int IComparable.CompareTo(Relocation other) => rva.CompareTo(other.rva); + +// } + +// struct RelocationBlock +// { + +// internal readonly uint PageRVA; +// internal readonly ushort[] TypeOffset; + +// /// +// /// Initializes a new instance. +// /// +// /// +// /// +// internal RelocationBlock(uint pageRva, ushort[] typeOffset) +// { +// PageRVA = pageRva; +// TypeOffset = typeOffset; +// } + +// } + +// internal uint PackRelocations() +// { +// var list = new List(); +// switch (peWriter.Headers.FileHeader.Machine) +// { +// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386: +// list.Add(new Relocation(0x3000, this.StartupStubRVA + 2)); +// break; +// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: +// list.Add(new Relocation(0xA000, this.StartupStubRVA + 2)); +// break; +// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64: +// list.Add(new Relocation(0xA000, this.StartupStubRVA + 0x20)); +// list.Add(new Relocation(0xA000, this.StartupStubRVA + 0x28)); +// break; +// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM: +// list.Add(new Relocation(0x7000, this.StartupStubRVA)); +// break; +// default: +// throw new NotSupportedException(); +// } + +// exportTables?.GetRelocations(list); + +// list.Sort(); +// uint size = 0; +// for (int i = 0; i < list.Count;) +// { +// uint pageRVA = list[i].rva & ~0xFFFU; +// int count = 1; +// while (i + count < list.Count && (list[i + count].rva & ~0xFFFU) == pageRVA) +// count++; + +// var typeOffset = new ushort[(count + 1) & ~1]; +// for (int j = 0; j < count; j++, i++) +// typeOffset[j] = (ushort)(list[i].type + (list[i].rva - pageRVA)); + +// relocations.Add(new RelocationBlock(pageRVA, typeOffset)); +// size += (uint)(8 + typeOffset.Length * 2); +// } + +// return size; +// } + +// } + +//} diff --git a/src/IKVM.Reflection/Writer/UserStringHeap.cs b/src/IKVM.Reflection/Writer/UserStringHeap.cs deleted file mode 100644 index 78ba77bc8d..0000000000 --- a/src/IKVM.Reflection/Writer/UserStringHeap.cs +++ /dev/null @@ -1,89 +0,0 @@ -/* - Copyright (C) 2008 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.Collections.Generic; -using System.Diagnostics; - -namespace IKVM.Reflection.Writer -{ - - sealed class UserStringHeap : SimpleHeap - { - - readonly List list = new List(); - readonly Dictionary strings = new Dictionary(); - int nextOffset; - - /// - /// Initializes a new instance. - /// - internal UserStringHeap() - { - nextOffset = 1; - } - - internal bool IsEmpty => nextOffset == 1; - - internal int Add(string str) - { - Debug.Assert(frozen == false); - - if (strings.TryGetValue(str, out var offset) == false) - { - int length = str.Length * 2 + 1 + MetadataWriter.GetCompressedUIntLength(str.Length * 2 + 1); - if (nextOffset + length > 0xFFFFFF) - throw new FileFormatLimitationExceededException("No logical space left to create more user strings.", FileFormatLimitationExceededException.META_E_STRINGSPACE_FULL); - - offset = nextOffset; - nextOffset += length; - list.Add(str); - strings.Add(str, offset); - } - - return offset; - } - - protected override int GetLength() => nextOffset; - - protected override void WriteImpl(MetadataWriter mw) - { - mw.Write((byte)0); - foreach (var str in list) - { - mw.WriteCompressedUInt(str.Length * 2 + 1); - byte hasSpecialChars = 0; - foreach (var ch in str) - { - mw.Write((ushort)ch); - if (hasSpecialChars == 0 && (ch < 0x20 || ch > 0x7E)) - if (ch > 0x7E || (ch >= 0x01 && ch <= 0x08) || (ch >= 0x0E && ch <= 0x1F) || ch == 0x27 || ch == 0x2D) - hasSpecialChars = 1; - } - - mw.Write(hasSpecialChars); - } - } - - } - -} From 55abde14f725dfe096f23c67aa73c7cb94bb05cd Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sat, 13 Jan 2024 13:35:43 -0600 Subject: [PATCH 04/10] Much fixes. --- IKVM.sln | 6 + .../IKVM.Java.Tests.Util.csproj | 14 ++ .../InMemoryCodeUnit.cs | 2 +- .../InMemoryCompiler.cs | 2 +- src/IKVM.Reflection.Tests/FrameworkSpec.cs | 28 +++ .../IKVM.Reflection.Tests.csproj | 8 + .../ModuleReaderTests.cs | 86 +++++++ .../ModuleWriterTests.cs | 231 +++++++++++++++--- .../TestAssemblyResolver.cs | 67 +++++ .../Emit/GenericTypeParameterBuilder.cs | 4 +- src/IKVM.Reflection/Emit/ILGenerator.cs | 2 +- src/IKVM.Reflection/Metadata/ConstantTable.cs | 15 +- .../Metadata/CustomAttributeTable.cs | 55 ++--- src/IKVM.Reflection/Metadata/EventMapTable.cs | 4 - .../Metadata/FieldLayoutTable.cs | 4 - src/IKVM.Reflection/Metadata/FieldRVATable.cs | 4 - .../Metadata/GenericParamConstraintTable.cs | 7 +- .../Metadata/GenericParamTable.cs | 23 +- .../Metadata/InterfaceImplTable.cs | 43 ++-- .../Metadata/MethodSemanticsTable.cs | 27 +- src/IKVM.Reflection/Metadata/SortedTable.cs | 3 +- src/IKVM.Reflection/Universe.cs | 7 +- src/IKVM.Tests.Util/DotNetSdkUtil.cs | 20 +- src/IKVM.Tests.Util/IKVM.Tests.Util.csproj | 3 - 24 files changed, 500 insertions(+), 165 deletions(-) create mode 100644 src/IKVM.Java.Tests.Util/IKVM.Java.Tests.Util.csproj rename src/{IKVM.Tests.Util => IKVM.Java.Tests.Util}/InMemoryCodeUnit.cs (96%) rename src/{IKVM.Tests.Util => IKVM.Java.Tests.Util}/InMemoryCompiler.cs (99%) create mode 100644 src/IKVM.Reflection.Tests/FrameworkSpec.cs create mode 100644 src/IKVM.Reflection.Tests/ModuleReaderTests.cs create mode 100644 src/IKVM.Reflection.Tests/TestAssemblyResolver.cs diff --git a/IKVM.sln b/IKVM.sln index ea5ffb12bf..b47c0d7d72 100644 --- a/IKVM.sln +++ b/IKVM.sln @@ -325,6 +325,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IKVM.Image.runtime.win-arm6 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IKVM.Reflection.Tests", "src\IKVM.Reflection.Tests\IKVM.Reflection.Tests.csproj", "{17755A44-22EC-4D28-B219-3C5CAE6317C8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IKVM.Java.Tests.Util", "src\IKVM.Java.Tests.Util\IKVM.Java.Tests.Util.csproj", "{00AFE142-5F4F-48DD-90C1-20CC0512C43C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -803,6 +805,10 @@ Global {17755A44-22EC-4D28-B219-3C5CAE6317C8}.Debug|Any CPU.Build.0 = Debug|Any CPU {17755A44-22EC-4D28-B219-3C5CAE6317C8}.Release|Any CPU.ActiveCfg = Release|Any CPU {17755A44-22EC-4D28-B219-3C5CAE6317C8}.Release|Any CPU.Build.0 = Release|Any CPU + {00AFE142-5F4F-48DD-90C1-20CC0512C43C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00AFE142-5F4F-48DD-90C1-20CC0512C43C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00AFE142-5F4F-48DD-90C1-20CC0512C43C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00AFE142-5F4F-48DD-90C1-20CC0512C43C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/IKVM.Java.Tests.Util/IKVM.Java.Tests.Util.csproj b/src/IKVM.Java.Tests.Util/IKVM.Java.Tests.Util.csproj new file mode 100644 index 0000000000..284ecbb6c6 --- /dev/null +++ b/src/IKVM.Java.Tests.Util/IKVM.Java.Tests.Util.csproj @@ -0,0 +1,14 @@ + + + net472;net6.0;net7.0 + + + + + + + + + + + diff --git a/src/IKVM.Tests.Util/InMemoryCodeUnit.cs b/src/IKVM.Java.Tests.Util/InMemoryCodeUnit.cs similarity index 96% rename from src/IKVM.Tests.Util/InMemoryCodeUnit.cs rename to src/IKVM.Java.Tests.Util/InMemoryCodeUnit.cs index c0d7b9588e..dc687bca87 100644 --- a/src/IKVM.Tests.Util/InMemoryCodeUnit.cs +++ b/src/IKVM.Java.Tests.Util/InMemoryCodeUnit.cs @@ -1,6 +1,6 @@ using System; -namespace IKVM.Tests.Util +namespace IKVM.Java.Tests.Util { /// /// Represents a unit of code to compile. diff --git a/src/IKVM.Tests.Util/InMemoryCompiler.cs b/src/IKVM.Java.Tests.Util/InMemoryCompiler.cs similarity index 99% rename from src/IKVM.Tests.Util/InMemoryCompiler.cs rename to src/IKVM.Java.Tests.Util/InMemoryCompiler.cs index f1d3d2d106..c9b14f4a2d 100644 --- a/src/IKVM.Tests.Util/InMemoryCompiler.cs +++ b/src/IKVM.Java.Tests.Util/InMemoryCompiler.cs @@ -8,7 +8,7 @@ using javax.tools; -namespace IKVM.Tests.Util +namespace IKVM.Java.Tests.Util { /// diff --git a/src/IKVM.Reflection.Tests/FrameworkSpec.cs b/src/IKVM.Reflection.Tests/FrameworkSpec.cs new file mode 100644 index 0000000000..77eb1e004e --- /dev/null +++ b/src/IKVM.Reflection.Tests/FrameworkSpec.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace IKVM.Reflection.Tests +{ + + /// + /// + /// + /// + /// + /// + public record struct FrameworkSpec(string Tfm, string TargetFrameworkIdentifier, string TargetFrameworkVersion) + { + + /// + /// Individual Frameworks to test. + /// + public static IEnumerable GetFrameworkTestData() + { + yield return new object[] { new FrameworkSpec("net472", ".NETFramework", "4.7.2") }; + yield return new object[] { new FrameworkSpec("net48", ".NETFramework", "4.8") }; + yield return new object[] { new FrameworkSpec("net6.0", ".NETCore", "6.0") }; + yield return new object[] { new FrameworkSpec("net7.0", ".NETCore", "7.0") }; + } + + } + +} diff --git a/src/IKVM.Reflection.Tests/IKVM.Reflection.Tests.csproj b/src/IKVM.Reflection.Tests/IKVM.Reflection.Tests.csproj index 8daa814601..32e0cd3fd2 100644 --- a/src/IKVM.Reflection.Tests/IKVM.Reflection.Tests.csproj +++ b/src/IKVM.Reflection.Tests/IKVM.Reflection.Tests.csproj @@ -6,13 +6,21 @@ + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + \ No newline at end of file diff --git a/src/IKVM.Reflection.Tests/ModuleReaderTests.cs b/src/IKVM.Reflection.Tests/ModuleReaderTests.cs new file mode 100644 index 0000000000..4d675d34b5 --- /dev/null +++ b/src/IKVM.Reflection.Tests/ModuleReaderTests.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; + +using FluentAssertions; + +using IKVM.Tests.Util; + +using Xunit; + +namespace IKVM.Reflection.Tests +{ + public class ModuleReaderTests + { + + /// + /// Initializes the variables requires to execute tests. + /// + /// + /// + bool Init(FrameworkSpec framework, out Universe universe, out TestAssemblyResolver resolver) + { + universe = null; + resolver = null; + + // no reference assemblies for NetFX on Unix + if (framework.TargetFrameworkIdentifier == ".NETFramework") + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) == false) + return false; + + // initialize primary classes + universe = new Universe(DotNetSdkUtil.GetCoreLibName(framework.Tfm, framework.TargetFrameworkIdentifier, framework.TargetFrameworkVersion)); + resolver = new TestAssemblyResolver(universe, framework.Tfm, framework.TargetFrameworkIdentifier, framework.TargetFrameworkVersion); + + return true; + } + + [Theory] + [MemberData(nameof(FrameworkSpec.GetFrameworkTestData), MemberType = typeof(FrameworkSpec))] + public void CanMakeGenericType(FrameworkSpec framework) + { + if (Init(framework, out var universe, out var resolver) == false) + return; + + var t = universe.Import(typeof(IEnumerable<>)); + t.IsGenericType.Should().BeTrue(); + t.IsGenericTypeDefinition.Should().BeTrue(); + t.IsConstructedGenericType.Should().BeFalse(); + var g = t.MakeGenericType(universe.Import(typeof(object))); + g.IsGenericTypeDefinition.Should().BeFalse(); + g.IsConstructedGenericType.Should().BeTrue(); + } + + [Theory] + [MemberData(nameof(FrameworkSpec.GetFrameworkTestData), MemberType = typeof(FrameworkSpec))] + public void CanGetGenericPropertyOfGenericType(FrameworkSpec framework) + { + if (Init(framework, out var universe, out var resolver) == false) + return; + + // simple generic with a single property + var nullableType = universe.Import(typeof(Nullable<>)); + nullableType.IsGenericType.Should().BeTrue(); + nullableType.IsGenericTypeDefinition.Should().BeTrue(); + nullableType.IsConstructedGenericType.Should().BeFalse(); + nullableType.GetGenericArguments().Should().HaveCount(1); + nullableType.GetGenericArguments()[0].Should().NotBeNull(); + + // make generic instance + var nullableOfObjectType = nullableType.MakeGenericType(universe.Import(typeof(object))); + nullableOfObjectType.IsGenericTypeDefinition.Should().BeFalse(); + nullableOfObjectType.IsConstructedGenericType.Should().BeTrue(); + + // check for expected property + var valueProperty = nullableOfObjectType.GetProperty("Value"); + valueProperty.PropertyType.Should().Be(universe.Import(typeof(object))); + var valueGetter = valueProperty.GetGetMethod(); + valueGetter.ReturnType.Should().Be(universe.Import(typeof(object))); + valueGetter.GetParameters().Should().BeEmpty(); + } + + } + +} diff --git a/src/IKVM.Reflection.Tests/ModuleWriterTests.cs b/src/IKVM.Reflection.Tests/ModuleWriterTests.cs index d66d3b7da7..8262c1b60b 100644 --- a/src/IKVM.Reflection.Tests/ModuleWriterTests.cs +++ b/src/IKVM.Reflection.Tests/ModuleWriterTests.cs @@ -1,60 +1,213 @@ -using System.IO; +using System; +using System.IO; +using System.Reflection; +using System.Reflection.PortableExecutable; +using System.Runtime.InteropServices; + +using FluentAssertions; using IKVM.Reflection.Emit; +using IKVM.Tests.Util; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Xunit; +using Xunit.Abstractions; namespace IKVM.Reflection.Tests { - [TestClass] - public class ModuleWriterTests + public partial class ModuleWriterTests { - public TestContext TestContext { get; set; } + /// + /// Provides resolution for ILVerify. + /// + class VerifyResolver : ILVerify.IResolver + { + + readonly TestAssemblyResolver resolver; + + /// + /// Initializes a new instance. + /// + /// + public VerifyResolver(TestAssemblyResolver resolver) + { + this.resolver = resolver ?? throw new ArgumentNullException(nameof(resolver)); + } + + public PEReader ResolveAssembly(System.Reflection.AssemblyName assemblyName) + { + return resolver.Resolve(assemblyName.Name) is string s ? new PEReader(File.OpenRead(s)) : null; + } + + public PEReader ResolveModule(System.Reflection.AssemblyName referencingAssembly, string fileName) + { + return resolver.Resolve(fileName) is string s ? new PEReader(File.OpenRead(s)) : null; + } + + } + + class MetadataAssemblyResolver : System.Reflection.MetadataAssemblyResolver + { + + readonly TestAssemblyResolver resolver; + + /// + /// Initializes a new instance. + /// + /// + /// + public MetadataAssemblyResolver(TestAssemblyResolver resolver) + { + this.resolver = resolver ?? throw new ArgumentNullException(nameof(resolver)); + } + + public override System.Reflection.Assembly Resolve(MetadataLoadContext context, System.Reflection.AssemblyName assemblyName) + { + return resolver.Resolve(assemblyName.Name) is string s ? context.LoadFromAssemblyPath(s) : null; + } + + } + + readonly ITestOutputHelper output; + + /// + /// Initializes a new instance. + /// + /// + public ModuleWriterTests(ITestOutputHelper output) + { + this.output = output ?? throw new ArgumentNullException(nameof(output)); + } - [TestMethod] - public void CanWriteNetFxModule() + /// + /// Initializes the variables requires to execute tests. + /// + /// + /// + /// + /// + bool Init(FrameworkSpec framework, out Universe universe, out TestAssemblyResolver resolver, out ILVerify.Verifier verifier, out string tempPath, out MetadataLoadContext tempLoad) { - var d = Path.Combine(Path.GetTempPath(), "IKVM.Reflection.Tests", "ModuleWriterTests"); - if (Directory.Exists(d)) - Directory.Delete(d, true); - Directory.CreateDirectory(d); - - var u = new Universe("mscorlib"); - u.AssemblyResolve += U_AssemblyResolve; - var a = u.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save, d); - var m = a.DefineDynamicModule("Test", "Test.dll", false); - var t = m.DefineType("Type"); - var z = t.DefineMethod("Exec", MethodAttributes.Public, u.Import(typeof(object)), new[] { u.Import(typeof(string[])) }); - z.DefineParameter(0, ParameterAttributes.None, "args"); - a.Save("Test.dll"); - TestContext.WriteLine(d); + universe = null; + resolver = null; + verifier = null; + tempPath = null; + tempLoad = null; + + // no reference assemblies for NetFX on Unix + if (framework.TargetFrameworkIdentifier == ".NETFramework") + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) == false) + return false; + + // set up temporary directory + tempPath = Path.Combine(Path.GetTempPath(), typeof(ModuleWriterTests).Namespace, typeof(ModuleWriterTests).Name, Guid.NewGuid().ToString()); + if (Directory.Exists(tempPath)) + Directory.Delete(tempPath, true); + Directory.CreateDirectory(tempPath); + output.WriteLine("TempPath: {0}", tempPath); + + // initialize primary classes + universe = new Universe(DotNetSdkUtil.GetCoreLibName(framework.Tfm, framework.TargetFrameworkIdentifier, framework.TargetFrameworkVersion)); + resolver = new TestAssemblyResolver(universe, framework.Tfm, framework.TargetFrameworkIdentifier, framework.TargetFrameworkVersion); + verifier = new ILVerify.Verifier(new VerifyResolver(resolver), new ILVerify.VerifierOptions() { SanityChecks = true }); + verifier.SetSystemModuleName(new System.Reflection.AssemblyName(universe.CoreLibName)); + tempLoad = new MetadataLoadContext(new MetadataAssemblyResolver(resolver)); + + return true; } - Assembly U_AssemblyResolve(object sender, ResolveEventArgs args) + [Theory] + [MemberData(nameof(FrameworkSpec.GetFrameworkTestData), MemberType = typeof(FrameworkSpec))] + public void CanWriteModule(FrameworkSpec framework) { - var d = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8.1"; - var p = Path.Combine(d, args.Name + ".dll"); - if (File.Exists(p)) - return ((Universe)sender).LoadFile(p); + if (Init(framework, out var universe, out var resolver, out var verifier, out var tempPath, out var tempLoad) == false) + return; + + var assembly = universe.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save, tempPath); + var module = assembly.DefineDynamicModule("Test", "Test.dll", false); + var type = module.DefineType("Type"); + + var valueField = type.DefineField("value", universe.Import(typeof(object)), FieldAttributes.Private); + + var getValueMethod = type.DefineMethod("get_Value", MethodAttributes.Public, universe.Import(typeof(object)), Array.Empty()); + var getValueIL = getValueMethod.GetILGenerator(); + getValueIL.Emit(OpCodes.Ldarg_0); + getValueIL.Emit(OpCodes.Ldfld, valueField); + getValueIL.Emit(OpCodes.Ret); + + var setValueMethod = type.DefineMethod("set_Value", MethodAttributes.Public, universe.Import(typeof(void)), new[] { universe.Import(typeof(object)) }); + var setValueIL = setValueMethod.GetILGenerator(); + setValueIL.Emit(OpCodes.Ldarg_0); + setValueIL.Emit(OpCodes.Ldarg_1); + setValueIL.Emit(OpCodes.Stfld, valueField); + setValueIL.Emit(OpCodes.Ret); + + var valueProperty = type.DefineProperty("Value", PropertyAttributes.None, universe.Import(typeof(object)), Array.Empty()); + valueProperty.SetGetMethod(getValueMethod); + valueProperty.SetSetMethod(setValueMethod); + + var execMethod = type.DefineMethod("Exec", MethodAttributes.Public, universe.Import(typeof(object)), new[] { universe.Import(typeof(string[])) }); + execMethod.DefineParameter(0, ParameterAttributes.None, "args"); + var execMethodIL = execMethod.GetILGenerator(); + execMethodIL.Emit(OpCodes.Ldnull); + execMethodIL.Emit(OpCodes.Ret); - return null; + type.CreateType(); + assembly.Save("Test.dll"); + + foreach (var v in verifier.Verify(new PEReader(File.OpenRead(Path.Combine(tempPath, "Test.dll"))))) + v.Code.Should().Be(ILVerify.VerifierError.None); + + var a = tempLoad.LoadFromAssemblyPath(Path.Combine(tempPath, "Test.dll")); + a.GetName().Name.Should().Be("Test"); + a.GetModule("Test").Should().NotBeNull(); + var t = a.GetType("Type"); + t.Should().NotBeNull(); + t.Should().NotBeStatic(); + t.Should().HaveMethod("Exec", new[] { tempLoad.CoreAssembly.GetType("System.String").MakeArrayType() }).Which.Should().Return(tempLoad.CoreAssembly.GetType("System.Object")); + t.Should().HaveProperty(tempLoad.CoreAssembly.GetType("System.Object"), "Value"); } - [TestMethod] - public void CanWriteNetCoreModule() + [Theory] + [MemberData(nameof(FrameworkSpec.GetFrameworkTestData), MemberType = typeof(FrameworkSpec))] + public void CanWriteInterfaceImplementation(FrameworkSpec framework) { - var d = Path.Combine(TestContext.TestRunResultsDirectory, "IKVM.Reflection.Tests", "ModuleWriterTests"); - if (Directory.Exists(d)) - Directory.Delete(d, true); - Directory.CreateDirectory(d); - - var u = new Universe("System.Runtime"); - var a = u.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save, d); - var m = a.DefineDynamicModule("Test", "Test.dll", false); - m.DefineType("Type"); - a.Save("Test.dll"); + if (Init(framework, out var universe, out var resolver, out var verifier, out var tempPath, out var tempLoad) == false) + return; + + var assembly = universe.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save, tempPath); + var module = assembly.DefineDynamicModule("Test", "Test.dll", false); + + var ifaceBuilder = module.DefineType("Iface", TypeAttributes.Interface); + var ifaceMethod = ifaceBuilder.DefineMethod("Method", MethodAttributes.Abstract, universe.Import(typeof(object)), Array.Empty()); + + var implType = module.DefineType("Impl", TypeAttributes.Public, null, new[] { ifaceBuilder }); + var implMethod = implType.DefineMethod("Method", MethodAttributes.Public, universe.Import(typeof(object)), Array.Empty()); + implType.DefineMethodOverride(ifaceMethod, implMethod); + + var il = implMethod.GetILGenerator(); + il.Emit(OpCodes.Ldnull); + il.Emit(OpCodes.Ret); + + ifaceBuilder.CreateType(); + implType.CreateType(); + assembly.Save("Test.dll"); + + foreach (var v in verifier.Verify(new PEReader(File.OpenRead(Path.Combine(tempPath, "Test.dll"))))) + v.Code.Should().Be(ILVerify.VerifierError.None); + + var a = tempLoad.LoadFromAssemblyPath(Path.Combine(tempPath, "Test.dll")); + var i = a.GetType("Iface"); + i.IsInterface.Should().BeTrue(); + i.Should().HaveMethod("Method", Array.Empty()); + var t = a.GetType("Impl"); + t.IsInterface.Should().BeFalse(); + t.IsClass.Should().BeTrue(); + var m = t.GetMethod("Method"); + m.Should().NotBeNull(); + m.Should().Return(tempLoad.CoreAssembly.GetType("System.Object")); } } diff --git a/src/IKVM.Reflection.Tests/TestAssemblyResolver.cs b/src/IKVM.Reflection.Tests/TestAssemblyResolver.cs new file mode 100644 index 0000000000..795a718f07 --- /dev/null +++ b/src/IKVM.Reflection.Tests/TestAssemblyResolver.cs @@ -0,0 +1,67 @@ +using System; +using System.IO; + +using IKVM.Tests.Util; + +namespace IKVM.Reflection.Tests +{ + + /// + /// Basic assembly resolver. + /// + class TestAssemblyResolver + { + + readonly Universe universe; + readonly string tfm; + readonly string targetFrameworkIdentifier; + readonly string targetFrameworkVersion; + + /// + /// Initializes a new instance. + /// + /// + /// + /// + /// + /// + public TestAssemblyResolver(Universe universe, string tfm, string targetFrameworkIdentifier, string targetFrameworkVersion) + { + this.universe = universe ?? throw new ArgumentNullException(nameof(universe)); + this.tfm = tfm ?? throw new ArgumentNullException(nameof(tfm)); + this.targetFrameworkIdentifier = targetFrameworkIdentifier ?? throw new ArgumentNullException(nameof(targetFrameworkIdentifier)); + this.targetFrameworkVersion = targetFrameworkVersion ?? throw new ArgumentNullException(nameof(targetFrameworkVersion)); + + universe.AssemblyResolve += (s, a) => UniverseAssemblyResolve(a.Name); + } + + /// + /// Attempts to resolve the named assembly. + /// + /// + /// + public string Resolve(string name) + { + foreach (var d in DotNetSdkUtil.GetPathToReferenceAssemblies(tfm, targetFrameworkIdentifier, targetFrameworkVersion)) + { + var p = Path.GetExtension(name) == ".dll" ? Path.Combine(d, name) : Path.Combine(d, name + ".dll"); + if (File.Exists(p)) + return p; + } + + return null; + } + + /// + /// Resolves and loads an assembly. + /// + /// + /// + public Assembly UniverseAssemblyResolve(string name) + { + return Resolve(name) is string s ? universe.LoadFile(s) : null; + } + + } + +} diff --git a/src/IKVM.Reflection/Emit/GenericTypeParameterBuilder.cs b/src/IKVM.Reflection/Emit/GenericTypeParameterBuilder.cs index 918f8163a7..d722e87495 100644 --- a/src/IKVM.Reflection/Emit/GenericTypeParameterBuilder.cs +++ b/src/IKVM.Reflection/Emit/GenericTypeParameterBuilder.cs @@ -263,9 +263,9 @@ internal override Type BindTypeParameters(IGenericBinder binder) internal override int GetCurrentToken() { - if (this.ModuleBuilder.IsSaved) + if (ModuleBuilder.IsSaved) { - return (GenericParamTable.Index << 24) | this.Module.GenericParam.GetIndexFixup()[paramPseudoIndex - 1] + 1; + return (GenericParamTable.Index << 24) | Module.GenericParam.GetIndexFixup()[paramPseudoIndex - 1] + 1; } else { diff --git a/src/IKVM.Reflection/Emit/ILGenerator.cs b/src/IKVM.Reflection/Emit/ILGenerator.cs index 5985f7c7f4..b4e6c2dcf1 100644 --- a/src/IKVM.Reflection/Emit/ILGenerator.cs +++ b/src/IKVM.Reflection/Emit/ILGenerator.cs @@ -385,7 +385,7 @@ public void Emit(OpCode opc) if (opc.Value < 0) code.Write((byte)(opc.Value >> 8)); - code.Write((byte)opc.Value); + code.Write((byte)opc.Value); switch (opc.FlowControl) { case FlowControl.Branch: diff --git a/src/IKVM.Reflection/Metadata/ConstantTable.cs b/src/IKVM.Reflection/Metadata/ConstantTable.cs index cf98fc8b4e..8470214585 100644 --- a/src/IKVM.Reflection/Metadata/ConstantTable.cs +++ b/src/IKVM.Reflection/Metadata/ConstantTable.cs @@ -83,16 +83,13 @@ internal void Fixup(ModuleBuilder moduleBuilder) Sort(); } - internal static int EncodeHasConstant(int token) + internal static int EncodeHasConstant(int token) => (token >> 24) switch { - return (token >> 24) switch - { - FieldTable.Index => (token & 0xFFFFFF) << 2 | 0, - ParamTable.Index => (token & 0xFFFFFF) << 2 | 1, - PropertyTable.Index => (token & 0xFFFFFF) << 2 | 2, - _ => throw new InvalidOperationException(), - }; - } + FieldTable.Index => (token & 0xFFFFFF) << 2 | 0, + ParamTable.Index => (token & 0xFFFFFF) << 2 | 1, + PropertyTable.Index => (token & 0xFFFFFF) << 2 | 2, + _ => throw new InvalidOperationException(), + }; internal object GetRawConstantValue(Module module, int parent) { diff --git a/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs b/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs index 1239e20215..313e186ee1 100644 --- a/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs +++ b/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs @@ -90,36 +90,33 @@ internal void Fixup(ModuleBuilder moduleBuilder) Sort(); } - internal static int EncodeHasCustomAttribute(int token) + internal static int EncodeHasCustomAttribute(int token) => (token >> 24) switch { - return (token >> 24) switch - { - MethodDefTable.Index => (token & 0xFFFFFF) << 5 | 0, - FieldTable.Index => (token & 0xFFFFFF) << 5 | 1, - TypeRefTable.Index => (token & 0xFFFFFF) << 5 | 2, - TypeDefTable.Index => (token & 0xFFFFFF) << 5 | 3, - ParamTable.Index => (token & 0xFFFFFF) << 5 | 4, - InterfaceImplTable.Index => (token & 0xFFFFFF) << 5 | 5, - MemberRefTable.Index => (token & 0xFFFFFF) << 5 | 6, - ModuleTable.Index => (token & 0xFFFFFF) << 5 | 7, - // LAMESPEC spec calls this Permission table - DeclSecurityTable.Index => throw new NotImplementedException(), //return (token & 0xFFFFFF) << 5 | 8; - PropertyTable.Index => (token & 0xFFFFFF) << 5 | 9, - EventTable.Index => (token & 0xFFFFFF) << 5 | 10, - StandAloneSigTable.Index => (token & 0xFFFFFF) << 5 | 11, - ModuleRefTable.Index => (token & 0xFFFFFF) << 5 | 12, - TypeSpecTable.Index => (token & 0xFFFFFF) << 5 | 13, - AssemblyTable.Index => (token & 0xFFFFFF) << 5 | 14, - AssemblyRefTable.Index => (token & 0xFFFFFF) << 5 | 15, - FileTable.Index => (token & 0xFFFFFF) << 5 | 16, - ExportedTypeTable.Index => (token & 0xFFFFFF) << 5 | 17, - ManifestResourceTable.Index => (token & 0xFFFFFF) << 5 | 18, - GenericParamTable.Index => (token & 0xFFFFFF) << 5 | 19, - GenericParamConstraintTable.Index => throw new NotImplementedException(), //return (token & 0xFFFFFF) << 5 | 20; - MethodSpecTable.Index => (token & 0xFFFFFF) << 5 | 21, - _ => throw new InvalidOperationException(), - }; - } + MethodDefTable.Index => (token & 0xFFFFFF) << 5 | 0, + FieldTable.Index => (token & 0xFFFFFF) << 5 | 1, + TypeRefTable.Index => (token & 0xFFFFFF) << 5 | 2, + TypeDefTable.Index => (token & 0xFFFFFF) << 5 | 3, + ParamTable.Index => (token & 0xFFFFFF) << 5 | 4, + InterfaceImplTable.Index => (token & 0xFFFFFF) << 5 | 5, + MemberRefTable.Index => (token & 0xFFFFFF) << 5 | 6, + ModuleTable.Index => (token & 0xFFFFFF) << 5 | 7, + // LAMESPEC spec calls this Permission table + DeclSecurityTable.Index => throw new NotImplementedException(), //return (token & 0xFFFFFF) << 5 | 8; + PropertyTable.Index => (token & 0xFFFFFF) << 5 | 9, + EventTable.Index => (token & 0xFFFFFF) << 5 | 10, + StandAloneSigTable.Index => (token & 0xFFFFFF) << 5 | 11, + ModuleRefTable.Index => (token & 0xFFFFFF) << 5 | 12, + TypeSpecTable.Index => (token & 0xFFFFFF) << 5 | 13, + AssemblyTable.Index => (token & 0xFFFFFF) << 5 | 14, + AssemblyRefTable.Index => (token & 0xFFFFFF) << 5 | 15, + FileTable.Index => (token & 0xFFFFFF) << 5 | 16, + ExportedTypeTable.Index => (token & 0xFFFFFF) << 5 | 17, + ManifestResourceTable.Index => (token & 0xFFFFFF) << 5 | 18, + GenericParamTable.Index => (token & 0xFFFFFF) << 5 | 19, + GenericParamConstraintTable.Index => throw new NotImplementedException(), //return (token & 0xFFFFFF) << 5 | 20; + MethodSpecTable.Index => (token & 0xFFFFFF) << 5 | 21, + _ => throw new InvalidOperationException(), + }; } diff --git a/src/IKVM.Reflection/Metadata/EventMapTable.cs b/src/IKVM.Reflection/Metadata/EventMapTable.cs index 8058fb3db8..45d99d0252 100644 --- a/src/IKVM.Reflection/Metadata/EventMapTable.cs +++ b/src/IKVM.Reflection/Metadata/EventMapTable.cs @@ -21,11 +21,7 @@ Jeroen Frijters jeroen@frijters.net */ -using System.Reflection.Metadata.Ecma335; - using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { diff --git a/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs b/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs index 7391747ff8..cd4e3a8a44 100644 --- a/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs +++ b/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs @@ -21,11 +21,7 @@ Jeroen Frijters jeroen@frijters.net */ -using System.Reflection.Metadata.Ecma335; - using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { diff --git a/src/IKVM.Reflection/Metadata/FieldRVATable.cs b/src/IKVM.Reflection/Metadata/FieldRVATable.cs index 6f5642ff99..fed37d7b56 100644 --- a/src/IKVM.Reflection/Metadata/FieldRVATable.cs +++ b/src/IKVM.Reflection/Metadata/FieldRVATable.cs @@ -21,11 +21,7 @@ Jeroen Frijters jeroen@frijters.net */ -using System.Reflection.Metadata.Ecma335; - using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { diff --git a/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs b/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs index 41601ac069..9cc2379d87 100644 --- a/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs +++ b/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs @@ -25,7 +25,6 @@ Jeroen Frijters using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; namespace IKVM.Reflection.Metadata { @@ -60,10 +59,10 @@ internal override void Write(ModuleBuilder module) for (int i = 0; i < rowCount; i++) { var h = module.Metadata.AddGenericParameterConstraint( - System.Reflection.Metadata.Ecma335.MetadataTokens.GenericParameterHandle(records[i].Owner), - System.Reflection.Metadata.Ecma335.MetadataTokens.EntityHandle(records[i].Constraint)); + MetadataTokens.GenericParameterHandle(records[i].Owner), + MetadataTokens.EntityHandle(records[i].Constraint)); - Debug.Assert(h == System.Reflection.Metadata.Ecma335.MetadataTokens.GenericParameterConstraintHandle(i + 1)); + Debug.Assert(h == MetadataTokens.GenericParameterConstraintHandle(i + 1)); } } diff --git a/src/IKVM.Reflection/Metadata/GenericParamTable.cs b/src/IKVM.Reflection/Metadata/GenericParamTable.cs index 422574d85c..281d308f0e 100644 --- a/src/IKVM.Reflection/Metadata/GenericParamTable.cs +++ b/src/IKVM.Reflection/Metadata/GenericParamTable.cs @@ -46,7 +46,7 @@ internal struct Record : IRecord // not part of the table, we use it to be able to fixup the GenericParamConstraint table internal int unsortedIndex; - readonly int IRecord.SortKey => Owner; + readonly int IRecord.SortKey => EncodeOwner(Owner); readonly int IRecord.FilterKey => Owner; @@ -83,23 +83,20 @@ internal void Fixup(ModuleBuilder moduleBuilder) { for (int i = 0; i < rowCount; i++) { - int token = records[i].Owner; - moduleBuilder.FixupPseudoToken(ref token); - - // do the TypeOrMethodDef encoding, so that we can sort the table - records[i].Owner = (token >> 24) switch - { - TypeDefTable.Index => (token & 0xFFFFFF) << 1 | 0, - MethodDefTable.Index => (token & 0xFFFFFF) << 1 | 1, - _ => throw new InvalidOperationException(), - }; - + moduleBuilder.FixupPseudoToken(ref records[i].Owner); records[i].unsortedIndex = i; } - Array.Sort(records, 0, rowCount, this); + Sort(); } + internal static int EncodeOwner(int token) => (token >> 24) switch + { + TypeDefTable.Index => (token & 0xFFFFFF) << 1 | 0, + MethodDefTable.Index => (token & 0xFFFFFF) << 1 | 1, + _ => throw new InvalidOperationException(), + }; + int IComparer.Compare(Record x, Record y) { if (x.Owner == y.Owner) diff --git a/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs b/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs index b66bfbc4d5..b2d18a89ec 100644 --- a/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs +++ b/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs @@ -26,7 +26,6 @@ Jeroen Frijters using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; namespace IKVM.Reflection.Metadata { @@ -40,9 +39,9 @@ internal struct Record : IRecord internal int Class; internal int Interface; - int IRecord.SortKey => Class; + readonly int IRecord.SortKey => EncodeOwner(Class); - int IRecord.FilterKey => Class; + readonly int IRecord.FilterKey => Class; } internal const int Index = (int)TableIndex.InterfaceImpl; @@ -61,38 +60,24 @@ internal override void Write(ModuleBuilder module) for (int i = 0; i < rowCount; i++) { var h = module.Metadata.AddInterfaceImplementation( - System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].Class), - System.Reflection.Metadata.Ecma335.MetadataTokens.EntityHandle(records[i].Interface)); + MetadataTokens.TypeDefinitionHandle(records[i].Class), + MetadataTokens.EntityHandle(records[i].Interface)); - Debug.Assert(h == System.Reflection.Metadata.Ecma335.MetadataTokens.InterfaceImplementationHandle(i + 1)); + Debug.Assert(h == MetadataTokens.InterfaceImplementationHandle(i + 1)); } } - internal void Fixup() + internal static int EncodeOwner(int token) => (token >> 24) switch { - for (int i = 0; i < rowCount; i++) - { - var token = records[i].Interface; - switch (token >> 24) - { - case 0: - break; - case TypeDefTable.Index: - token = (token & 0xFFFFFF) << 2 | 0; - break; - case TypeRefTable.Index: - token = (token & 0xFFFFFF) << 2 | 1; - break; - case TypeSpecTable.Index: - token = (token & 0xFFFFFF) << 2 | 2; - break; - default: - throw new InvalidOperationException(); - } - - records[i].Interface = token; - } + 0 => 0, + TypeDefTable.Index => (token & 0xFFFFFF) << 2 | 0, + TypeRefTable.Index => (token & 0xFFFFFF) << 2 | 1, + TypeSpecTable.Index => (token & 0xFFFFFF) << 2 | 2, + _ => throw new InvalidOperationException(), + }; + internal void Fixup() + { // LAMESPEC the CLI spec says that InterfaceImpl should be sorted by { Class, Interface }, // but it appears to only be necessary to sort by Class (and csc emits InterfaceImpl records in // source file order, so to be able to support round tripping, we need to retain ordering as well). diff --git a/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs b/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs index d133d27341..02260fbc4d 100644 --- a/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs +++ b/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs @@ -26,8 +26,6 @@ Jeroen Frijters using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -42,7 +40,7 @@ internal struct Record : IRecord internal int Method; internal int Association; - readonly int IRecord.SortKey => Association; + readonly int IRecord.SortKey => EncodeHasSemantics(Association); readonly int IRecord.FilterKey => Association; @@ -72,27 +70,22 @@ internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) module.Metadata.AddMethodSemantics( - System.Reflection.Metadata.Ecma335.MetadataTokens.EntityHandle(records[i].Association), + MetadataTokens.EntityHandle(records[i].Association), (System.Reflection.MethodSemanticsAttributes)records[i].Semantics, - System.Reflection.Metadata.Ecma335.MetadataTokens.MethodDefinitionHandle(records[i].Method)); + MetadataTokens.MethodDefinitionHandle(records[i].Method)); } + static internal int EncodeHasSemantics(int token) => (token >> 24) switch + { + EventTable.Index => (token & 0xFFFFFF) << 1 | 0, + PropertyTable.Index => (token & 0xFFFFFF) << 1 | 1, + _ => throw new InvalidOperationException(), + }; + internal void Fixup(ModuleBuilder moduleBuilder) { for (int i = 0; i < rowCount; i++) - { moduleBuilder.FixupPseudoToken(ref records[i].Method); - int token = records[i].Association; - // do the HasSemantics encoding, so that we can sort the table - token = (token >> 24) switch - { - EventTable.Index => (token & 0xFFFFFF) << 1 | 0, - PropertyTable.Index => (token & 0xFFFFFF) << 1 | 1, - _ => throw new InvalidOperationException(), - }; - - records[i].Association = token; - } Sort(); } diff --git a/src/IKVM.Reflection/Metadata/SortedTable.cs b/src/IKVM.Reflection/Metadata/SortedTable.cs index 76521ac919..bcf955daaa 100644 --- a/src/IKVM.Reflection/Metadata/SortedTable.cs +++ b/src/IKVM.Reflection/Metadata/SortedTable.cs @@ -23,7 +23,6 @@ Jeroen Frijters */ using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; namespace IKVM.Reflection.Metadata { @@ -61,7 +60,7 @@ internal Enumerable(SortedTable table, int token) public Enumerator GetEnumerator() { var records = table.records; - if (!table.Sorted) + if (table.Sorted == false) return new Enumerator(records, table.RowCount - 1, -1, token); int index = BinarySearch(records, table.RowCount, token & 0xFFFFFF); diff --git a/src/IKVM.Reflection/Universe.cs b/src/IKVM.Reflection/Universe.cs index 69093a0643..d0959884b7 100644 --- a/src/IKVM.Reflection/Universe.cs +++ b/src/IKVM.Reflection/Universe.cs @@ -39,13 +39,16 @@ namespace IKVM.Reflection public sealed class Universe : IDisposable { + public static readonly string NetCoreLibName = "System.Runtime"; + public static readonly string NetFxCoreLibName = "mscorlib"; + #if NETCOREAPP3_1_OR_GREATER - public static readonly string DefaultCoreLibName = "System.Runtime"; + public static readonly string DefaultCoreLibName = NetCoreLibName; #elif NETFRAMEWORK - public static readonly string DefaultCoreLibName = "mscorlib"; + public static readonly string DefaultCoreLibName = NetFxCoreLibName; #endif diff --git a/src/IKVM.Tests.Util/DotNetSdkUtil.cs b/src/IKVM.Tests.Util/DotNetSdkUtil.cs index 64574f6f2c..b0a49b1347 100644 --- a/src/IKVM.Tests.Util/DotNetSdkUtil.cs +++ b/src/IKVM.Tests.Util/DotNetSdkUtil.cs @@ -33,6 +33,24 @@ public static bool IsAssembly(string path) } } + /// + /// Gets the paths to the reference assemblies of the specified TFM for the target framework. + /// + /// + /// + /// + /// + /// + public static string GetCoreLibName(string tfm, string targetFrameworkIdentifier, string targetFrameworkVersion) + { + if (targetFrameworkIdentifier == ".NETFramework") + return "mscorlib"; + if (targetFrameworkIdentifier == ".NETCore") + return "System.Runtime"; + + throw new InvalidOperationException(); + } + /// /// Gets the paths to the reference assemblies of the specified TFM for the target framework. /// @@ -86,7 +104,7 @@ static IList GetCorePathToReferenceAssemblies(string tfm, string targetF throw new InvalidOperationException(); // find all ref assemblies - return new[] { refsDir }; + return new[] { Path.GetFullPath(refsDir) }; } } diff --git a/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj b/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj index 8d2868e21c..aa880d2c48 100644 --- a/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj +++ b/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj @@ -8,7 +8,4 @@ - - - From 2e5564362a405e51cde5dbd2ad949ef509360bce Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sun, 14 Jan 2024 10:03:32 -0600 Subject: [PATCH 05/10] Clean up some sorting. Using Array.Sort now, and Comparable. Fast enough. Making sure we have appropriate token or row numbers where needed. Fix strong naming to use RSA.Create(). Fix manifest resource support. --- IKVM.sln | 8 +- .../IKVM.Java.Tests.Util.csproj | 2 +- src/IKVM.Java/IKVM.Java.msbuildproj | 1 + .../IKVM.MSBuild.Tasks.csproj | 2 +- .../ModuleWriterTests.cs | 163 ++++++++++++++++++ src/IKVM.Reflection/Emit/AssemblyBuilder.cs | 14 +- .../Emit/CustomAttributeBuilder.cs | 1 - src/IKVM.Reflection/Emit/EventBuilder.cs | 10 +- .../Emit/GenericTypeParameterBuilder.cs | 6 +- src/IKVM.Reflection/Emit/MethodBuilder.cs | 2 +- src/IKVM.Reflection/Emit/ModuleBuilder.cs | 100 +++++------ src/IKVM.Reflection/Emit/TypeBuilder.cs | 4 +- src/IKVM.Reflection/IKVM.Reflection.csproj | 2 +- src/IKVM.Reflection/Metadata/AssemblyTable.cs | 2 + .../Metadata/ClassLayoutTable.cs | 11 +- src/IKVM.Reflection/Metadata/ConstantTable.cs | 10 +- .../Metadata/CustomAttributeTable.cs | 9 +- .../Metadata/DeclSecurityTable.cs | 5 +- src/IKVM.Reflection/Metadata/EventMapTable.cs | 14 +- .../Metadata/FieldLayoutTable.cs | 11 +- .../Metadata/FieldMarshalTable.cs | 6 +- src/IKVM.Reflection/Metadata/FieldRVATable.cs | 7 +- .../Metadata/GenericParamConstraintTable.cs | 10 +- .../Metadata/GenericParamTable.cs | 30 ++-- src/IKVM.Reflection/Metadata/ImplMapTable.cs | 9 +- .../Metadata/InterfaceImplTable.cs | 27 ++- .../Metadata/MethodImplTable.cs | 15 +- .../Metadata/MethodSemanticsTable.cs | 4 +- .../Metadata/NestedClassTable.cs | 11 +- .../Metadata/PropertyMapTable.cs | 12 +- src/IKVM.Reflection/Metadata/SortedTable.cs | 53 +----- src/IKVM.Reflection/Reader/TypeDefImpl.cs | 2 +- src/IKVM.Reflection/StrongNameKeyPair.cs | 9 +- src/IKVM.Reflection/Writer/ModuleWriter.cs | 133 ++++---------- src/IKVM.Runtime/RuntimeJavaType.cs | 50 ++---- src/IKVM.Tests.Util/IKVM.Tests.Util.csproj | 2 +- .../IKVM.Tools.Exporter.csproj | 2 +- .../CompilerClassLoader.cs | 103 +++++------ .../IKVM.Tools.Importer.csproj | 2 +- src/ikvmc/Properties/launchSettings.json | 8 + 40 files changed, 443 insertions(+), 429 deletions(-) create mode 100644 src/ikvmc/Properties/launchSettings.json diff --git a/IKVM.sln b/IKVM.sln index b47c0d7d72..d69efc6beb 100644 --- a/IKVM.sln +++ b/IKVM.sln @@ -53,12 +53,6 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IKVM.MSBuild.Tasks.Tests", "src\IKVM.MSBuild.Tasks.Tests\IKVM.MSBuild.Tasks.Tests.csproj", "{E7C0E8FA-F34C-48C6-AD55-FD9798F5BC71}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IKVM.Java", "src\IKVM.Java\IKVM.Java.msbuildproj", "{ABD81C7E-F986-4018-986E-ACAF82C64D3A}" - ProjectSection(ProjectDependencies) = postProject - {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7} = {0A87FF49-AC9D-479A-ACBB-F4028A0BE1F7} - {17979A73-C0CE-41CD-B54F-4E72B998E6D0} = {17979A73-C0CE-41CD-B54F-4E72B998E6D0} - {2F29E48C-63C3-4E47-BCBA-A7454B9119CF} = {2F29E48C-63C3-4E47-BCBA-A7454B9119CF} - {50954AE0-E513-4CE7-AC8E-F3896CA0BEB7} = {50954AE0-E513-4CE7-AC8E-F3896CA0BEB7} - EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IKVM.NET.Sdk", "src\IKVM.NET.Sdk\IKVM.NET.Sdk.msbuildproj", "{704BD7C7-7746-4D72-A86E-ECFE7BBD80CC}" EndProject @@ -325,7 +319,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IKVM.Image.runtime.win-arm6 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IKVM.Reflection.Tests", "src\IKVM.Reflection.Tests\IKVM.Reflection.Tests.csproj", "{17755A44-22EC-4D28-B219-3C5CAE6317C8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IKVM.Java.Tests.Util", "src\IKVM.Java.Tests.Util\IKVM.Java.Tests.Util.csproj", "{00AFE142-5F4F-48DD-90C1-20CC0512C43C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IKVM.Java.Tests.Util", "src\IKVM.Java.Tests.Util\IKVM.Java.Tests.Util.csproj", "{00AFE142-5F4F-48DD-90C1-20CC0512C43C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/IKVM.Java.Tests.Util/IKVM.Java.Tests.Util.csproj b/src/IKVM.Java.Tests.Util/IKVM.Java.Tests.Util.csproj index 284ecbb6c6..1b6ae8895c 100644 --- a/src/IKVM.Java.Tests.Util/IKVM.Java.Tests.Util.csproj +++ b/src/IKVM.Java.Tests.Util/IKVM.Java.Tests.Util.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/IKVM.Java/IKVM.Java.msbuildproj b/src/IKVM.Java/IKVM.Java.msbuildproj index be715ca3d1..81ddd9d256 100644 --- a/src/IKVM.Java/IKVM.Java.msbuildproj +++ b/src/IKVM.Java/IKVM.Java.msbuildproj @@ -6,6 +6,7 @@ net472;net6.0 true + true diff --git a/src/IKVM.MSBuild.Tasks/IKVM.MSBuild.Tasks.csproj b/src/IKVM.MSBuild.Tasks/IKVM.MSBuild.Tasks.csproj index 8516d7968d..af84027354 100644 --- a/src/IKVM.MSBuild.Tasks/IKVM.MSBuild.Tasks.csproj +++ b/src/IKVM.MSBuild.Tasks/IKVM.MSBuild.Tasks.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/IKVM.Reflection.Tests/ModuleWriterTests.cs b/src/IKVM.Reflection.Tests/ModuleWriterTests.cs index 8262c1b60b..c579835d34 100644 --- a/src/IKVM.Reflection.Tests/ModuleWriterTests.cs +++ b/src/IKVM.Reflection.Tests/ModuleWriterTests.cs @@ -205,11 +205,174 @@ public void CanWriteInterfaceImplementation(FrameworkSpec framework) var t = a.GetType("Impl"); t.IsInterface.Should().BeFalse(); t.IsClass.Should().BeTrue(); + t.GetInterfaces().Should().Contain(i); var m = t.GetMethod("Method"); m.Should().NotBeNull(); m.Should().Return(tempLoad.CoreAssembly.GetType("System.Object")); } + /// + /// Due to the unique sorting requirements of InterfaceImpl, we check that we can emit two different sorted by a differnt class. + /// + /// + [Theory] + [MemberData(nameof(FrameworkSpec.GetFrameworkTestData), MemberType = typeof(FrameworkSpec))] + public void CanWriteMultipleInterfaceImplementation(FrameworkSpec framework) + { + if (Init(framework, out var universe, out var resolver, out var verifier, out var tempPath, out var tempLoad) == false) + return; + + var assembly = universe.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save, tempPath); + var module = assembly.DefineDynamicModule("Test", "Test.dll", false); + + var iface1Type = module.DefineType("Iface1", TypeAttributes.Interface); + var iface1Method = iface1Type.DefineMethod("Method1", MethodAttributes.Abstract, universe.Import(typeof(object)), Array.Empty()); + + var iface2Type = module.DefineType("Iface2", TypeAttributes.Interface); + var iface2Method = iface2Type.DefineMethod("Method2", MethodAttributes.Abstract, universe.Import(typeof(object)), Array.Empty()); + + var impl1Type = module.DefineType("Impl1", TypeAttributes.Public, null, new[] { iface1Type }); + var impl1Method = impl1Type.DefineMethod("Method1", MethodAttributes.Public, universe.Import(typeof(object)), Array.Empty()); + + var il1 = impl1Method.GetILGenerator(); + il1.Emit(OpCodes.Ldnull); + il1.Emit(OpCodes.Ret); + + var impl2Type = module.DefineType("Impl2", TypeAttributes.Public, null, new[] { iface2Type }); + var impl2Method = impl2Type.DefineMethod("Method2", MethodAttributes.Public, universe.Import(typeof(object)), Array.Empty()); + + impl2Type.DefineMethodOverride(iface2Method, impl2Method); + impl1Type.DefineMethodOverride(iface1Method, impl1Method); + + var il2 = impl2Method.GetILGenerator(); + il2.Emit(OpCodes.Ldnull); + il2.Emit(OpCodes.Ret); + + iface1Type.CreateType(); + iface2Type.CreateType(); + impl1Type.CreateType(); + impl2Type.CreateType(); + assembly.Save("Test.dll"); + + foreach (var v in verifier.Verify(new PEReader(File.OpenRead(Path.Combine(tempPath, "Test.dll"))))) + v.Code.Should().Be(ILVerify.VerifierError.None); + + var a = tempLoad.LoadFromAssemblyPath(Path.Combine(tempPath, "Test.dll")); + var i1 = a.GetType("Iface1"); + i1.IsInterface.Should().BeTrue(); + i1.Should().HaveMethod("Method1", Array.Empty()); + var i2 = a.GetType("Iface2"); + i2.IsInterface.Should().BeTrue(); + i2.Should().HaveMethod("Method2", Array.Empty()); + var t1 = a.GetType("Impl1"); + t1.IsInterface.Should().BeFalse(); + t1.IsClass.Should().BeTrue(); + t1.GetInterfaces().Should().Contain(i1); + var m1 = t1.GetMethod("Method1"); + m1.Should().NotBeNull(); + m1.Should().Return(tempLoad.CoreAssembly.GetType("System.Object")); + var t2 = a.GetType("Impl2"); + t2.IsInterface.Should().BeFalse(); + t2.IsClass.Should().BeTrue(); + t2.GetInterfaces().Should().Contain(i2); + var m2 = t2.GetMethod("Method2"); + m2.Should().NotBeNull(); + m2.Should().Return(tempLoad.CoreAssembly.GetType("System.Object")); + } + + [Theory] + [MemberData(nameof(FrameworkSpec.GetFrameworkTestData), MemberType = typeof(FrameworkSpec))] + public void CanWriteConstantFieldValue(FrameworkSpec framework) + { + if (Init(framework, out var universe, out var resolver, out var verifier, out var tempPath, out var tempLoad) == false) + return; + + var assembly = universe.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save, tempPath); + var module = assembly.DefineDynamicModule("Test", "Test.dll", false); + + var type = module.DefineType("Test"); + var field = type.DefineField("value", universe.Import(typeof(int)), FieldAttributes.Public | FieldAttributes.Static); + field.SetConstant(128); + type.CreateType(); + assembly.Save("Test.dll"); + + foreach (var v in verifier.Verify(new PEReader(File.OpenRead(Path.Combine(tempPath, "Test.dll"))))) + v.Code.Should().Be(ILVerify.VerifierError.None); + + var a = tempLoad.LoadFromAssemblyPath(Path.Combine(tempPath, "Test.dll")); + var t = a.GetType("Test"); + var f = t.GetField("value"); + f.FieldType.Should().Be(tempLoad.CoreAssembly.GetType("System.Int32")); + } + + [Theory] + [MemberData(nameof(FrameworkSpec.GetFrameworkTestData), MemberType = typeof(FrameworkSpec))] + public void CanWriteCustomAttributeWithArgument(FrameworkSpec framework) + { + if (Init(framework, out var universe, out var resolver, out var verifier, out var tempPath, out var tempLoad) == false) + return; + + var assembly = universe.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save, tempPath); + var cab = new CustomAttributeBuilder(universe.Import(typeof(AssemblyVersionAttribute)).GetConstructor(new[] { universe.Import(typeof(string)) }), new[] { "1.0.0.0" }); + assembly.SetCustomAttribute(cab); + + var module = assembly.DefineDynamicModule("Test", "Test.dll", false); + var type = module.DefineType("Test"); + type.CreateType(); + assembly.Save("Test.dll"); + + foreach (var v in verifier.Verify(new PEReader(File.OpenRead(Path.Combine(tempPath, "Test.dll"))))) + v.Code.Should().Be(ILVerify.VerifierError.None); + + var a = tempLoad.LoadFromAssemblyPath(Path.Combine(tempPath, "Test.dll")); + var d = a.GetCustomAttributesData(); + d.Should().HaveCount(1); + d[0].ConstructorArguments.Should().HaveCount(1); + d[0].ConstructorArguments[0].Value.Should().Be("1.0.0.0"); + d[0].Constructor.Should().BeSameAs(tempLoad.CoreAssembly.GetType("System.Reflection.AssemblyVersionAttribute").GetConstructor(new[] { tempLoad.CoreAssembly.GetType("System.String") })); + } + + [Theory] + [MemberData(nameof(FrameworkSpec.GetFrameworkTestData), MemberType = typeof(FrameworkSpec))] + public void CanWriteManifestResources(FrameworkSpec framework) + { + if (Init(framework, out var universe, out var resolver, out var verifier, out var tempPath, out var tempLoad) == false) + return; + + var assembly = universe.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save, tempPath); + var module = assembly.DefineDynamicModule("Test", "Test.dll", false); + var type = module.DefineType("Test"); + module.DefineManifestResource("Resource1", new MemoryStream(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 }), ResourceAttributes.Public); + module.DefineManifestResource("Resource2", new MemoryStream(new byte[] { 0x06, 0x07, 0x08, 0x09, 0x0a }), ResourceAttributes.Public); + module.DefineManifestResource("Resource3", new MemoryStream(new byte[] { 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }), ResourceAttributes.Public); + type.CreateType(); + assembly.Save("Test.dll"); + + foreach (var v in verifier.Verify(new PEReader(File.OpenRead(Path.Combine(tempPath, "Test.dll"))))) + v.Code.Should().Be(ILVerify.VerifierError.None); + + var a = tempLoad.LoadFromAssemblyPath(Path.Combine(tempPath, "Test.dll")); + a.GetManifestResourceNames().Should().HaveCount(3); + + var res1 = a.GetManifestResourceStream("Resource1"); + res1.Should().HaveLength(5); + var buf1 = new byte[res1.Length]; + res1.Read(buf1, 0, (int)res1.Length); + buf1.Should().BeEquivalentTo(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 }); + + var res2 = a.GetManifestResourceStream("Resource2"); + res2.Should().HaveLength(5); + var buf2 = new byte[res2.Length]; + res2.Read(buf2, 0, (int)res2.Length); + buf2.Should().BeEquivalentTo(new byte[] { 0x06, 0x07, 0x08, 0x09, 0x0a }); + + var res3 = a.GetManifestResourceStream("Resource3"); + res3.Should().HaveLength(5); + var buf3 = new byte[res3.Length]; + res3.Read(buf3, 0, (int)res3.Length); + buf3.Should().BeEquivalentTo(new byte[] { 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }); + } + } } diff --git a/src/IKVM.Reflection/Emit/AssemblyBuilder.cs b/src/IKVM.Reflection/Emit/AssemblyBuilder.cs index cca8003441..6632a841da 100644 --- a/src/IKVM.Reflection/Emit/AssemblyBuilder.cs +++ b/src/IKVM.Reflection/Emit/AssemblyBuilder.cs @@ -439,7 +439,6 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi foreach (var moduleBuilder in modules) { moduleBuilder.FillAssemblyRefTable(); - moduleBuilder.EmitResources(); if (moduleBuilder != manifestModule) { @@ -456,8 +455,6 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi moduleBuilder.ExportTypes(fileToken, manifestModule); } - - moduleBuilder.CloseResources(); } foreach (var module in addedModules) @@ -467,7 +464,7 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi } if (entryPointToken.IsNil && entryPoint != null) - entryPointToken = MetadataTokens.MethodDefinitionHandle(entryPoint.MetadataToken); + entryPointToken = (MethodDefinitionHandle)MetadataTokens.EntityHandle(entryPoint.MetadataToken); // finally, write the manifest module ModuleWriter.WriteModule(keyPair, publicKey, manifestModule, fileKind, portableExecutableKind, imageFileMachine, unmanagedResources ?? manifestModule.unmanagedResources, entryPointToken, streamOrNull); @@ -509,13 +506,12 @@ public IResourceWriter DefineResource(string name, string description, string fi { // FXBUG we ignore the description, because there is no such thing - string fullPath = fileName; + var fullPath = fileName; if (dir != null) - { fullPath = Path.Combine(dir, fileName); - } - ResourceWriter rw = new ResourceWriter(fullPath); - ResourceFile resfile; + + var rw = new ResourceWriter(fullPath); + var resfile = new ResourceFile(); resfile.Name = name; resfile.FileName = fileName; resfile.Attributes = attribute; diff --git a/src/IKVM.Reflection/Emit/CustomAttributeBuilder.cs b/src/IKVM.Reflection/Emit/CustomAttributeBuilder.cs index 3d9c071c14..8f18c1425f 100644 --- a/src/IKVM.Reflection/Emit/CustomAttributeBuilder.cs +++ b/src/IKVM.Reflection/Emit/CustomAttributeBuilder.cs @@ -25,7 +25,6 @@ Jeroen Frijters using System.Collections.Generic; using System.Diagnostics; using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; using System.Text; using IKVM.Reflection.Writer; diff --git a/src/IKVM.Reflection/Emit/EventBuilder.cs b/src/IKVM.Reflection/Emit/EventBuilder.cs index 7d82dfb884..9f919cb78c 100644 --- a/src/IKVM.Reflection/Emit/EventBuilder.cs +++ b/src/IKVM.Reflection/Emit/EventBuilder.cs @@ -43,7 +43,7 @@ struct Accessor readonly TypeBuilder typeBuilder; readonly string name; EventAttributes attributes; - readonly int eventtype; + readonly int eventType; MethodBuilder addOnMethod; MethodBuilder removeOnMethod; MethodBuilder fireMethod; @@ -62,7 +62,7 @@ internal EventBuilder(TypeBuilder typeBuilder, string name, EventAttributes attr this.typeBuilder = typeBuilder; this.name = name; this.attributes = attributes; - this.eventtype = typeBuilder.ModuleBuilder.GetTypeTokenForMemberRef(eventtype); + this.eventType = typeBuilder.ModuleBuilder.GetTypeTokenForMemberRef(eventtype); } public void SetAddOnMethod(MethodBuilder mdBuilder) @@ -185,7 +185,7 @@ public EventToken GetEventToken() public override Type EventHandlerType { - get { return typeBuilder.ModuleBuilder.ResolveType(eventtype); } + get { return typeBuilder.ModuleBuilder.ResolveType(eventType); } } internal void Bake() @@ -193,9 +193,9 @@ internal void Bake() var rec = new EventTable.Record(); rec.EventFlags = (short)attributes; rec.Name = typeBuilder.ModuleBuilder.GetOrAddString(name); - rec.EventType = eventtype; - var token = MetadataTokens.GetToken(MetadataTokens.EventDefinitionHandle(typeBuilder.ModuleBuilder.Event.AddRecord(rec))); + rec.EventType = eventType; + var token = MetadataTokens.GetToken(MetadataTokens.EventDefinitionHandle(typeBuilder.ModuleBuilder.Event.AddRecord(rec))); if (lazyPseudoToken == 0) lazyPseudoToken = token; else diff --git a/src/IKVM.Reflection/Emit/GenericTypeParameterBuilder.cs b/src/IKVM.Reflection/Emit/GenericTypeParameterBuilder.cs index d722e87495..bf3a65b5fe 100644 --- a/src/IKVM.Reflection/Emit/GenericTypeParameterBuilder.cs +++ b/src/IKVM.Reflection/Emit/GenericTypeParameterBuilder.cs @@ -192,9 +192,9 @@ internal override void CheckBaked() private void AddConstraint(Type type) { - GenericParamConstraintTable.Record rec = new GenericParamConstraintTable.Record(); - rec.Owner = paramPseudoIndex; - rec.Constraint = this.ModuleBuilder.GetTypeTokenForMemberRef(type); + var rec = new GenericParamConstraintTable.Record(); + rec.Owner = MetadataTokens.GetToken(MetadataTokens.GenericParameterHandle(paramPseudoIndex)); + rec.Constraint = ModuleBuilder.GetTypeTokenForMemberRef(type); this.ModuleBuilder.GenericParamConstraint.AddRecord(rec); } diff --git a/src/IKVM.Reflection/Emit/MethodBuilder.cs b/src/IKVM.Reflection/Emit/MethodBuilder.cs index 01346a3aca..74909ee44f 100644 --- a/src/IKVM.Reflection/Emit/MethodBuilder.cs +++ b/src/IKVM.Reflection/Emit/MethodBuilder.cs @@ -681,7 +681,7 @@ internal void WriteParamRecords(MetadataBuilder metadata) internal void FixupToken(int token, ref int parameterToken) { - typeBuilder.ModuleBuilder.RegisterTokenFixup(this.pseudoToken, token); + typeBuilder.ModuleBuilder.RegisterTokenFixup(pseudoToken, token); if (parameters != null) foreach (var pb in parameters) pb.FixupToken(parameterToken++); diff --git a/src/IKVM.Reflection/Emit/ModuleBuilder.cs b/src/IKVM.Reflection/Emit/ModuleBuilder.cs index 92785905b7..06f42b9b53 100644 --- a/src/IKVM.Reflection/Emit/ModuleBuilder.cs +++ b/src/IKVM.Reflection/Emit/ModuleBuilder.cs @@ -77,23 +77,36 @@ internal ResourceWriterRecord(string name, ResourceWriter rw, Stream stream, Res this.attributes = attributes; } - internal readonly void Emit(ModuleBuilder mb, int offset) + internal readonly int GetLength() => 4 + (int)stream.Length; + + /// + /// Writes the resource to the resource stream. + /// + /// + internal readonly void Write(ModuleBuilder module) { + // write resource to internal stream rw?.Generate(); + // align the start of the resource + module.resourceStream.Align(8); + var offset = module.resourceStream.Count; + + // resource begins with a length, followed by the data + module.resourceStream.WriteInt32((int)stream.Length); + stream.Position = 0; + var buffer = new byte[8192]; + int length; + while ((length = stream.Read(buffer, 0, buffer.Length)) != 0) + module.resourceStream.WriteBytes(buffer, 0, length); + + // add the resource record var rec = new ManifestResourceTable.Record(); rec.Offset = offset; rec.Flags = (int)attributes; - rec.Name = mb.GetOrAddString(name); + rec.Name = module.GetOrAddString(name); rec.Implementation = 0; - mb.ManifestResource.AddRecord(rec); - } - - internal readonly int GetLength() => 4 + (int)stream.Length; - - internal readonly void Write(ModuleBuilder module) - { - throw new NotImplementedException(); + module.ManifestResource.AddRecord(rec); } internal readonly void Close() @@ -194,6 +207,7 @@ public bool Equals(MethodSpecKey other) readonly MetadataBuilder metadata; readonly BlobBuilder ilStream; + readonly BlobBuilder resourceStream; readonly AssemblyBuilder asm; Guid mvid; uint timestamp; @@ -242,6 +256,7 @@ internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, { this.metadata = new MetadataBuilder(); this.ilStream = new BlobBuilder(); + this.resourceStream = new BlobBuilder(); this.asm = asm ?? throw new ArgumentNullException(nameof(asm)); this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); @@ -283,6 +298,11 @@ internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, /// internal BlobBuilder ILStream => ilStream; + /// + /// Gets a reference to the for the resource stream. + /// + internal BlobBuilder ResourceStream => resourceStream; + /// /// Gets a new string handle from the metadata. /// @@ -663,52 +683,17 @@ public IResourceWriter DefineResource(string name, string description, ResourceA return rw; } - internal void EmitResources() - { - int offset = 0; - foreach (var rwr in resourceWriters) - { - // resources must be 8-byte aligned - offset = (offset + 7) & ~7; - rwr.Emit(this, offset); - offset += rwr.GetLength(); - } - } - + /// + /// Writes the defined resources to the resource blob and metadata tables. + /// + /// internal void WriteResources() { - int offset = 0; - foreach (var rwr in resourceWriters) { - throw new NotImplementedException(); - - //// resources must be 8-byte aligned - //int alignment = ((offset + 7) & ~7) - offset; - //for (int i = 0; i < alignment; i++) - // mw.Write((byte)0); - //rwr.Write(mw); - //offset += rwr.GetLength() + alignment; - } - } - - internal void CloseResources() - { - foreach (var rwr in resourceWriters) + rwr.Write(this); rwr.Close(); - } - - internal int GetManifestResourcesLength() - { - int length = 0; - foreach (var rwr in resourceWriters) - { - // resources must be 8-byte aligned - length = (length + 7) & ~7; - length += rwr.GetLength(); } - - return length; } public override Assembly Assembly @@ -1274,7 +1259,7 @@ internal void AddConstant(int parentToken, object defaultValue) // encode index into blobs, as well as pass along value, since SRME does not have an AddConstant override that takes a handle // final blob should be deduplicated, leading to the same index value on write rec.Offset = GetOrAddBlob(val.ToArray()); - rec.Value = val; + rec.Value = defaultValue; Constant.AddRecord(rec); } @@ -1562,13 +1547,12 @@ public void __Save(PortableExecutableKinds portableExecutableKind, ImageFileMach public void __Save(Stream stream, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine) { if (!stream.CanRead || !stream.CanWrite || !stream.CanSeek || stream.Position != 0) - { throw new ArgumentException("Stream must support read/write/seek and current position must be zero.", "stream"); - } + SaveImpl(stream, portableExecutableKind, imageFileMachine); } - private void SaveImpl(Stream streamOrNull, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine) + void SaveImpl(Stream streamOrNull, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine) { SetIsSaved(); PopulatePropertyAndEventTables(); @@ -1610,9 +1594,7 @@ private void SaveImpl(Stream streamOrNull, PortableExecutableKinds portableExecu } FillAssemblyRefTable(); - EmitResources(); ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, unmanagedResources, default, streamOrNull); - CloseResources(); } public void __AddAssemblyReference(AssemblyName assemblyName) @@ -1741,8 +1723,8 @@ internal void SetInterfaceImplementationCustomAttribute(TypeBuilder typeBuilder, var rec = new InterfaceImplCustomAttribute(); rec.type = typeBuilder.MetadataToken; - var token = GetTypeToken(interfaceType).Token; + var token = GetTypeToken(interfaceType).Token; token = (token >> 24) switch { TypeDefTable.Index => (token & 0xFFFFFF) << 2 | 0, @@ -1762,13 +1744,13 @@ internal void ResolveInterfaceImplPseudoTokens() { if (interfaceImplCustomAttributes != null) { - foreach (InterfaceImplCustomAttribute rec in interfaceImplCustomAttributes) + foreach (var rec in interfaceImplCustomAttributes) { for (int i = 0; i < InterfaceImpl.records.Length; i++) { if (InterfaceImpl.records[i].Class == rec.type && InterfaceImpl.records[i].Interface == rec.interfaceType) { - RegisterTokenFixup(rec.pseudoToken, (InterfaceImplTable.Index << 24) | (i + 1)); + RegisterTokenFixup(rec.pseudoToken, MetadataTokens.GetToken(MetadataTokens.InterfaceImplementationHandle(i + 1))); break; } } diff --git a/src/IKVM.Reflection/Emit/TypeBuilder.cs b/src/IKVM.Reflection/Emit/TypeBuilder.cs index d2ceff7bac..434f43fd36 100644 --- a/src/IKVM.Reflection/Emit/TypeBuilder.cs +++ b/src/IKVM.Reflection/Emit/TypeBuilder.cs @@ -509,7 +509,7 @@ internal void PopulatePropertyAndEventTables() { var rec = new PropertyMapTable.Record(); rec.Parent = token; - rec.PropertyList = ModuleBuilder.Property.RowCount + 1; + rec.PropertyList = MetadataTokens.GetToken(MetadataTokens.PropertyDefinitionHandle(ModuleBuilder.Property.RowCount + 1)); ModuleBuilder.PropertyMap.AddRecord(rec); foreach (var pb in properties) pb.Bake(); @@ -519,7 +519,7 @@ internal void PopulatePropertyAndEventTables() { var rec = new EventMapTable.Record(); rec.Parent = token; - rec.EventList = ModuleBuilder.Event.RowCount + 1; + rec.EventList = MetadataTokens.GetToken(MetadataTokens.EventDefinitionHandle(ModuleBuilder.Event.RowCount + 1)); ModuleBuilder.EventMap.AddRecord(rec); foreach (var eb in events) eb.Bake(); diff --git a/src/IKVM.Reflection/IKVM.Reflection.csproj b/src/IKVM.Reflection/IKVM.Reflection.csproj index 58e577a065..754032f372 100644 --- a/src/IKVM.Reflection/IKVM.Reflection.csproj +++ b/src/IKVM.Reflection/IKVM.Reflection.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/IKVM.Reflection/Metadata/AssemblyTable.cs b/src/IKVM.Reflection/Metadata/AssemblyTable.cs index fd3784da20..7eb75c7b0c 100644 --- a/src/IKVM.Reflection/Metadata/AssemblyTable.cs +++ b/src/IKVM.Reflection/Metadata/AssemblyTable.cs @@ -34,6 +34,7 @@ sealed class AssemblyTable : Table internal struct Record { + internal int HashAlgId; internal ushort MajorVersion; internal ushort MinorVersion; @@ -43,6 +44,7 @@ internal struct Record internal BlobHandle PublicKey; internal StringHandle Name; internal StringHandle Culture; + } internal const int Index = 0x20; diff --git a/src/IKVM.Reflection/Metadata/ClassLayoutTable.cs b/src/IKVM.Reflection/Metadata/ClassLayoutTable.cs index 85f23e6cf8..b278aaf9f3 100644 --- a/src/IKVM.Reflection/Metadata/ClassLayoutTable.cs +++ b/src/IKVM.Reflection/Metadata/ClassLayoutTable.cs @@ -21,10 +21,11 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Collections.Generic; +using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; namespace IKVM.Reflection.Metadata { @@ -38,13 +39,13 @@ internal struct Record : IRecord internal int ClassSize; internal int Parent; - int IRecord.SortKey => Parent; + readonly int IRecord.FilterKey => Parent; - int IRecord.FilterKey => Parent; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(Parent, other.Parent); } - internal const int Index = 0x0f; + internal const int Index = (int)TableIndex.ClassLayout; internal override void Read(Reader.MetadataReader mr) { @@ -62,7 +63,7 @@ internal override void Write(ModuleBuilder module) for (int i = 0; i < rowCount; i++) module.Metadata.AddTypeLayout( - System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].Parent), + (TypeDefinitionHandle)MetadataTokens.EntityHandle(records[i].Parent), (ushort)records[i].PackingSize, (uint)records[i].ClassSize); } diff --git a/src/IKVM.Reflection/Metadata/ConstantTable.cs b/src/IKVM.Reflection/Metadata/ConstantTable.cs index 8470214585..d581f5175a 100644 --- a/src/IKVM.Reflection/Metadata/ConstantTable.cs +++ b/src/IKVM.Reflection/Metadata/ConstantTable.cs @@ -22,12 +22,12 @@ Jeroen Frijters */ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; namespace IKVM.Reflection.Metadata { @@ -43,10 +43,10 @@ internal struct Record : IRecord internal BlobHandle Offset; internal object Value; - readonly int IRecord.SortKey => EncodeHasConstant(Parent); - readonly int IRecord.FilterKey => Parent; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(EncodeHasConstant(Parent), EncodeHasConstant(other.Parent)); + } internal const int Index = 0x0B; @@ -75,10 +75,10 @@ internal override void Write(ModuleBuilder module) } } - internal void Fixup(ModuleBuilder moduleBuilder) + internal void Fixup(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) - moduleBuilder.FixupPseudoToken(ref records[i].Parent); + module.FixupPseudoToken(ref records[i].Parent); Sort(); } diff --git a/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs b/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs index 313e186ee1..34650c288a 100644 --- a/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs +++ b/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs @@ -22,6 +22,7 @@ Jeroen Frijters */ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -40,10 +41,10 @@ internal struct Record : IRecord internal int Constructor; internal BlobHandle Value; - readonly int IRecord.SortKey => EncodeHasCustomAttribute(Parent); - readonly int IRecord.FilterKey => Parent; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(EncodeHasCustomAttribute(Parent), EncodeHasCustomAttribute(other.Parent)); + } internal const int Index = 0x0C; @@ -68,7 +69,7 @@ internal override void Write(ModuleBuilder module) MetadataTokens.EntityHandle(records[i].Constructor), records[i].Value); - Debug.Assert(h == MetadataTokens.CustomAttributeHandle(i)); + Debug.Assert(h == MetadataTokens.CustomAttributeHandle(i + 1)); } } @@ -80,7 +81,7 @@ internal void Fixup(ModuleBuilder moduleBuilder) { moduleBuilder.FixupPseudoToken(ref records[i].Constructor); moduleBuilder.FixupPseudoToken(ref records[i].Parent); - if (records[i].Parent >> 24 == GenericParamTable.Index) + if (MetadataTokens.EntityHandle(records[i].Parent).Kind == HandleKind.GenericParameter) records[i].Parent = (GenericParamTable.Index << 24) + genericParamFixup[(records[i].Parent & 0xFFFFFF) - 1] + 1; // TODO if we ever add support for custom attributes on DeclSecurity or GenericParamConstraint diff --git a/src/IKVM.Reflection/Metadata/DeclSecurityTable.cs b/src/IKVM.Reflection/Metadata/DeclSecurityTable.cs index 48a4cb6207..d799b21f58 100644 --- a/src/IKVM.Reflection/Metadata/DeclSecurityTable.cs +++ b/src/IKVM.Reflection/Metadata/DeclSecurityTable.cs @@ -22,6 +22,7 @@ Jeroen Frijters */ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -40,10 +41,10 @@ internal struct Record : IRecord internal int Parent; internal BlobHandle PermissionSet; - readonly int IRecord.SortKey => Parent; - readonly int IRecord.FilterKey => Parent; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(Parent, other.Parent); + } internal const int Index = 0x0E; diff --git a/src/IKVM.Reflection/Metadata/EventMapTable.cs b/src/IKVM.Reflection/Metadata/EventMapTable.cs index 45d99d0252..0dc7e23bad 100644 --- a/src/IKVM.Reflection/Metadata/EventMapTable.cs +++ b/src/IKVM.Reflection/Metadata/EventMapTable.cs @@ -21,10 +21,15 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { + sealed class EventMapTable : SortedTable { @@ -34,9 +39,10 @@ internal struct Record : IRecord internal int Parent; internal int EventList; - readonly int IRecord.SortKey => Parent; - readonly int IRecord.FilterKey => Parent; + + public readonly int CompareTo(Record other) => Comparer.Default.Compare(Parent, other.Parent); + } internal const int Index = 0x12; @@ -54,8 +60,8 @@ internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) module.Metadata.AddEventMap( - System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].Parent), - System.Reflection.Metadata.Ecma335.MetadataTokens.EventDefinitionHandle(records[i].EventList)); + (TypeDefinitionHandle)MetadataTokens.EntityHandle(records[i].Parent), + (EventDefinitionHandle)MetadataTokens.EntityHandle(records[i].EventList)); } } diff --git a/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs b/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs index cd4e3a8a44..016700d66b 100644 --- a/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs +++ b/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs @@ -21,6 +21,10 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata @@ -35,9 +39,10 @@ internal struct Record : IRecord internal int Offset; internal int Field; - readonly int IRecord.SortKey => Field; - readonly int IRecord.FilterKey => Field; + + public readonly int CompareTo(Record other) => Comparer.Default.Compare(Field, other.Field); + } internal const int Index = 0x10; @@ -55,7 +60,7 @@ internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) module.Metadata.AddFieldLayout( - System.Reflection.Metadata.Ecma335.MetadataTokens.FieldDefinitionHandle(records[i].Field), + (FieldDefinitionHandle)MetadataTokens.EntityHandle(records[i].Field), records[i].Offset); } diff --git a/src/IKVM.Reflection/Metadata/FieldMarshalTable.cs b/src/IKVM.Reflection/Metadata/FieldMarshalTable.cs index 0e415f263b..1f4ce0e998 100644 --- a/src/IKVM.Reflection/Metadata/FieldMarshalTable.cs +++ b/src/IKVM.Reflection/Metadata/FieldMarshalTable.cs @@ -22,6 +22,7 @@ Jeroen Frijters */ using System; +using System.Collections.Generic; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -29,6 +30,7 @@ Jeroen Frijters namespace IKVM.Reflection.Metadata { + sealed class FieldMarshalTable : SortedTable { @@ -38,10 +40,10 @@ internal struct Record : IRecord internal int Parent; internal BlobHandle NativeType; - readonly int IRecord.SortKey => EncodeHasFieldMarshal(Parent); - readonly int IRecord.FilterKey => Parent; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(EncodeHasFieldMarshal(Parent), EncodeHasFieldMarshal(other.Parent)); + } internal const int Index = 0x0D; diff --git a/src/IKVM.Reflection/Metadata/FieldRVATable.cs b/src/IKVM.Reflection/Metadata/FieldRVATable.cs index fed37d7b56..d8758f4519 100644 --- a/src/IKVM.Reflection/Metadata/FieldRVATable.cs +++ b/src/IKVM.Reflection/Metadata/FieldRVATable.cs @@ -21,10 +21,13 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Collections.Generic; + using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { + sealed class FieldRVATable : SortedTable { @@ -34,9 +37,9 @@ internal struct Record : IRecord internal int RVA; // we set the high bit to signify that the RVA is in the CIL stream (instead of .sdata) internal int Field; - int IRecord.SortKey => Field; + readonly int IRecord.FilterKey => Field; - int IRecord.FilterKey => Field; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(Field, other.Field); } diff --git a/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs b/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs index 9cc2379d87..b21451f82a 100644 --- a/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs +++ b/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs @@ -21,7 +21,9 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Collections.Generic; using System.Diagnostics; +using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; @@ -37,10 +39,10 @@ internal struct Record : IRecord internal int Owner; internal int Constraint; - readonly int IRecord.SortKey => Owner; - readonly int IRecord.FilterKey => Owner; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(Owner, other.Owner); + } internal const int Index = 0x2C; @@ -59,7 +61,7 @@ internal override void Write(ModuleBuilder module) for (int i = 0; i < rowCount; i++) { var h = module.Metadata.AddGenericParameterConstraint( - MetadataTokens.GenericParameterHandle(records[i].Owner), + (GenericParameterHandle)MetadataTokens.EntityHandle(records[i].Owner), MetadataTokens.EntityHandle(records[i].Constraint)); Debug.Assert(h == MetadataTokens.GenericParameterConstraintHandle(i + 1)); @@ -70,7 +72,7 @@ internal void Fixup(ModuleBuilder moduleBuilder) { var fixups = moduleBuilder.GenericParam.GetIndexFixup(); for (int i = 0; i < rowCount; i++) - records[i].Owner = fixups[records[i].Owner - 1] + 1; + records[i].Owner = MetadataTokens.GetToken(MetadataTokens.GenericParameterHandle(fixups[MetadataTokens.GetRowNumber(MetadataTokens.EntityHandle(records[i].Owner)) - 1] + 1)); Sort(); } diff --git a/src/IKVM.Reflection/Metadata/GenericParamTable.cs b/src/IKVM.Reflection/Metadata/GenericParamTable.cs index 281d308f0e..b0018a939f 100644 --- a/src/IKVM.Reflection/Metadata/GenericParamTable.cs +++ b/src/IKVM.Reflection/Metadata/GenericParamTable.cs @@ -32,7 +32,7 @@ Jeroen Frijters namespace IKVM.Reflection.Metadata { - sealed class GenericParamTable : SortedTable, IComparer + sealed class GenericParamTable : SortedTable { internal struct Record : IRecord @@ -43,13 +43,21 @@ internal struct Record : IRecord internal int Owner; internal StringHandle Name; - // not part of the table, we use it to be able to fixup the GenericParamConstraint table - internal int unsortedIndex; - - readonly int IRecord.SortKey => EncodeOwner(Owner); + /// + /// Original index of the record before sort. + /// + internal int UnsortedIndex; readonly int IRecord.FilterKey => Owner; + public readonly int CompareTo(Record other) + { + if (Owner == other.Owner) + return Comparer.Default.Compare(Number, other.Number); + else + return Comparer.Default.Compare(EncodeOwner(Owner), EncodeOwner(other.Owner)); + } + } internal const int Index = 0x2A; @@ -84,7 +92,7 @@ internal void Fixup(ModuleBuilder moduleBuilder) for (int i = 0; i < rowCount; i++) { moduleBuilder.FixupPseudoToken(ref records[i].Owner); - records[i].unsortedIndex = i; + records[i].UnsortedIndex = i; } Sort(); @@ -97,14 +105,6 @@ internal void Fixup(ModuleBuilder moduleBuilder) _ => throw new InvalidOperationException(), }; - int IComparer.Compare(Record x, Record y) - { - if (x.Owner == y.Owner) - return x.Number == y.Number ? 0 : (x.Number > y.Number ? 1 : -1); - - return x.Owner > y.Owner ? 1 : -1; - } - internal void PatchAttribute(int token, GenericParameterAttributes genericParameterAttributes) { records[(token & 0xFFFFFF) - 1].Flags = (short)genericParameterAttributes; @@ -114,7 +114,7 @@ internal int[] GetIndexFixup() { var array = new int[rowCount]; for (int i = 0; i < rowCount; i++) - array[records[i].unsortedIndex] = i; + array[records[i].UnsortedIndex] = i; return array; } diff --git a/src/IKVM.Reflection/Metadata/ImplMapTable.cs b/src/IKVM.Reflection/Metadata/ImplMapTable.cs index bfe184cb43..13fe111338 100644 --- a/src/IKVM.Reflection/Metadata/ImplMapTable.cs +++ b/src/IKVM.Reflection/Metadata/ImplMapTable.cs @@ -21,6 +21,7 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Collections.Generic; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -40,10 +41,10 @@ internal struct Record : IRecord internal StringHandle ImportName; internal int ImportScope; - readonly int IRecord.SortKey => MemberForwarded; - readonly int IRecord.FilterKey => MemberForwarded; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(MemberForwarded, other.MemberForwarded); + } internal const int Index = 0x1C; @@ -63,10 +64,10 @@ internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) module.Metadata.AddMethodImport( - MetadataTokens.MethodDefinitionHandle(records[i].MemberForwarded), + (MethodDefinitionHandle)MetadataTokens.EntityHandle(records[i].MemberForwarded), (System.Reflection.MethodImportAttributes)records[i].MappingFlags, records[i].ImportName, - MetadataTokens.ModuleReferenceHandle(records[i].ImportScope)); + (ModuleReferenceHandle)MetadataTokens.EntityHandle(records[i].ImportScope)); } internal void Fixup(ModuleBuilder moduleBuilder) diff --git a/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs b/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs index b2d18a89ec..69ec083e06 100644 --- a/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs +++ b/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs @@ -21,8 +21,9 @@ Jeroen Frijters jeroen@frijters.net */ -using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; @@ -39,9 +40,10 @@ internal struct Record : IRecord internal int Class; internal int Interface; - readonly int IRecord.SortKey => EncodeOwner(Class); - readonly int IRecord.FilterKey => Class; + + public readonly int CompareTo(Record other) => Comparer.Default.Compare(Class, other.Class); + } internal const int Index = (int)TableIndex.InterfaceImpl; @@ -60,24 +62,21 @@ internal override void Write(ModuleBuilder module) for (int i = 0; i < rowCount; i++) { var h = module.Metadata.AddInterfaceImplementation( - MetadataTokens.TypeDefinitionHandle(records[i].Class), + (TypeDefinitionHandle)MetadataTokens.EntityHandle(records[i].Class), MetadataTokens.EntityHandle(records[i].Interface)); Debug.Assert(h == MetadataTokens.InterfaceImplementationHandle(i + 1)); } } - internal static int EncodeOwner(int token) => (token >> 24) switch - { - 0 => 0, - TypeDefTable.Index => (token & 0xFFFFFF) << 2 | 0, - TypeRefTable.Index => (token & 0xFFFFFF) << 2 | 1, - TypeSpecTable.Index => (token & 0xFFFFFF) << 2 | 2, - _ => throw new InvalidOperationException(), - }; - - internal void Fixup() + internal void Fixup(ModuleBuilder module) { + for (int i = 0; i < rowCount; i++) + { + module.FixupPseudoToken(ref records[i].Class); + module.FixupPseudoToken(ref records[i].Interface); + } + // LAMESPEC the CLI spec says that InterfaceImpl should be sorted by { Class, Interface }, // but it appears to only be necessary to sort by Class (and csc emits InterfaceImpl records in // source file order, so to be able to support round tripping, we need to retain ordering as well). diff --git a/src/IKVM.Reflection/Metadata/MethodImplTable.cs b/src/IKVM.Reflection/Metadata/MethodImplTable.cs index 153dcf5fc4..ee6e74265a 100644 --- a/src/IKVM.Reflection/Metadata/MethodImplTable.cs +++ b/src/IKVM.Reflection/Metadata/MethodImplTable.cs @@ -21,11 +21,12 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Collections.Generic; using System.Diagnostics; +using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; namespace IKVM.Reflection.Metadata { @@ -40,10 +41,10 @@ internal struct Record : IRecord internal int MethodBody; internal int MethodDeclaration; - readonly int IRecord.SortKey => Class; - readonly int IRecord.FilterKey => Class; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(Class, other.Class); + } internal const int Index = 0x19; @@ -63,11 +64,11 @@ internal override void Write(ModuleBuilder module) for (int i = 0; i < rowCount; i++) { var h = module.Metadata.AddMethodImplementation( - System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].Class), - System.Reflection.Metadata.Ecma335.MetadataTokens.EntityHandle(records[i].MethodBody), - System.Reflection.Metadata.Ecma335.MetadataTokens.EntityHandle(records[i].MethodDeclaration)); + (TypeDefinitionHandle)MetadataTokens.EntityHandle(records[i].Class), + MetadataTokens.EntityHandle(records[i].MethodBody), + MetadataTokens.EntityHandle(records[i].MethodDeclaration)); - Debug.Assert(h == System.Reflection.Metadata.Ecma335.MetadataTokens.MethodImplementationHandle(i + 1)); + Debug.Assert(h == MetadataTokens.MethodImplementationHandle(i + 1)); } } diff --git a/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs b/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs index 02260fbc4d..c032d6f865 100644 --- a/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs +++ b/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs @@ -40,10 +40,10 @@ internal struct Record : IRecord internal int Method; internal int Association; - readonly int IRecord.SortKey => EncodeHasSemantics(Association); - readonly int IRecord.FilterKey => Association; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(EncodeHasSemantics(Association), EncodeHasSemantics(other.Association)); + } internal const int Index = 0x18; diff --git a/src/IKVM.Reflection/Metadata/NestedClassTable.cs b/src/IKVM.Reflection/Metadata/NestedClassTable.cs index 5ee6d6d6d1..387c4b1b45 100644 --- a/src/IKVM.Reflection/Metadata/NestedClassTable.cs +++ b/src/IKVM.Reflection/Metadata/NestedClassTable.cs @@ -22,12 +22,11 @@ Jeroen Frijters */ using System.Collections.Generic; +using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; - namespace IKVM.Reflection.Metadata { @@ -39,10 +38,10 @@ internal struct Record : IRecord internal int NestedClass; internal int EnclosingClass; - readonly int IRecord.SortKey => NestedClass; - readonly int IRecord.FilterKey => NestedClass; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(NestedClass, other.NestedClass); + } internal const int Index = 0x29; @@ -60,8 +59,8 @@ internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) module.Metadata.AddNestedType( - System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].NestedClass), - System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].EnclosingClass)); + (TypeDefinitionHandle)MetadataTokens.EntityHandle(records[i].NestedClass), + (TypeDefinitionHandle)MetadataTokens.EntityHandle(records[i].EnclosingClass)); } internal List GetNestedClasses(int enclosingClass) diff --git a/src/IKVM.Reflection/Metadata/PropertyMapTable.cs b/src/IKVM.Reflection/Metadata/PropertyMapTable.cs index 71cafab7e5..b9d758c9e7 100644 --- a/src/IKVM.Reflection/Metadata/PropertyMapTable.cs +++ b/src/IKVM.Reflection/Metadata/PropertyMapTable.cs @@ -21,13 +21,15 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Collections.Generic; +using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; namespace IKVM.Reflection.Metadata { + sealed class PropertyMapTable : SortedTable { @@ -37,10 +39,10 @@ internal struct Record : IRecord internal int Parent; internal int PropertyList; - readonly int IRecord.SortKey => Parent; - readonly int IRecord.FilterKey => Parent; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(Parent, other.Parent); + } internal const int Index = 0x15; @@ -58,8 +60,8 @@ internal override void Write(ModuleBuilder module) { for (int i = 0; i < rowCount; i++) module.Metadata.AddPropertyMap( - System.Reflection.Metadata.Ecma335.MetadataTokens.TypeDefinitionHandle(records[i].Parent), - System.Reflection.Metadata.Ecma335.MetadataTokens.PropertyDefinitionHandle(records[i].PropertyList)); + (TypeDefinitionHandle)MetadataTokens.EntityHandle(records[i].Parent), + (PropertyDefinitionHandle)MetadataTokens.EntityHandle(records[i].PropertyList)); } } diff --git a/src/IKVM.Reflection/Metadata/SortedTable.cs b/src/IKVM.Reflection/Metadata/SortedTable.cs index bcf955daaa..176a08e3ab 100644 --- a/src/IKVM.Reflection/Metadata/SortedTable.cs +++ b/src/IKVM.Reflection/Metadata/SortedTable.cs @@ -31,11 +31,9 @@ abstract class SortedTable : Table where T : SortedTable.IRecord { - internal interface IRecord + internal interface IRecord : IComparable { - int SortKey { get; } - int FilterKey { get; } } @@ -147,54 +145,7 @@ internal Enumerable Filter(int token) /// protected void Sort() { -#if NETFRAMEWORK - HeapSort(); -#else - if (rowCount < 256) - StackSort(); - else - HeapSort(); -#endif - } - -#if NETFRAMEWORK == false - - /// - /// Sorts the rows without allocating a temporary array on the heap. - /// - unsafe void StackSort() - { - var map = (Span)stackalloc ulong[rowCount]; - for (int i = 0; i < rowCount; i++) - map[i] = ((ulong)records[i].SortKey << 32) | (uint)i; - - map.Sort(Comparer.Default); - var newRecords = new T[rowCount]; - for (int i = 0; i < rowCount; i++) - newRecords[i] = records[(int)map[i]]; - - records = newRecords; - return; - } - -#endif - - /// - /// Sorts the rows while allocating a temporary array on the heap. - /// - void HeapSort() - { - var map = new ulong[rowCount]; - for (uint i = 0; i < map.Length; i++) - map[i] = ((ulong)records[i].SortKey << 32) | i; - - Array.Sort(map, Comparer.Default); - var newRecords = new T[rowCount]; - for (int i = 0; i < map.Length; i++) - newRecords[i] = records[(int)map[i]]; - - records = newRecords; - return; + Array.Sort(records, 0, rowCount, Comparer.Default); } } diff --git a/src/IKVM.Reflection/Reader/TypeDefImpl.cs b/src/IKVM.Reflection/Reader/TypeDefImpl.cs index 39c2d4fad1..c90c1e1368 100644 --- a/src/IKVM.Reflection/Reader/TypeDefImpl.cs +++ b/src/IKVM.Reflection/Reader/TypeDefImpl.cs @@ -109,7 +109,7 @@ public override FieldInfo[] __GetDeclaredFields() public override Type[] __GetDeclaredInterfaces() { List list = null; - foreach (int i in module.InterfaceImpl.Filter(this.MetadataToken)) + foreach (int i in module.InterfaceImpl.Filter(MetadataToken)) { list ??= new List(); list.Add(module.ResolveType(module.InterfaceImpl.records[i].Interface, this)); diff --git a/src/IKVM.Reflection/StrongNameKeyPair.cs b/src/IKVM.Reflection/StrongNameKeyPair.cs index 71b3b9872f..2ebbd03cf9 100644 --- a/src/IKVM.Reflection/StrongNameKeyPair.cs +++ b/src/IKVM.Reflection/StrongNameKeyPair.cs @@ -68,7 +68,8 @@ public StrongNameKeyPair(byte[] keyPairArray) /// Initializes a new instance. /// /// - public StrongNameKeyPair(FileStream keyPairFile) : this(ReadAllBytes(keyPairFile)) + public StrongNameKeyPair(FileStream keyPairFile) : + this(ReadAllBytes(keyPairFile)) { } @@ -91,7 +92,7 @@ public byte[] PublicKey if (Universe.MonoRuntime) return MonoGetPublicKey(); - using RSACryptoServiceProvider rsa = CreateRSA(); + using var rsa = CreateRSA(); var rsaParameters = rsa.ExportParameters(false); var cspBlob = ExportPublicKey(rsaParameters); var publicKey = new byte[12 + cspBlob.Length]; @@ -107,13 +108,13 @@ public byte[] PublicKey } } - internal RSACryptoServiceProvider CreateRSA() + internal RSA CreateRSA() { try { if (keyPairArray != null) { - var rsa = new RSACryptoServiceProvider(); + var rsa = RSA.Create(); // we import from parameters, as using ImportCspBlob // causes the exception "KeySet not found" when signing a hash later. rsa.ImportParameters(RSAParametersFromByteArray(keyPairArray)); diff --git a/src/IKVM.Reflection/Writer/ModuleWriter.cs b/src/IKVM.Reflection/Writer/ModuleWriter.cs index d2618447fb..21fea05747 100644 --- a/src/IKVM.Reflection/Writer/ModuleWriter.cs +++ b/src/IKVM.Reflection/Writer/ModuleWriter.cs @@ -107,7 +107,7 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IK /// /// /// - /// + /// /// /// /// @@ -115,46 +115,49 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IK /// /// /// - static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, MethodDefinitionHandle entryPoint, Stream stream) + static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder module, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, MethodDefinitionHandle entryPoint, Stream stream) { - moduleBuilder.ApplyUnmanagedExports(imageFileMachine); - moduleBuilder.FixupMethodBodyTokens(); + module.ApplyUnmanagedExports(imageFileMachine); + module.FixupMethodBodyTokens(); // for compatibility with Reflection.Emit, if there aren't any user strings, we add one - moduleBuilder.Metadata.GetOrAddUserString(""); + module.Metadata.GetOrAddUserString(""); if (resources != null) resources.Finish(); #if NETFRAMEWORK - if (moduleBuilder.symbolWriter != null) + if (module.symbolWriter != null) { - moduleBuilder.WriteSymbolTokenMap(); - moduleBuilder.symbolWriter.Close(); + module.WriteSymbolTokenMap(); + module.symbolWriter.Close(); } #endif // write the module content - WriteModuleImpl(moduleBuilder); + WriteModuleImpl(module); // initialize PE header builder var peHeaderBuilder = new PEHeaderBuilder( machine: GetMachine(imageFileMachine), - fileAlignment: moduleBuilder.__FileAlignment, - imageBase: (ulong)moduleBuilder.__ImageBase, + fileAlignment: module.__FileAlignment, + imageBase: (ulong)module.__ImageBase, subsystem: GetSubsystem(fileKind), - dllCharacteristics: (System.Reflection.PortableExecutable.DllCharacteristics)(int)moduleBuilder.__DllCharacteristics, + dllCharacteristics: (System.Reflection.PortableExecutable.DllCharacteristics)(int)module.__DllCharacteristics, imageCharacteristics: GetImageCharacteristics(imageFileMachine, fileKind), - sizeOfStackReserve: moduleBuilder.GetStackReserve(1048576)); + sizeOfStackReserve: module.GetStackReserve(1048576)); // initialize PE builder + var strongNameSignatureSize = ComputeStrongNameSignatureLength(publicKey); var peBuilder = new ManagedPEBuilder( peHeaderBuilder, - new MetadataRootBuilder(moduleBuilder.Metadata), - moduleBuilder.ILStream, + new MetadataRootBuilder(module.Metadata), + module.ILStream, + managedResources: module.ResourceStream, + strongNameSignatureSize: strongNameSignatureSize, entryPoint: entryPoint, flags: GetCorFlags(portableExecutableKind, keyPair), - deterministicIdProvider: GetDeterministicIdProvider(moduleBuilder)); + deterministicIdProvider: GetDeterministicIdProvider(module)); // serialize the image var pe = new BlobBuilder(); @@ -162,7 +165,7 @@ static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Re // strong name specified, sign the blobs if (keyPair != null) - peBuilder.Sign(pe, blobs => GetSignature(keyPair, blobs)); + peBuilder.Sign(pe, blobs => GetSignature(keyPair, blobs, strongNameSignatureSize)); // write the final content to the output stream pe.WriteContentTo(stream); @@ -178,7 +181,7 @@ static void WriteModuleImpl(IKVM.Reflection.Emit.ModuleBuilder moduleBuilder) moduleBuilder.TypeRef.Fixup(moduleBuilder); moduleBuilder.MethodImpl.Fixup(moduleBuilder); moduleBuilder.MethodSemantics.Fixup(moduleBuilder); - moduleBuilder.InterfaceImpl.Fixup(); + moduleBuilder.InterfaceImpl.Fixup(moduleBuilder); moduleBuilder.ResolveInterfaceImplPseudoTokens(); moduleBuilder.MemberRef.Fixup(moduleBuilder); moduleBuilder.Constant.Fixup(moduleBuilder); @@ -194,81 +197,9 @@ static void WriteModuleImpl(IKVM.Reflection.Emit.ModuleBuilder moduleBuilder) moduleBuilder.MethodSpec.Fixup(moduleBuilder); moduleBuilder.GenericParamConstraint.Fixup(moduleBuilder); - //// Import Address Table - //AssertRVA(mw, ImportAddressTableRVA); - //if (ImportAddressTableLength != 0) - //{ - // WriteRVA(mw, ImportHintNameTableRVA); - // WriteRVA(mw, 0); - //} - - //// CLI Header - //AssertRVA(mw, ComDescriptorRVA); - //cliHeader.MetaData.VirtualAddress = MetadataRVA; - //cliHeader.MetaData.Size = MetadataLength; - //if (ResourcesLength != 0) - //{ - // cliHeader.Resources.VirtualAddress = ResourcesRVA; - // cliHeader.Resources.Size = ResourcesLength; - //} - //if (StrongNameSignatureLength != 0) - //{ - // cliHeader.StrongNameSignature.VirtualAddress = StrongNameSignatureRVA; - // cliHeader.StrongNameSignature.Size = StrongNameSignatureLength; - //} - //if (VTableFixupsLength != 0) - //{ - // cliHeader.VTableFixups.VirtualAddress = VTableFixupsRVA; - // cliHeader.VTableFixups.Size = VTableFixupsLength; - //} - //cliHeader.Write(mw); - - //// alignment padding - //for (int i = (int)(MethodBodiesRVA - (ComDescriptorRVA + ComDescriptorLength)); i > 0; i--) - // mw.Write((byte)0); - - // Method Bodies - //mw.Write(moduleBuilder.methodBodies); moduleBuilder.ILStream.WriteBytes(moduleBuilder.methodBodies.ToArray()); - - // Resources - //moduleBuilder.WriteResources(mw); - - // The strong name signature live here (if it exists), but it will written later - // and the following alignment padding will take care of reserving the space. - - //// alignment padding - //for (int i = (int)(MetadataRVA - (ResourcesRVA + ResourcesLength)); i > 0; i--) - // mw.Write((byte)0); - - // Metadata - //AssertRVA(mw, MetadataRVA); + moduleBuilder.WriteResources(); moduleBuilder.WriteMetadata(); - - //// alignment padding - //for (int i = (int)(VTableFixupsRVA - (MetadataRVA + MetadataLength)); i > 0; i--) - // mw.Write((byte)0); - - //// VTableFixups - //AssertRVA(mw, VTableFixupsRVA); - //WriteVTableFixups(mw, sdataRVA); - - //// Debug Directory - //AssertRVA(mw, DebugDirectoryRVA); - //WriteDebugDirectory(mw); - - //// Export Directory - //AssertRVA(mw, ExportDirectoryRVA); - //WriteExportDirectory(mw); - - //// Export Tables - //AssertRVA(mw, ExportTablesRVA); - //WriteExportTables(mw, sdataRVA); - - //// Import Directory - //AssertRVA(mw, ImportDirectoryRVA); - //if (ImportDirectoryLength != 0) - // WriteImportDirectory(mw); } /// @@ -374,16 +305,10 @@ static Func, BlobContentId> GetDeterministicIdProvider(Emit.Mo } /// - /// + /// Computes the length of the strong name signature. /// - /// + /// /// - /// - static BlobContentId DeterministicIdProvider(IEnumerable enumerable) - { - throw new NotImplementedException(); - } - static int ComputeStrongNameSignatureLength(byte[] publicKey) { if (publicKey == null) @@ -426,16 +351,22 @@ static byte[] GetSHA1Hash(IEnumerable blobs) /// /// Calculates the strong name signature for the specified blobs. /// + /// /// + /// /// /// - static byte[] GetSignature(StrongNameKeyPair keyPair, IEnumerable blobs) + static byte[] GetSignature(StrongNameKeyPair keyPair, IEnumerable blobs, int strongNameSignatureSize) { // sign the hash with the keypair using var rsa = keyPair.CreateRSA(); - var signature = rsa.SignHash(GetSHA1Hash(blobs), "1.3.14.3.2.26"); + var signature = rsa.SignHash(GetSHA1Hash(blobs), HashAlgorithmName.SHA1, RSASignaturePadding.Pss); Array.Reverse(signature); + // check that our signature length matches + if (signature.Length != strongNameSignatureSize) + throw new InvalidOperationException("Signature length mismatch."); + return signature; } diff --git a/src/IKVM.Runtime/RuntimeJavaType.cs b/src/IKVM.Runtime/RuntimeJavaType.cs index 719efd7e74..b57ea603f8 100644 --- a/src/IKVM.Runtime/RuntimeJavaType.cs +++ b/src/IKVM.Runtime/RuntimeJavaType.cs @@ -900,14 +900,13 @@ internal virtual bool IsPackageAccessibleFrom(RuntimeJavaType wrapper) } } - private static bool MatchingPackageNames(string name1, string name2) + static bool MatchingPackageNames(string name1, string name2) { int index1 = name1.LastIndexOf('.'); int index2 = name2.LastIndexOf('.'); if (index1 == -1 && index2 == -1) - { return true; - } + // for array types we need to skip the brackets int skip1 = 0; int skip2 = 0; @@ -933,7 +932,8 @@ private static bool MatchingPackageNames(string name1, string name2) { return false; } - return String.CompareOrdinal(name1, skip1, name2, skip2, index1 - skip1) == 0; + + return string.CompareOrdinal(name1, skip1, name2, skip2, index1 - skip1) == 0; } internal abstract Type TypeAsTBD @@ -946,50 +946,35 @@ internal Type TypeAsSignatureType get { if (IsUnloadable) - { return ((RuntimeUnloadableJavaType)this).MissingType ?? context.Types.Object; - } + if (IsGhostArray) - { return RuntimeArrayJavaType.MakeArrayType(context.Types.Object, ArrayRank); - } + return TypeAsTBD; } } - internal Type TypeAsPublicSignatureType - { - get - { - return (IsPublic ? this : GetPublicBaseTypeWrapper()).TypeAsSignatureType; - } - } + internal Type TypeAsPublicSignatureType => (IsPublic ? this : GetPublicBaseTypeWrapper()).TypeAsSignatureType; - internal virtual Type TypeAsBaseType - { - get - { - return TypeAsTBD; - } - } + internal virtual Type TypeAsBaseType => TypeAsTBD; internal Type TypeAsLocalOrStackType { get { if (IsUnloadable || IsGhost) - { return context.Types.Object; - } + if (IsNonPrimitiveValueType) { // return either System.ValueType or System.Enum return TypeAsTBD.BaseType; } + if (IsGhostArray) - { return RuntimeArrayJavaType.MakeArrayType(context.Types.Object, ArrayRank); - } + return TypeAsTBD; } } @@ -1000,13 +985,11 @@ internal Type TypeAsArrayType get { if (IsUnloadable || IsGhost) - { return context.Types.Object; - } + if (IsGhostArray) - { return RuntimeArrayJavaType.MakeArrayType(context.Types.Object, ArrayRank); - } + return TypeAsTBD; } } @@ -1016,9 +999,8 @@ internal Type TypeAsExceptionType get { if (IsUnloadable) - { return context.Types.Exception; - } + return TypeAsTBD; } } @@ -1032,8 +1014,8 @@ internal RuntimeJavaType ElementTypeWrapper { get { - Debug.Assert(!this.IsUnloadable); - Debug.Assert(this == context.VerifierJavaTypeFactory.Null || this.IsArray); + Debug.Assert(IsUnloadable == false); + Debug.Assert(this == context.VerifierJavaTypeFactory.Null || IsArray); if (this == context.VerifierJavaTypeFactory.Null) { diff --git a/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj b/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj index aa880d2c48..12b720a5f6 100644 --- a/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj +++ b/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj @@ -6,6 +6,6 @@ - + diff --git a/src/IKVM.Tools.Exporter/IKVM.Tools.Exporter.csproj b/src/IKVM.Tools.Exporter/IKVM.Tools.Exporter.csproj index d9a077d568..17563db628 100644 --- a/src/IKVM.Tools.Exporter/IKVM.Tools.Exporter.csproj +++ b/src/IKVM.Tools.Exporter/IKVM.Tools.Exporter.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/IKVM.Tools.Importer/CompilerClassLoader.cs b/src/IKVM.Tools.Importer/CompilerClassLoader.cs index ed4c6c9c93..fdb27c758e 100644 --- a/src/IKVM.Tools.Importer/CompilerClassLoader.cs +++ b/src/IKVM.Tools.Importer/CompilerClassLoader.cs @@ -608,6 +608,7 @@ void Save() else { Tracer.Info(Tracer.Compiler, "CompilerClassLoader saving {0} in {1}", assemblyFile, assemblyDir); + try { assemblyBuilder.Save(assemblyFile, options.pekind, options.imageFileMachine); @@ -623,104 +624,90 @@ void Save() } } - private void AddJavaModuleAttribute(ModuleBuilder mb) + void AddJavaModuleAttribute(ModuleBuilder mb) { - Type typeofJavaModuleAttribute = Context.Resolver.ResolveRuntimeType(typeof(JavaModuleAttribute).FullName); - PropertyInfo[] propInfos = new PropertyInfo[] { - typeofJavaModuleAttribute.GetProperty("Jars") - }; - object[] propValues = new object[] { - jarList.ToArray() - }; + var typeofJavaModuleAttribute = Context.Resolver.ResolveRuntimeType(typeof(JavaModuleAttribute).FullName); + var propInfos = new[] { typeofJavaModuleAttribute.GetProperty("Jars") }; + var propValues = new object[] { jarList.ToArray() }; + if (nameMappings.Count > 0) { - string[] list = new string[nameMappings.Count * 2]; + var list = new string[nameMappings.Count * 2]; int i = 0; - foreach (KeyValuePair kv in nameMappings) + foreach (var kv in nameMappings) { list[i++] = kv.Key; list[i++] = kv.Value; } + list = UnicodeUtil.EscapeInvalidSurrogates(list); - CustomAttributeBuilder cab = new CustomAttributeBuilder(typeofJavaModuleAttribute.GetConstructor(new Type[] { Context.Resolver.ResolveCoreType(typeof(string).FullName).MakeArrayType() }), new object[] { list }, propInfos, propValues); + var cab = new CustomAttributeBuilder(typeofJavaModuleAttribute.GetConstructor(new Type[] { Context.Resolver.ResolveCoreType(typeof(string).FullName).MakeArrayType() }), new object[] { list }, propInfos, propValues); mb.SetCustomAttribute(cab); } else { - CustomAttributeBuilder cab = new CustomAttributeBuilder(typeofJavaModuleAttribute.GetConstructor(Type.EmptyTypes), new object[0], propInfos, propValues); + var cab = new CustomAttributeBuilder(typeofJavaModuleAttribute.GetConstructor(Type.EmptyTypes), new object[0], propInfos, propValues); mb.SetCustomAttribute(cab); } } - private static void AddExportMapEntry(Dictionary> map, CompilerClassLoader ccl, string name) + static void AddExportMapEntry(Dictionary> map, CompilerClassLoader ccl, string name) { string assemblyName = ccl.assemblyBuilder.FullName; - List list; - if (!map.TryGetValue(assemblyName, out list)) + + if (map.TryGetValue(assemblyName, out var list) == false) { list = new List(); map.Add(assemblyName, list); } + if (list != null) // if list is null, we already have a wildcard export for this assembly - { list.Add(name); - } } - private void AddWildcardExports(Dictionary> exportedNamesPerAssembly) + void AddWildcardExports(Dictionary> exportedNamesPerAssembly) { - foreach (RuntimeAssemblyClassLoader acl in referencedAssemblies) - { + foreach (var acl in referencedAssemblies) exportedNamesPerAssembly[acl.MainAssembly.FullName] = null; - } } - private void WriteExportMap() + void WriteExportMap() { - Dictionary> exportedNamesPerAssembly = new Dictionary>(); + var exportedNamesPerAssembly = new Dictionary>(); + AddWildcardExports(exportedNamesPerAssembly); foreach (var tw in dynamicallyImportedTypes) - { AddExportMapEntry(exportedNamesPerAssembly, (CompilerClassLoader)tw.GetClassLoader(), tw.Name); - } + if (options.sharedclassloader == null) { - foreach (CompilerClassLoader ccl in peerReferences) - { + foreach (var ccl in peerReferences) exportedNamesPerAssembly[ccl.assemblyBuilder.FullName] = null; - } } else { - foreach (CompilerClassLoader ccl in options.sharedclassloader) + foreach (var ccl in options.sharedclassloader) { if (ccl != this) { ccl.AddWildcardExports(exportedNamesPerAssembly); - foreach (Jar jar in ccl.options.jars) - { - foreach (Jar.Item item in jar) - { - if (!item.IsStub) - { + foreach (var jar in ccl.options.jars) + foreach (var item in jar) + if (item.IsStub == false) AddExportMapEntry(exportedNamesPerAssembly, ccl, item.Name); - } - } - } + if (ccl.options.externalResources != null) - { foreach (string name in ccl.options.externalResources.Keys) - { AddExportMapEntry(exportedNamesPerAssembly, ccl, name); - } - } } } } - MemoryStream ms = new MemoryStream(); - BinaryWriter bw = new BinaryWriter(ms); + + var ms = new MemoryStream(); + var bw = new BinaryWriter(ms); bw.Write(exportedNamesPerAssembly.Count); - foreach (KeyValuePair> kv in exportedNamesPerAssembly) + + foreach (var kv in exportedNamesPerAssembly) { bw.Write(kv.Key); if (kv.Value == null) @@ -732,17 +719,15 @@ private void WriteExportMap() { Debug.Assert(kv.Value.Count != 0); bw.Write(kv.Value.Count); - foreach (string name in kv.Value) - { + foreach (var name in kv.Value) bw.Write(JVM.PersistableHash(name)); - } } } ms.Position = 0; - this.GetTypeWrapperFactory().ModuleBuilder.DefineManifestResource("ikvm.exports", ms, ResourceAttributes.Public); + GetTypeWrapperFactory().ModuleBuilder.DefineManifestResource("ikvm.exports", ms, ResourceAttributes.Public); } - private void WriteResources() + void WriteResources() { Tracer.Info(Tracer.Compiler, "CompilerClassLoader adding resources..."); @@ -753,7 +738,7 @@ private void WriteResources() { var hasEntries = false; var mem = new MemoryStream(); - using (ZipArchive zip = new ZipArchive(mem, ZipArchiveMode.Create)) + using (var zip = new ZipArchive(mem, ZipArchiveMode.Create)) { var stubs = new List(); foreach (Jar.Item item in options.jars[i]) @@ -779,29 +764,27 @@ private void WriteResources() if (stubs.Count != 0) { // generate the --ikvm-classes-- file in the jar - ZipArchiveEntry zipEntry = zip.CreateEntry(JVM.Internal.JarClassList); + var zipEntry = zip.CreateEntry(JVM.Internal.JarClassList); using Stream stream = zipEntry.Open(); using BinaryWriter bw = new BinaryWriter(stream); bw.Write(stubs.Count); foreach (string classFile in stubs) - { bw.Write(classFile); - } hasEntries = true; } } + // don't include empty classes.jar if (i != options.classesJar || hasEntries) { mem = new MemoryStream(mem.ToArray()); - string name = options.jars[i].Name; + var name = options.jars[i].Name; if (options.targetIsModule) - { name = Path.GetFileNameWithoutExtension(name) + "-" + moduleBuilder.ModuleVersionId.ToString("N") + Path.GetExtension(name); - } + jarList.Add(name); moduleBuilder.DefineManifestResource(name, mem, ResourceAttributes.Public); } @@ -2998,13 +2981,11 @@ private int CompilePass3() } Tracer.Info(Tracer.Compiler, "Compiling class files (2)"); WriteResources(); + if (options.externalResources != null) - { foreach (KeyValuePair kv in options.externalResources) - { assemblyBuilder.AddResourceFile(JVM.MangleResourceName(kv.Key), kv.Value); - } - } + if (options.fileversion != null) { CustomAttributeBuilder filever = new CustomAttributeBuilder(Context.Resolver.ResolveCoreType(typeof(System.Reflection.AssemblyFileVersionAttribute).FullName).GetConstructor(new Type[] { Context.Types.String }), new object[] { options.fileversion }); diff --git a/src/IKVM.Tools.Importer/IKVM.Tools.Importer.csproj b/src/IKVM.Tools.Importer/IKVM.Tools.Importer.csproj index d3f1a77ade..a59212befb 100644 --- a/src/IKVM.Tools.Importer/IKVM.Tools.Importer.csproj +++ b/src/IKVM.Tools.Importer/IKVM.Tools.Importer.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/ikvmc/Properties/launchSettings.json b/src/ikvmc/Properties/launchSettings.json new file mode 100644 index 0000000000..37d0dc50cc --- /dev/null +++ b/src/ikvmc/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "ikvmc": { + "commandName": "Project", + "commandLineArgs": "@C:\\dev\\ikvm\\src\\IKVM.Java\\obj\\Debug\\net6.0\\IKVM.Java.ikvmc.rsp" + } + } +} \ No newline at end of file From 0b93b35b51cf6b4bcd290fda3f3c3c554a9e767d Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sun, 14 Jan 2024 13:14:28 -0600 Subject: [PATCH 06/10] Fix up native resources. --- .../IKVM.Reflection.Tests.csproj | 14 +- .../ModuleWriterTests.cs | 27 ++++ src/IKVM.Reflection.Tests/sample.ico | Bin 0 -> 99448 bytes src/IKVM.Reflection/Emit/AssemblyBuilder.cs | 140 +++++++----------- src/IKVM.Reflection/Emit/ModuleBuilder.cs | 25 +++- ...ion.cs => ModuleResourceSectionBuilder.cs} | 108 ++++++++------ src/IKVM.Reflection/Writer/ModuleWriter.cs | 24 ++- src/IKVM.Reflection/Writer/OrdinalOrName.cs | 41 +++-- .../Writer/ResourceDirectoryEntry.cs | 62 +++++--- .../IkvmImporterInternal.cs | 30 ++-- 10 files changed, 266 insertions(+), 205 deletions(-) create mode 100644 src/IKVM.Reflection.Tests/sample.ico rename src/IKVM.Reflection/Writer/{ResourceSection.cs => ModuleResourceSectionBuilder.cs} (52%) diff --git a/src/IKVM.Reflection.Tests/IKVM.Reflection.Tests.csproj b/src/IKVM.Reflection.Tests/IKVM.Reflection.Tests.csproj index 32e0cd3fd2..be055641bd 100644 --- a/src/IKVM.Reflection.Tests/IKVM.Reflection.Tests.csproj +++ b/src/IKVM.Reflection.Tests/IKVM.Reflection.Tests.csproj @@ -1,4 +1,4 @@ - + net472;net6.0;net7.0 @@ -13,11 +13,19 @@ - all - runtime; build; native; contentfiles; analyzers; buildtransitive + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/src/IKVM.Reflection.Tests/ModuleWriterTests.cs b/src/IKVM.Reflection.Tests/ModuleWriterTests.cs index c579835d34..4c1a0f1aa2 100644 --- a/src/IKVM.Reflection.Tests/ModuleWriterTests.cs +++ b/src/IKVM.Reflection.Tests/ModuleWriterTests.cs @@ -373,6 +373,33 @@ public void CanWriteManifestResources(FrameworkSpec framework) buf3.Should().BeEquivalentTo(new byte[] { 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }); } + [Theory] + [MemberData(nameof(FrameworkSpec.GetFrameworkTestData), MemberType = typeof(FrameworkSpec))] + public void CanWriteWin32Icon(FrameworkSpec framework) + { + if (Init(framework, out var universe, out var resolver, out var verifier, out var tempPath, out var tempLoad) == false) + return; + + // obtain sample ico file + var ico = typeof(ModuleWriterTests).Assembly.GetManifestResourceStream("IKVM.Reflection.Tests.sample.ico"); + var buf = new byte[ico.Length]; + ico.Read(buf, 0, (int)ico.Length); + + // define assembly with an ico file + var assembly = universe.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save, tempPath); + assembly.__DefineIconResource(buf); + var module = assembly.DefineDynamicModule("Test", "Test.dll", false); + var type = module.DefineType("Test"); + type.CreateType(); + assembly.Save("Test.dll"); + + foreach (var v in verifier.Verify(new PEReader(File.OpenRead(Path.Combine(tempPath, "Test.dll"))))) + v.Code.Should().Be(ILVerify.VerifierError.None); + + // reload the assembly + var a = tempLoad.LoadFromAssemblyPath(Path.Combine(tempPath, "Test.dll")); + } + } } diff --git a/src/IKVM.Reflection.Tests/sample.ico b/src/IKVM.Reflection.Tests/sample.ico new file mode 100644 index 0000000000000000000000000000000000000000..e88b760e08396f125d3701773e7664b63d9dbb06 GIT binary patch literal 99448 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

!AJayj<+#(ks za0DYD0M+PZBp}WHv$Xo7vjX2Lqo4jB-M*Ns%@IR!+p>_)=drrFgLczRfE)%b{MUf~ z$zvwb$HXyU_|uR>Y%G)vi4h6_7!yo@2hwF|7_rpDbta%jI1$HTOdv(fDkh+bU19=Y z@i{K9VGN)^AkGnnA^adf5Lhx(kWe2i#vsy!6II3%TM#wV+9M2SOmCO0ZK=9QyxX8E z5eqB5@6wQgIBwbm=zi2KOict5)1Ns!FT`yp$B@mss5g2>{a7`Qq6oEGEp0K7tH1lZ zzne@T@Gh1k@Fv>}(bs9Bbm0eQdBRjKU#Q!9cEm7=#?Y-^avwR<+FZ0C3I~(T8DZ z5KA-GGeQh^GRxf%Aj)*#PkkEAIy3t2ROe0Ra#**d!COZ5x5#$L4kmu-w#k zCK!O$cG^!h_;IKd;^2A|Ar#TmzRpDSoFI&eFxoJb1ZYBCx&he(5>|R(Fo!@I6Bwcn z02mAwf`KZ;HZ5`*aSBc>3ivB`O&Z?yLNkZqu z5UBm}w@=~+4FwplngAdvMHm5vZ7Y&-08tpivH77MfP^7BS+<8i@trS62m})DJzD$E z(#8Vm{Zwq*K{lHOb^frlU~hL@Jol{=zTWYD&jXmAz*8&|>IZ!+uQb6i4LxJ781Gyx z@u$BFbfQl}e1i0Yssh(+0LH9Bl4~4@qCn2jlMiBX&{0x6X`@w75;DL9i0F0qV0`b` zsF$J+B(B2{CLkbw6osPwoaO<@slh=c%*QqZtO&8{p!cUa7g#X07_JlgfEGKTUP40* z2AWB@4mHL=h=IrVQB%K}eh+aSy)rEb8b%@?0Ampf*$_b(4Hb5jAuEtG1 FM*xBW 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 literal 0 HcmV?d00001 diff --git a/src/IKVM.Reflection/Emit/AssemblyBuilder.cs b/src/IKVM.Reflection/Emit/AssemblyBuilder.cs index 6632a841da..d1533663fe 100644 --- a/src/IKVM.Reflection/Emit/AssemblyBuilder.cs +++ b/src/IKVM.Reflection/Emit/AssemblyBuilder.cs @@ -381,8 +381,10 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi manifestModule.AssemblyTable.AddRecord(assemblyRecord); - var unmanagedResources = versionInfo != null || win32icon != null || win32manifest != null || win32resources != null ? new ResourceSection() : null; + // final copy of manifest module native resources + var nativeResources = manifestModule.nativeResources != null ? new ModuleResourceSectionBuilder(manifestModule.nativeResources) : new ModuleResourceSectionBuilder(); + // version info specified on assembly: insert into manifest module if (versionInfo != null) { versionInfo.SetName(GetName()); @@ -390,23 +392,25 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi foreach (var cab in customAttributes) { // .NET doesn't support copying blob custom attributes into the version info - if (!cab.HasBlob || universe.DecodeVersionInfoAttributeBlobs) + if (cab.HasBlob == false || universe.DecodeVersionInfoAttributeBlobs) versionInfo.SetAttribute(this, cab); } var versionInfoData = new ByteBuffer(512); versionInfo.Write(versionInfoData); - unmanagedResources.AddVersionInfo(versionInfoData); + nativeResources.AddVersionInfo(versionInfoData); } + // win32 icon specified on assembly: insert into manifest module if (win32icon != null) - unmanagedResources.AddIcon(win32icon); + nativeResources.AddIcon(win32icon); + // win32 manifest specified on assembly: insert into manifest module if (win32manifest != null) - unmanagedResources.AddManifest(win32manifest, fileKind == PEFileKinds.Dll ? (ushort)2 : (ushort)1); + nativeResources.AddManifest(win32manifest, fileKind == PEFileKinds.Dll ? (ushort)2 : (ushort)1); if (win32resources != null) - unmanagedResources.ExtractResources(win32resources); + nativeResources.ImportWin32ResourceFile(win32resources); // we intentionally don't filter out the version info (pseudo) custom attributes (to be compatible with .NET) foreach (var cab in customAttributes) @@ -417,6 +421,7 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi foreach (var fwd in typeForwarders) manifestModule.AddTypeForwarder(fwd.Type, fwd.IncludeNested); + // add resource files for assembly to manifest module foreach (var resfile in resourceFiles) { if (resfile.Writer != null) @@ -434,8 +439,7 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi manifestModule.ManifestResource.AddRecord(rec); } - var entryPointToken = MetadataTokens.MethodDefinitionHandle(0); - + // write each non-manifest module foreach (var moduleBuilder in modules) { moduleBuilder.FillAssemblyRefTable(); @@ -449,7 +453,7 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi } else { - ModuleWriter.WriteModule(null, null, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, moduleBuilder.unmanagedResources, default); + ModuleWriter.WriteModule(null, null, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, moduleBuilder.nativeResources, default); fileToken = AddFile(manifestModule, moduleBuilder.fileName, 0 /*ContainsMetaData*/); } @@ -457,17 +461,20 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi } } + // import existing modules foreach (var module in addedModules) { var fileToken = AddFile(manifestModule, module.FullyQualifiedName, 0 /*ContainsMetaData*/); module.ExportTypes(fileToken, manifestModule); } - if (entryPointToken.IsNil && entryPoint != null) + // start with an empty entry point + var entryPointToken = MetadataTokens.MethodDefinitionHandle(0); + if (entryPoint != null) entryPointToken = (MethodDefinitionHandle)MetadataTokens.EntityHandle(entryPoint.MetadataToken); // finally, write the manifest module - ModuleWriter.WriteModule(keyPair, publicKey, manifestModule, fileKind, portableExecutableKind, imageFileMachine, unmanagedResources ?? manifestModule.unmanagedResources, entryPointToken, streamOrNull); + ModuleWriter.WriteModule(keyPair, publicKey, manifestModule, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPointToken, streamOrNull); } AssemblyFileHandle AddFile(ModuleBuilder manifestModule, string fileName, int flags) @@ -531,9 +538,8 @@ public void DefineVersionInfoResource() public void DefineVersionInfoResource(string product, string productVersion, string company, string copyright, string trademark) { if (versionInfo != null || win32resources != null) - { throw new ArgumentException("Native resource has already been defined."); - } + versionInfo = new VersionInfo(); versionInfo.product = product; versionInfo.informationalVersion = productVersion; @@ -545,27 +551,24 @@ public void DefineVersionInfoResource(string product, string productVersion, str public void __DefineIconResource(byte[] iconFile) { if (win32icon != null || win32resources != null) - { throw new ArgumentException("Native resource has already been defined."); - } + win32icon = (byte[])iconFile.Clone(); } public void __DefineManifestResource(byte[] manifest) { if (win32manifest != null || win32resources != null) - { throw new ArgumentException("Native resource has already been defined."); - } + win32manifest = (byte[])manifest.Clone(); } public void __DefineUnmanagedResource(byte[] resource) { if (versionInfo != null || win32icon != null || win32manifest != null || win32resources != null) - { throw new ArgumentException("Native resource has already been defined."); - } + // The standard .NET DefineUnmanagedResource(byte[]) is useless, because it embeds "resource" (as-is) as the .rsrc section, // but it doesn't set the PE file Resource Directory entry to point to it. That's why we have a renamed version, which behaves // like DefineUnmanagedResource(string). @@ -581,57 +584,52 @@ public void DefineUnmanagedResource(string resourceFileName) public override Type[] GetTypes() { - List list = new List(); - foreach (ModuleBuilder module in modules) - { + var list = new List(); + + foreach (var module in modules) module.GetTypesImpl(list); - } - foreach (Module module in addedModules) - { + + foreach (var module in addedModules) module.GetTypesImpl(list); - } + return list.ToArray(); } internal override Type FindType(TypeName typeName) { - foreach (ModuleBuilder mb in modules) + foreach (var mb in modules) { - Type type = mb.FindType(typeName); + var type = mb.FindType(typeName); if (type != null) - { return type; - } } + foreach (Module module in addedModules) { - Type type = module.FindType(typeName); + var type = module.FindType(typeName); if (type != null) - { return type; - } } + return null; } internal override Type FindTypeIgnoreCase(TypeName lowerCaseName) { - foreach (ModuleBuilder mb in modules) + foreach (var mb in modules) { - Type type = mb.FindTypeIgnoreCase(lowerCaseName); + var type = mb.FindTypeIgnoreCase(lowerCaseName); if (type != null) - { return type; - } } + foreach (Module module in addedModules) { - Type type = module.FindTypeIgnoreCase(lowerCaseName); + var type = module.FindTypeIgnoreCase(lowerCaseName); if (type != null) - { return type; - } } + return null; } @@ -646,27 +644,11 @@ public void __SetImageRuntimeVersion(string imageRuntimeVersion, int mdStreamVer this.mdStreamVersion = mdStreamVersion; } - public override Module ManifestModule - { - get - { - if (pseudoManifestModule == null) - { - pseudoManifestModule = new ManifestModule(this); - } - return pseudoManifestModule; - } - } + public override Module ManifestModule => pseudoManifestModule ??= new ManifestModule(this); - public override MethodInfo EntryPoint - { - get { return entryPoint; } - } + public override MethodInfo EntryPoint => entryPoint; - public override AssemblyName[] GetReferencedAssemblies() - { - return Array.Empty(); - } + public override AssemblyName[] GetReferencedAssemblies() => Array.Empty(); public override Module[] GetLoadedModules(bool getResourceModules) { @@ -675,40 +657,29 @@ public override Module[] GetLoadedModules(bool getResourceModules) public override Module[] GetModules(bool getResourceModules) { - List list = new List(); - foreach (ModuleBuilder module in modules) - { + var list = new List(); + + foreach (var module in modules) if (getResourceModules || !module.IsResource()) - { list.Add(module); - } - } - foreach (Module module in addedModules) - { + + foreach (var module in addedModules) if (getResourceModules || !module.IsResource()) - { list.Add(module); - } - } + return list.ToArray(); } public override Module GetModule(string name) { - foreach (ModuleBuilder module in modules) - { + foreach (var module in modules) if (module.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) - { return module; - } - } - foreach (Module module in addedModules) - { + + foreach (var module in addedModules) if (module.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) - { return module; - } - } + return null; } @@ -751,14 +722,11 @@ public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyB internal override IList GetCustomAttributesData(Type attributeType) { - List list = new List(); - foreach (CustomAttributeBuilder cab in customAttributes) - { + var list = new List(); + foreach (var cab in customAttributes) if (attributeType == null || attributeType.IsAssignableFrom(cab.Constructor.DeclaringType)) - { list.Add(cab.ToData(this)); - } - } + return list; } diff --git a/src/IKVM.Reflection/Emit/ModuleBuilder.cs b/src/IKVM.Reflection/Emit/ModuleBuilder.cs index 06f42b9b53..fdf6ebd1a0 100644 --- a/src/IKVM.Reflection/Emit/ModuleBuilder.cs +++ b/src/IKVM.Reflection/Emit/ModuleBuilder.cs @@ -78,7 +78,7 @@ internal ResourceWriterRecord(string name, ResourceWriter rw, Stream stream, Res } internal readonly int GetLength() => 4 + (int)stream.Length; - + ///

/// Writes the resource to the resource stream. /// @@ -227,7 +227,7 @@ public bool Equals(MethodSpecKey other) internal readonly ByteBuffer methodBodies = new ByteBuffer(128 * 1024); internal readonly List tokenFixupOffsets = new List(); internal readonly ByteBuffer initializedData = new ByteBuffer(512); - internal ResourceSection unmanagedResources; + internal ModuleResourceSectionBuilder nativeResources; readonly Dictionary importedMemberRefs = new Dictionary(); readonly Dictionary importedMethodSpecs = new Dictionary(); readonly Dictionary referencedAssemblies = new Dictionary(); @@ -1400,12 +1400,23 @@ public ISymbolWriter GetSymWriter() #endif } + /// + /// Defines an unmanaged embedded resource given an opaque binary large object (BLOB) of bytes. + /// + /// + public void DefineUnmanagedResource(byte[] resource) + { + throw new NotImplementedException(); + } + + /// + /// Defines an unmanaged resource given the name of Win32 resource file. + /// + /// public void DefineUnmanagedResource(string resourceFileName) { - // This method reads the specified resource file (Win32 .res file) and converts it into the appropriate format and embeds it in the .rsrc section, - // also setting the Resource Directory entry. - unmanagedResources = new ResourceSection(); - unmanagedResources.ExtractResources(System.IO.File.ReadAllBytes(resourceFileName)); + nativeResources = new ModuleResourceSectionBuilder(); + nativeResources.ImportWin32ResourceFile(System.IO.File.ReadAllBytes(resourceFileName)); } public bool IsTransient() @@ -1594,7 +1605,7 @@ void SaveImpl(Stream streamOrNull, PortableExecutableKinds portableExecutableKin } FillAssemblyRefTable(); - ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, unmanagedResources, default, streamOrNull); + ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, nativeResources, default, streamOrNull); } public void __AddAssemblyReference(AssemblyName assemblyName) diff --git a/src/IKVM.Reflection/Writer/ResourceSection.cs b/src/IKVM.Reflection/Writer/ModuleResourceSectionBuilder.cs similarity index 52% rename from src/IKVM.Reflection/Writer/ResourceSection.cs rename to src/IKVM.Reflection/Writer/ModuleResourceSectionBuilder.cs index 9e5c326988..cfbb82cd90 100644 --- a/src/IKVM.Reflection/Writer/ResourceSection.cs +++ b/src/IKVM.Reflection/Writer/ModuleResourceSectionBuilder.cs @@ -1,36 +1,18 @@ -/* - Copyright (C) 2010-2012 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; using System.Collections.Generic; using System.IO; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; using IKVM.Reflection.Reader; namespace IKVM.Reflection.Writer { - sealed class ResourceSection + /// + /// Implements a for writing IKVM reflection resource section data. + /// + class ModuleResourceSectionBuilder : ResourceSectionBuilder { const int RT_ICON = 3; @@ -38,15 +20,42 @@ sealed class ResourceSection const int RT_VERSION = 16; const int RT_MANIFEST = 24; - ResourceDirectoryEntry root = new ResourceDirectoryEntry(new OrdinalOrName("root")); - ByteBuffer bb; - List linkOffsets; + readonly ResourceDirectoryEntry root; + /// + /// Initializes a new instance. + /// + public ModuleResourceSectionBuilder() + { + root = new ResourceDirectoryEntry(new OrdinalOrName("root")); + } + + /// + /// Initializes a new instance, importing the resources from the specified builder. + /// + /// + public ModuleResourceSectionBuilder(ModuleResourceSectionBuilder other) + { + if (other is null) + throw new ArgumentNullException(nameof(other)); + + root = new ResourceDirectoryEntry(other.root); + } + + /// + /// Adds a VersionInfo structure. + /// + /// internal void AddVersionInfo(ByteBuffer versionInfo) { - root[new OrdinalOrName(RT_VERSION)][new OrdinalOrName(1)][new OrdinalOrName(0)].Data = versionInfo; + root[new OrdinalOrName(RT_VERSION)][new OrdinalOrName(1)][new OrdinalOrName(0)].data = versionInfo; } + /// + /// Adds a Win32 ICO file. + /// + /// + /// internal void AddIcon(byte[] iconFile) { var br = new BinaryReader(new MemoryStream(iconFile)); @@ -85,18 +94,27 @@ internal void AddIcon(byte[] iconFile) var icon = new byte[dwBytesInRes]; Buffer.BlockCopy(iconFile, (int)dwImageOffset, icon, 0, icon.Length); - root[new OrdinalOrName(RT_ICON)][new OrdinalOrName(id)][new OrdinalOrName(0)].Data = ByteBuffer.Wrap(icon); + root[new OrdinalOrName(RT_ICON)][new OrdinalOrName(id)][new OrdinalOrName(0)].data = ByteBuffer.Wrap(icon); } - root[new OrdinalOrName(RT_GROUP_ICON)][new OrdinalOrName(32512)][new OrdinalOrName(0)].Data = group; + root[new OrdinalOrName(RT_GROUP_ICON)][new OrdinalOrName(32512)][new OrdinalOrName(0)].data = group; } + /// + /// Adds the native manifest. + /// + /// + /// internal void AddManifest(byte[] manifest, ushort resourceID) { - root[new OrdinalOrName(RT_MANIFEST)][new OrdinalOrName(resourceID)][new OrdinalOrName(0)].Data = ByteBuffer.Wrap(manifest); + root[new OrdinalOrName(RT_MANIFEST)][new OrdinalOrName(resourceID)][new OrdinalOrName(0)].data = ByteBuffer.Wrap(manifest); } - internal void ExtractResources(byte[] buf) + /// + /// Imports the resources from the specified Win32 resource file. + /// + /// + internal void ImportWin32ResourceFile(byte[] buf) { var br = new ByteReader(buf, 0, buf.Length); while (br.Length >= 32) @@ -104,24 +122,24 @@ internal void ExtractResources(byte[] buf) br.Align(4); var hdr = new RESOURCEHEADER(br); if (hdr.DataSize != 0) - root[hdr.TYPE][hdr.NAME][new OrdinalOrName(hdr.LanguageId)].Data = ByteBuffer.Wrap(br.ReadBytes(hdr.DataSize)); + root[hdr.TYPE][hdr.NAME][new OrdinalOrName(hdr.LanguageId)].data = ByteBuffer.Wrap(br.ReadBytes(hdr.DataSize)); } } - internal void Finish() + /// + protected override void Serialize(BlobBuilder builder, SectionLocation location) { - if (bb != null) - throw new InvalidOperationException(); - - bb = new ByteBuffer(1024); - linkOffsets = new List(); + var bb = new ByteBuffer(1024); + var linkOffsets = new List(); root.Write(bb, linkOffsets); - root = null; - } - internal int Length - { - get { return bb.Length; } + foreach (int offset in linkOffsets) + { + bb.Position = offset; + bb.Write(bb.GetInt32AtCurrentPosition() + (int)location.RelativeVirtualAddress); + } + + builder.WriteBytes(bb.ToArray()); } } diff --git a/src/IKVM.Reflection/Writer/ModuleWriter.cs b/src/IKVM.Reflection/Writer/ModuleWriter.cs index 21fea05747..5df54eaae4 100644 --- a/src/IKVM.Reflection/Writer/ModuleWriter.cs +++ b/src/IKVM.Reflection/Writer/ModuleWriter.cs @@ -47,11 +47,11 @@ static class ModuleWriter /// /// /// - /// + /// /// - internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, MethodDefinitionHandle entryPointToken) + internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSectionBuilder nativeResources, MethodDefinitionHandle entryPointToken) { - WriteModule(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, null); + WriteModule(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPointToken, null); } /// @@ -63,10 +63,10 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IK /// /// /// - /// + /// /// /// - internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, MethodDefinitionHandle entryPointToken, Stream stream) + internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSectionBuilder nativeResources, MethodDefinitionHandle entryPointToken, Stream stream) { if (stream == null) { @@ -88,7 +88,7 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IK using (var fs = new FileStream(fileName, FileMode.Create)) { var entryPoint = entryPointToken.IsNil == false ? entryPointToken : default; - WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPoint, fs); + WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPoint, fs); } // if we're running on Mono, mark the module as executable by using a Mono private API extension @@ -98,7 +98,7 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IK else { var entryPoint = entryPointToken.IsNil == false ? entryPointToken : default; - WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPoint, stream); + WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPoint, stream); } } @@ -111,11 +111,11 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IK /// /// /// - /// + /// /// /// /// - static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder module, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, MethodDefinitionHandle entryPoint, Stream stream) + static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder module, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSectionBuilder nativeResources, MethodDefinitionHandle entryPoint, Stream stream) { module.ApplyUnmanagedExports(imageFileMachine); module.FixupMethodBodyTokens(); @@ -123,9 +123,6 @@ static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Re // for compatibility with Reflection.Emit, if there aren't any user strings, we add one module.Metadata.GetOrAddUserString(""); - if (resources != null) - resources.Finish(); - #if NETFRAMEWORK if (module.symbolWriter != null) { @@ -154,6 +151,7 @@ static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Re new MetadataRootBuilder(module.Metadata), module.ILStream, managedResources: module.ResourceStream, + nativeResources: nativeResources, strongNameSignatureSize: strongNameSignatureSize, entryPoint: entryPoint, flags: GetCorFlags(portableExecutableKind, keyPair), @@ -360,7 +358,7 @@ static byte[] GetSignature(StrongNameKeyPair keyPair, IEnumerable blobs, i { // sign the hash with the keypair using var rsa = keyPair.CreateRSA(); - var signature = rsa.SignHash(GetSHA1Hash(blobs), HashAlgorithmName.SHA1, RSASignaturePadding.Pss); + var signature = rsa.SignHash(GetSHA1Hash(blobs), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); Array.Reverse(signature); // check that our signature length matches diff --git a/src/IKVM.Reflection/Writer/OrdinalOrName.cs b/src/IKVM.Reflection/Writer/OrdinalOrName.cs index 295a9a2211..e6e681b4e5 100644 --- a/src/IKVM.Reflection/Writer/OrdinalOrName.cs +++ b/src/IKVM.Reflection/Writer/OrdinalOrName.cs @@ -26,40 +26,51 @@ Jeroen Frijters namespace IKVM.Reflection.Writer { - readonly struct OrdinalOrName + readonly record struct OrdinalOrName(ushort Ordinal, string Name) { - internal readonly ushort Ordinal; - internal readonly string Name; - /// /// Initializes a new instance. /// - /// - internal OrdinalOrName(ushort value) + /// + internal OrdinalOrName(ushort ordinal) : + this(ordinal, null) { - Ordinal = value; - Name = null; + } /// /// Initializes a new instance. /// - /// - internal OrdinalOrName(string value) + /// + internal OrdinalOrName(string name) : + this(0xFFFF, name) { - Ordinal = 0xFFFF; - Name = value; + } + /// + /// Returns whether or not this ordinal is greater than the other ordinal. + /// + /// + /// internal readonly bool IsGreaterThan(OrdinalOrName other) { - return Name == null ? Ordinal > other.Ordinal : string.Compare(Name, other.Name, StringComparison.OrdinalIgnoreCase) > 0; + if (Name != null) + return StringComparer.OrdinalIgnoreCase.Compare(Name, other.Name) > 0; + else + return Ordinal > other.Ordinal; + } + + public readonly bool Equals(OrdinalOrName other) + { + return Ordinal == other.Ordinal && StringComparer.OrdinalIgnoreCase.Equals(Name, other.Name); } - internal readonly bool IsEqual(OrdinalOrName other) + /// + public override readonly int GetHashCode() { - return Name == null ? Ordinal == other.Ordinal : String.Compare(this.Name, other.Name, StringComparison.OrdinalIgnoreCase) == 0; + return Ordinal.GetHashCode() ^ StringComparer.OrdinalIgnoreCase.GetHashCode(Name); } } diff --git a/src/IKVM.Reflection/Writer/ResourceDirectoryEntry.cs b/src/IKVM.Reflection/Writer/ResourceDirectoryEntry.cs index 28027b2db1..f5f681719d 100644 --- a/src/IKVM.Reflection/Writer/ResourceDirectoryEntry.cs +++ b/src/IKVM.Reflection/Writer/ResourceDirectoryEntry.cs @@ -21,7 +21,9 @@ Jeroen Frijters jeroen@frijters.net */ +using System; using System.Collections.Generic; +using System.Linq; namespace IKVM.Reflection.Writer { @@ -29,35 +31,55 @@ namespace IKVM.Reflection.Writer sealed class ResourceDirectoryEntry { - internal readonly OrdinalOrName OrdinalOrName; - internal ByteBuffer Data; - int namedEntries; - readonly List entries = new List(); + internal readonly OrdinalOrName ordinalOrName; + internal readonly List entries = new(); + internal int namedEntries; + + internal ByteBuffer data; /// /// Initializes a new instance. /// + /// + internal ResourceDirectoryEntry(OrdinalOrName ordinalOrName) + { + this.ordinalOrName = ordinalOrName; + } + + /// + /// Initializes a new instance as a copy of the specified instance. + /// /// - internal ResourceDirectoryEntry(OrdinalOrName id) + internal ResourceDirectoryEntry(ResourceDirectoryEntry other) { - this.OrdinalOrName = id; + if (other is null) + throw new ArgumentNullException(nameof(other)); + + this.ordinalOrName = other.ordinalOrName; + this.entries = other.entries.Select(i => new ResourceDirectoryEntry(i)).ToList(); + this.namedEntries = other.namedEntries; } + /// + /// Gets the directory entry specified by the given ID. + /// + /// + /// internal ResourceDirectoryEntry this[OrdinalOrName id] { get { foreach (var entry in entries) - if (entry.OrdinalOrName.IsEqual(id)) + if (entry.ordinalOrName.Equals(id)) return entry; // the entries must be sorted var newEntry = new ResourceDirectoryEntry(id); if (id.Name == null) { - for (int i = namedEntries; i < entries.Count; i++) + for (var i = namedEntries; i < entries.Count; i++) { - if (entries[i].OrdinalOrName.IsGreaterThan(id)) + if (entries[i].ordinalOrName.IsGreaterThan(id)) { entries.Insert(i, newEntry); return newEntry; @@ -71,7 +93,7 @@ internal ResourceDirectoryEntry this[OrdinalOrName id] { for (int i = 0; i < namedEntries; i++) { - if (entries[i].OrdinalOrName.IsGreaterThan(id)) + if (entries[i].ordinalOrName.IsGreaterThan(id)) { entries.Insert(i, newEntry); namedEntries++; @@ -85,11 +107,11 @@ internal ResourceDirectoryEntry this[OrdinalOrName id] } } - private int DirectoryLength + int DirectoryLength { get { - if (Data != null) + if (data != null) { return 16; } @@ -127,16 +149,16 @@ internal void Write(ByteBuffer bb, List linkOffsets) void WriteResourceDataEntries(ByteBuffer bb, List linkOffsets, ref int offset) { - foreach (ResourceDirectoryEntry entry in entries) + foreach (var entry in entries) { - if (entry.Data != null) + if (entry.data != null) { linkOffsets.Add(bb.Position); bb.Write(offset); - bb.Write(entry.Data.Length); + bb.Write(entry.data.Length); bb.Write(0); // code page bb.Write(0); // reserved - offset += (entry.Data.Length + 3) & ~3; + offset += (entry.data.Length + 3) & ~3; } else { @@ -149,9 +171,9 @@ void WriteData(ByteBuffer bb) { foreach (var entry in entries) { - if (entry.Data != null) + if (entry.data != null) { - bb.Write(entry.Data); + bb.Write(entry.data); bb.Align(4); } else @@ -184,8 +206,8 @@ void Write(ByteBuffer bb, int writeDepth, int currentDepth, ref int offset, Dict void WriteEntry(ByteBuffer bb, ref int offset, Dictionary strings, ref int stringTableOffset, ByteBuffer stringTable) { - WriteNameOrOrdinal(bb, OrdinalOrName, strings, ref stringTableOffset, stringTable); - if (Data == null) + WriteNameOrOrdinal(bb, ordinalOrName, strings, ref stringTableOffset, stringTable); + if (data == null) bb.Write(0x80000000U | (uint)offset); else bb.Write(offset); diff --git a/src/IKVM.Tools.Importer/IkvmImporterInternal.cs b/src/IKVM.Tools.Importer/IkvmImporterInternal.cs index 0d7c4378cb..e407325eb6 100644 --- a/src/IKVM.Tools.Importer/IkvmImporterInternal.cs +++ b/src/IKVM.Tools.Importer/IkvmImporterInternal.cs @@ -228,27 +228,29 @@ static void loader_Warning(StaticCompiler compiler, AssemblyResolver.WarningId w static void ResolveStrongNameKeys(List targets) { - foreach (CompilerOptions options in targets) + foreach (var options in targets) { if (options.keyfile != null && options.keycontainer != null) - { throw new FatalCompilerErrorException(Message.CannotSpecifyBothKeyFileAndContainer); - } + if (options.keyfile == null && options.keycontainer == null && options.delaysign) - { throw new FatalCompilerErrorException(Message.DelaySignRequiresKey); - } + if (options.keyfile != null) { if (options.delaysign) { - byte[] buf = ReadAllBytes(options.keyfile); + var buf = ReadAllBytes(options.keyfile); try { // maybe it is a key pair, if so we need to extract just the public key buf = new StrongNameKeyPair(buf).PublicKey; } - catch { } + catch + { + + } + options.publicKey = buf; } else @@ -261,13 +263,9 @@ static void ResolveStrongNameKeys(List targets) StrongNameKeyPair keyPair = null; SetStrongNameKeyPair(ref keyPair, null, options.keycontainer); if (options.delaysign) - { options.publicKey = keyPair.PublicKey; - } else - { options.keyPair = keyPair; - } } } } @@ -1055,15 +1053,15 @@ static void SetStrongNameKeyPair(ref StrongNameKeyPair strongNameKeyPair, FileIn try { if (keyFile != null) - { strongNameKeyPair = new StrongNameKeyPair(ReadAllBytes(keyFile)); - } else - { strongNameKeyPair = new StrongNameKeyPair(keyContainer); - } + // FXBUG we explicitly try to access the public key force a check (the StrongNameKeyPair constructor doesn't validate the key) - if (strongNameKeyPair.PublicKey != null) { } + if (strongNameKeyPair.PublicKey != null) + { + + } } catch (Exception x) { From 1800b3b2b173c5e4ab84a5212f86d7978aae3857 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sun, 14 Jan 2024 13:41:15 -0600 Subject: [PATCH 07/10] Add win-arm64 support for NETFX. --- .../IKVM.Image.JDK.runtime.win-arm64.csproj | 1 - .../IKVM.Image.JDK.runtime.win-arm64.props | 5 +++++ .../IKVM.Image.JRE.runtime.win-arm64.csproj | 1 - .../IKVM.Image.JRE.runtime.win-arm64.props | 5 +++++ .../IKVM.Image.runtime.win-arm64.csproj | 1 - .../IKVM.Image.runtime.win-arm64.props | 5 +++++ src/IKVM.MSBuild.Tests/ProjectTests.cs | 4 ++++ .../IKVM.MSBuild.Tools.runtime.win-arm64.csproj | 16 ++++++++++++++++ .../IKVM.MSBuild.Tools.runtime.win-arm64.props | 2 ++ src/IKVM.NET.Sdk.Tests/ProjectTests.cs | 2 ++ src/IKVM.Tools.Tests/IKVM.Tools.Tests.csproj | 13 +++++++++++++ src/dist-image/dist-image.csproj | 1 + src/dist-tools/dist-tools.csproj | 1 + 13 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/IKVM.Image.JDK.runtime.win-arm64/IKVM.Image.JDK.runtime.win-arm64.csproj b/src/IKVM.Image.JDK.runtime.win-arm64/IKVM.Image.JDK.runtime.win-arm64.csproj index 2b57262371..7337df4c56 100644 --- a/src/IKVM.Image.JDK.runtime.win-arm64/IKVM.Image.JDK.runtime.win-arm64.csproj +++ b/src/IKVM.Image.JDK.runtime.win-arm64/IKVM.Image.JDK.runtime.win-arm64.csproj @@ -7,7 +7,6 @@ false win-arm64 ..\IKVM.Image.JDK-bin\IKVM.Image.JDK-bin.csproj - net6.0 diff --git a/src/IKVM.Image.JDK.runtime.win-arm64/buildTransitive/IKVM.Image.JDK.runtime.win-arm64.props b/src/IKVM.Image.JDK.runtime.win-arm64/buildTransitive/IKVM.Image.JDK.runtime.win-arm64.props index d893c696f4..ef06ff94ae 100644 --- a/src/IKVM.Image.JDK.runtime.win-arm64/buildTransitive/IKVM.Image.JDK.runtime.win-arm64.props +++ b/src/IKVM.Image.JDK.runtime.win-arm64/buildTransitive/IKVM.Image.JDK.runtime.win-arm64.props @@ -9,6 +9,11 @@ win-arm64 %(RecursiveDir)%(FileName)%(Extension) + + net472 + win-arm64 + %(RecursiveDir)%(FileName)%(Extension) + net6.0 win-arm64 diff --git a/src/IKVM.Image.JRE.runtime.win-arm64/IKVM.Image.JRE.runtime.win-arm64.csproj b/src/IKVM.Image.JRE.runtime.win-arm64/IKVM.Image.JRE.runtime.win-arm64.csproj index a038455964..4fa8b04522 100644 --- a/src/IKVM.Image.JRE.runtime.win-arm64/IKVM.Image.JRE.runtime.win-arm64.csproj +++ b/src/IKVM.Image.JRE.runtime.win-arm64/IKVM.Image.JRE.runtime.win-arm64.csproj @@ -7,7 +7,6 @@ false win-arm64 ..\IKVM.Image.JRE-bin\IKVM.Image.JRE-bin.csproj - net6.0 diff --git a/src/IKVM.Image.JRE.runtime.win-arm64/buildTransitive/IKVM.Image.JRE.runtime.win-arm64.props b/src/IKVM.Image.JRE.runtime.win-arm64/buildTransitive/IKVM.Image.JRE.runtime.win-arm64.props index d893c696f4..ef06ff94ae 100644 --- a/src/IKVM.Image.JRE.runtime.win-arm64/buildTransitive/IKVM.Image.JRE.runtime.win-arm64.props +++ b/src/IKVM.Image.JRE.runtime.win-arm64/buildTransitive/IKVM.Image.JRE.runtime.win-arm64.props @@ -9,6 +9,11 @@ win-arm64 %(RecursiveDir)%(FileName)%(Extension) + + net472 + win-arm64 + %(RecursiveDir)%(FileName)%(Extension) + net6.0 win-arm64 diff --git a/src/IKVM.Image.runtime.win-arm64/IKVM.Image.runtime.win-arm64.csproj b/src/IKVM.Image.runtime.win-arm64/IKVM.Image.runtime.win-arm64.csproj index b05f7ec8bb..4bd54a3ce8 100644 --- a/src/IKVM.Image.runtime.win-arm64/IKVM.Image.runtime.win-arm64.csproj +++ b/src/IKVM.Image.runtime.win-arm64/IKVM.Image.runtime.win-arm64.csproj @@ -7,7 +7,6 @@ false win-arm64 ..\IKVM.Image-bin\IKVM.Image-bin.csproj - net6.0 diff --git a/src/IKVM.Image.runtime.win-arm64/buildTransitive/IKVM.Image.runtime.win-arm64.props b/src/IKVM.Image.runtime.win-arm64/buildTransitive/IKVM.Image.runtime.win-arm64.props index d893c696f4..ef06ff94ae 100644 --- a/src/IKVM.Image.runtime.win-arm64/buildTransitive/IKVM.Image.runtime.win-arm64.props +++ b/src/IKVM.Image.runtime.win-arm64/buildTransitive/IKVM.Image.runtime.win-arm64.props @@ -9,6 +9,11 @@ win-arm64 %(RecursiveDir)%(FileName)%(Extension) + + net472 + win-arm64 + %(RecursiveDir)%(FileName)%(Extension) + net6.0 win-arm64 diff --git a/src/IKVM.MSBuild.Tests/ProjectTests.cs b/src/IKVM.MSBuild.Tests/ProjectTests.cs index bcb6d83104..f1cd5cac4b 100644 --- a/src/IKVM.MSBuild.Tests/ProjectTests.cs +++ b/src/IKVM.MSBuild.Tests/ProjectTests.cs @@ -143,8 +143,10 @@ public static void ClassCleanup() [DataTestMethod] [DataRow(EnvironmentPreference.Core, "net472", "win-x86", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Core, "net472", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Core, "net472", "win-arm64", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Core, "net48", "win-x86", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Core, "net48", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Core, "net48", "win-arm64", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Core, "net6.0", "win-x86", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Core, "net6.0", "win-x64", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Core, "net6.0", "win-arm64", "{0}.exe", "{0}.dll")] @@ -169,8 +171,10 @@ public static void ClassCleanup() [DataRow(EnvironmentPreference.Core, "net7.0", "osx-arm64", "{0}", "lib{0}.dylib")] [DataRow(EnvironmentPreference.Framework, "net472", "win-x86", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Framework, "net472", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net472", "win-arm64", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Framework, "net48", "win-x86", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Framework, "net48", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Framework, "net48", "win-arm64", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Framework, "net6.0", "win-x86", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Framework, "net6.0", "win-x64", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Framework, "net6.0", "win-arm64", "{0}.exe", "{0}.dll")] diff --git a/src/IKVM.MSBuild.Tools.runtime.win-arm64/IKVM.MSBuild.Tools.runtime.win-arm64.csproj b/src/IKVM.MSBuild.Tools.runtime.win-arm64/IKVM.MSBuild.Tools.runtime.win-arm64.csproj index 2a57df666e..1ecae57aea 100644 --- a/src/IKVM.MSBuild.Tools.runtime.win-arm64/IKVM.MSBuild.Tools.runtime.win-arm64.csproj +++ b/src/IKVM.MSBuild.Tools.runtime.win-arm64/IKVM.MSBuild.Tools.runtime.win-arm64.csproj @@ -15,6 +15,22 @@ + + TargetFramework=net472 + RuntimeIdentifier=win-arm64 + ikvmc\net472\win-arm64 + PreserveNewest + ikvmc\net472\win-arm64 + true + + + TargetFramework=net472 + RuntimeIdentifier=win-arm64 + ikvmstub\net472\win-arm64\bin + PreserveNewest + ikvmstub\net472\win-arm64 + true + TargetFramework=net6.0 RuntimeIdentifier=win-arm64 diff --git a/src/IKVM.MSBuild.Tools.runtime.win-arm64/buildTransitive/IKVM.MSBuild.Tools.runtime.win-arm64.props b/src/IKVM.MSBuild.Tools.runtime.win-arm64/buildTransitive/IKVM.MSBuild.Tools.runtime.win-arm64.props index 1db7dc3544..3227a46261 100644 --- a/src/IKVM.MSBuild.Tools.runtime.win-arm64/buildTransitive/IKVM.MSBuild.Tools.runtime.win-arm64.props +++ b/src/IKVM.MSBuild.Tools.runtime.win-arm64/buildTransitive/IKVM.MSBuild.Tools.runtime.win-arm64.props @@ -4,7 +4,9 @@ + + diff --git a/src/IKVM.NET.Sdk.Tests/ProjectTests.cs b/src/IKVM.NET.Sdk.Tests/ProjectTests.cs index 8a0fc170b6..e9e9e5db54 100644 --- a/src/IKVM.NET.Sdk.Tests/ProjectTests.cs +++ b/src/IKVM.NET.Sdk.Tests/ProjectTests.cs @@ -136,8 +136,10 @@ public static void ClassCleanup() [DataTestMethod] [DataRow(EnvironmentPreference.Core, "net472", "win-x86", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Core, "net472", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Core, "net472", "win-arm64", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Core, "net48", "win-x86", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Core, "net48", "win-x64", "{0}.exe", "{0}.dll")] + [DataRow(EnvironmentPreference.Core, "net48", "win-arm64", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Core, "net6.0", "win-x86", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Core, "net6.0", "win-x64", "{0}.exe", "{0}.dll")] [DataRow(EnvironmentPreference.Core, "net6.0", "win-arm64", "{0}.exe", "{0}.dll")] diff --git a/src/IKVM.Tools.Tests/IKVM.Tools.Tests.csproj b/src/IKVM.Tools.Tests/IKVM.Tools.Tests.csproj index 05527c4655..d73c82b683 100644 --- a/src/IKVM.Tools.Tests/IKVM.Tools.Tests.csproj +++ b/src/IKVM.Tools.Tests/IKVM.Tools.Tests.csproj @@ -73,6 +73,19 @@ PreserveNewest + + TargetFramework=net472 + RuntimeIdentifier=win-arm64 + ikvmc\net472\win-arm64 + PreserveNewest + + + TargetFramework=net472 + RuntimeIdentifier=win-arm64 + ikvmstub\net472\win-arm64 + PreserveNewest + + TargetFramework=net6.0 RuntimeIdentifier=win-arm64 diff --git a/src/dist-image/dist-image.csproj b/src/dist-image/dist-image.csproj index 4d3b1511bf..d2867afdac 100644 --- a/src/dist-image/dist-image.csproj +++ b/src/dist-image/dist-image.csproj @@ -11,6 +11,7 @@ + diff --git a/src/dist-tools/dist-tools.csproj b/src/dist-tools/dist-tools.csproj index 390fb772d9..120563f7af 100644 --- a/src/dist-tools/dist-tools.csproj +++ b/src/dist-tools/dist-tools.csproj @@ -9,6 +9,7 @@ + From a16a571c9c9206be414a35c5d25d75f5ab3a4a9c Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sun, 14 Jan 2024 17:42:24 -0600 Subject: [PATCH 08/10] Fix tests. Adjust headers. --- .../ModuleWriterTests.cs | 58 ++++++ src/IKVM.Reflection/Emit/AssemblyBuilder.cs | 24 +-- src/IKVM.Reflection/Emit/ModuleBuilder.cs | 29 +-- src/IKVM.Reflection/ImageFileMachine.cs | 1 + src/IKVM.Reflection/Module.cs | 24 +-- src/IKVM.Reflection/Reader/AssemblyReader.cs | 33 +--- src/IKVM.Reflection/Reader/ModuleReader.cs | 20 +- src/IKVM.Reflection/Universe.cs | 2 +- src/IKVM.Reflection/Writer/ModuleWriter.cs | 184 ++++++++++++++++-- src/IKVM.Tests/IKVM.Tests.csproj | 1 + src/IKVM.Tests/JNI/JniTests.cs | 2 +- .../Java/java/io/SerializableTests.cs | 2 +- src/IKVM.Tests/Java/java/lang/ClassTests.cs | 1 + .../Java/java/lang/ExceptionTests.cs | 2 +- .../Java/java/lang/ThrowableTests.cs | 2 +- .../lang/annotation/TypeAnnotationTests.cs | 2 +- .../java/lang/reflect/MethodInvokeTests.cs | 2 +- .../Java/javax/tools/JavaCompilerTests.cs | 2 +- .../Runtime/DefaultInterfaceMethodTests.cs | 2 +- .../CompilerClassLoader.cs | 4 +- .../IkvmImporterInternal.cs | 111 ++++------- 21 files changed, 323 insertions(+), 185 deletions(-) diff --git a/src/IKVM.Reflection.Tests/ModuleWriterTests.cs b/src/IKVM.Reflection.Tests/ModuleWriterTests.cs index 4c1a0f1aa2..b2027025d4 100644 --- a/src/IKVM.Reflection.Tests/ModuleWriterTests.cs +++ b/src/IKVM.Reflection.Tests/ModuleWriterTests.cs @@ -400,6 +400,64 @@ public void CanWriteWin32Icon(FrameworkSpec framework) var a = tempLoad.LoadFromAssemblyPath(Path.Combine(tempPath, "Test.dll")); } + [Theory] + [MemberData(nameof(FrameworkSpec.GetFrameworkTestData), MemberType = typeof(FrameworkSpec))] + public void CanWriteConsoleApplication(FrameworkSpec framework) + { + if (Init(framework, out var universe, out var resolver, out var verifier, out var tempPath, out var tempLoad) == false) + return; + + var assembly = universe.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save, tempPath); + var module = assembly.DefineDynamicModule("Test", "Test.exe", false); + var type = module.DefineType("Type"); + + var mainMethod = type.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, universe.Import(typeof(void)), new[] { universe.Import(typeof(string[])) }); + var mainMethodIL = mainMethod.GetILGenerator(); + mainMethodIL.Emit(OpCodes.Ret); + assembly.SetEntryPoint(mainMethod, PEFileKinds.ConsoleApplication); + + type.CreateType(); + assembly.Save("Test.exe", PortableExecutableKinds.ILOnly | PortableExecutableKinds.PE32Plus, ImageFileMachine.AMD64); + + foreach (var v in verifier.Verify(new PEReader(File.OpenRead(Path.Combine(tempPath, "Test.exe"))))) + v.Code.Should().Be(ILVerify.VerifierError.None); + + var a = tempLoad.LoadFromAssemblyPath(Path.Combine(tempPath, "Test.exe")); + a.GetName().Name.Should().Be("Test"); + a.GetModule("Test").Should().NotBeNull(); + var t = a.GetType("Type"); + t.Should().HaveMethod("Main", new[] { tempLoad.CoreAssembly.GetType("System.String").MakeArrayType() }).Which.Should().Return(tempLoad.CoreAssembly.GetType("System.Void")); + } + + [Theory] + [MemberData(nameof(FrameworkSpec.GetFrameworkTestData), MemberType = typeof(FrameworkSpec))] + public void CanWriteWindowsApplication(FrameworkSpec framework) + { + if (Init(framework, out var universe, out var resolver, out var verifier, out var tempPath, out var tempLoad) == false) + return; + + var assembly = universe.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save, tempPath); + var module = assembly.DefineDynamicModule("Test", "Test.exe", false); + var type = module.DefineType("Type"); + + var mainMethod = type.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, universe.Import(typeof(void)), new[] { universe.Import(typeof(string[])) }); + var mainMethodIL = mainMethod.GetILGenerator(); + mainMethodIL.Emit(OpCodes.Ret); + assembly.SetEntryPoint(mainMethod, PEFileKinds.WindowApplication); + + type.CreateType(); + assembly.Save("Test.exe", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64); + + foreach (var v in verifier.Verify(new PEReader(File.OpenRead(Path.Combine(tempPath, "Test.exe"))))) + v.Code.Should().Be(ILVerify.VerifierError.None); + + var a = tempLoad.LoadFromAssemblyPath(Path.Combine(tempPath, "Test.exe")); + a.GetName().Name.Should().Be("Test"); + a.GetModule("Test").Should().NotBeNull(); + var t = a.GetType("Type"); + t.Should().HaveMethod("Main", new[] { tempLoad.CoreAssembly.GetType("System.String").MakeArrayType() }).Which.Should().Return(tempLoad.CoreAssembly.GetType("System.Void")); + } + } } diff --git a/src/IKVM.Reflection/Emit/AssemblyBuilder.cs b/src/IKVM.Reflection/Emit/AssemblyBuilder.cs index d1533663fe..6040857826 100644 --- a/src/IKVM.Reflection/Emit/AssemblyBuilder.cs +++ b/src/IKVM.Reflection/Emit/AssemblyBuilder.cs @@ -110,12 +110,12 @@ internal AssemblyBuilder(Universe universe, AssemblyName name, string dir, IEnum { this.culture = name.CultureName; } + this.flags = name.RawFlags; this.hashAlgorithm = name.HashAlgorithm; if (this.hashAlgorithm == AssemblyHashAlgorithm.None) - { this.hashAlgorithm = AssemblyHashAlgorithm.SHA1; - } + this.keyPair = name.KeyPair; if (this.keyPair != null) { @@ -123,25 +123,20 @@ internal AssemblyBuilder(Universe universe, AssemblyName name, string dir, IEnum } else { - byte[] publicKey = name.GetPublicKey(); + var publicKey = name.GetPublicKey(); if (publicKey != null && publicKey.Length != 0) - { this.publicKey = (byte[])publicKey.Clone(); - } } + this.dir = dir ?? "."; if (customAttributes != null) - { this.customAttributes.AddRange(customAttributes); - } + if (universe.HasCoreLib && !universe.CoreLib.__IsMissing && universe.CoreLib.ImageRuntimeVersion != null) - { this.imageRuntimeVersion = universe.CoreLib.ImageRuntimeVersion; - } else - { this.imageRuntimeVersion = TypeUtil.GetAssembly(typeof(object)).ImageRuntimeVersion; - } + universe.RegisterDynamicAssembly(this); } @@ -468,13 +463,8 @@ void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKi module.ExportTypes(fileToken, manifestModule); } - // start with an empty entry point - var entryPointToken = MetadataTokens.MethodDefinitionHandle(0); - if (entryPoint != null) - entryPointToken = (MethodDefinitionHandle)MetadataTokens.EntityHandle(entryPoint.MetadataToken); - // finally, write the manifest module - ModuleWriter.WriteModule(keyPair, publicKey, manifestModule, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPointToken, streamOrNull); + ModuleWriter.WriteModule(keyPair, publicKey, manifestModule, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPoint, streamOrNull); } AssemblyFileHandle AddFile(ModuleBuilder manifestModule, string fileName, int flags) diff --git a/src/IKVM.Reflection/Emit/ModuleBuilder.cs b/src/IKVM.Reflection/Emit/ModuleBuilder.cs index fdf6ebd1a0..c61161208b 100644 --- a/src/IKVM.Reflection/Emit/ModuleBuilder.cs +++ b/src/IKVM.Reflection/Emit/ModuleBuilder.cs @@ -211,9 +211,9 @@ public bool Equals(MethodSpecKey other) readonly AssemblyBuilder asm; Guid mvid; uint timestamp; - long imageBaseAddress = 0x00400000; - long stackReserve = -1; - int fileAlignment = 0x200; + ulong imageBaseAddress = 0; + uint fileAlignment = 0; + ulong stackReserve = 0; DllCharacteristics dllCharacteristics = DllCharacteristics.DynamicBase | DllCharacteristics.NoSEH | DllCharacteristics.NXCompat | DllCharacteristics.TerminalServerAware; internal readonly string moduleName; internal readonly string fileName; @@ -1482,46 +1482,35 @@ internal BlobHandle GetSignatureBlobIndex(Signature sig) } // non-standard API - public new long __ImageBase + public new ulong __ImageBase { get { return imageBaseAddress; } set { imageBaseAddress = value; } } - protected override long GetImageBaseImpl() + protected override ulong GetImageBaseImpl() { return imageBaseAddress; } - public new long __StackReserve + public new ulong __StackReserve { get { return stackReserve; } set { stackReserve = value; } } - protected override long GetStackReserveImpl() + protected override ulong GetStackReserveImpl() { return stackReserve; } - [Obsolete("Use __StackReserve property.")] - public void __SetStackReserve(long stackReserve) - { - __StackReserve = stackReserve; - } - - internal ulong GetStackReserve(ulong defaultValue) - { - return stackReserve == -1 ? defaultValue : (ulong)stackReserve; - } - - public new int __FileAlignment + public new uint __FileAlignment { get { return fileAlignment; } set { fileAlignment = value; } } - protected override int GetFileAlignmentImpl() + protected override uint GetFileAlignmentImpl() { return fileAlignment; } diff --git a/src/IKVM.Reflection/ImageFileMachine.cs b/src/IKVM.Reflection/ImageFileMachine.cs index 6d74938560..79b992bfad 100644 --- a/src/IKVM.Reflection/ImageFileMachine.cs +++ b/src/IKVM.Reflection/ImageFileMachine.cs @@ -27,6 +27,7 @@ namespace IKVM.Reflection public enum ImageFileMachine { + UNKNOWN = 0, I386 = 332, ARM = 452, IA64 = 512, diff --git a/src/IKVM.Reflection/Module.cs b/src/IKVM.Reflection/Module.cs index 0668a67230..fd0299ad75 100644 --- a/src/IKVM.Reflection/Module.cs +++ b/src/IKVM.Reflection/Module.cs @@ -430,26 +430,20 @@ public virtual bool __IsMissing get { return false; } } - public long __ImageBase + public ulong __ImageBase { get { return GetImageBaseImpl(); } } - protected abstract long GetImageBaseImpl(); + protected abstract ulong GetImageBaseImpl(); - public long __StackReserve - { - get { return GetStackReserveImpl(); } - } + public ulong __StackReserve => GetStackReserveImpl(); - protected abstract long GetStackReserveImpl(); + protected abstract ulong GetStackReserveImpl(); - public int __FileAlignment - { - get { return GetFileAlignmentImpl(); } - } + public uint __FileAlignment => GetFileAlignmentImpl(); - protected abstract int GetFileAlignmentImpl(); + protected abstract uint GetFileAlignmentImpl(); public DllCharacteristics __DllCharacteristics { @@ -605,17 +599,17 @@ public override Type[] __GetExportedTypes() throw NotSupportedException(); } - protected sealed override long GetImageBaseImpl() + protected sealed override ulong GetImageBaseImpl() { throw NotSupportedException(); } - protected sealed override long GetStackReserveImpl() + protected sealed override ulong GetStackReserveImpl() { throw NotSupportedException(); } - protected sealed override int GetFileAlignmentImpl() + protected sealed override uint GetFileAlignmentImpl() { throw NotSupportedException(); } diff --git a/src/IKVM.Reflection/Reader/AssemblyReader.cs b/src/IKVM.Reflection/Reader/AssemblyReader.cs index b3379ffbe9..a426295869 100644 --- a/src/IKVM.Reflection/Reader/AssemblyReader.cs +++ b/src/IKVM.Reflection/Reader/AssemblyReader.cs @@ -73,23 +73,17 @@ AssemblyName GetNameImpl(ref AssemblyTable.Record rec) name.CodeBase = CodeBase; manifestModule.GetPEKind(out var peKind, out var machine); + switch (machine) { case ImageFileMachine.I386: // FXBUG we copy the .NET bug that Preferred32Bit implies x86 if ((peKind & (PortableExecutableKinds.Required32Bit | PortableExecutableKinds.Preferred32Bit)) != 0) - { name.ProcessorArchitecture = ProcessorArchitecture.X86; - } else if ((rec.Flags & 0x70) == 0x70) - { - // it's a reference assembly - name.ProcessorArchitecture = ProcessorArchitecture.None; - } + name.ProcessorArchitecture = ProcessorArchitecture.None; // it's a reference assembly else - { name.ProcessorArchitecture = ProcessorArchitecture.MSIL; - } break; case ImageFileMachine.IA64: name.ProcessorArchitecture = ProcessorArchitecture.IA64; @@ -104,6 +98,7 @@ AssemblyName GetNameImpl(ref AssemblyTable.Record rec) name.ProcessorArchitecture = ProcessorArchitecture.Arm64; break; } + name.RawFlags = (AssemblyNameFlags)rec.Flags; return name; } @@ -111,42 +106,32 @@ AssemblyName GetNameImpl(ref AssemblyTable.Record rec) public override Type[] GetTypes() { if (externalModules.Length == 0) - { return manifestModule.GetTypes(); - } - List list = new List(); - foreach (Module module in GetModules(false)) - { + var list = new List(); + foreach (var module in GetModules(false)) list.AddRange(module.GetTypes()); - } + return list.ToArray(); } internal override Type FindType(TypeName typeName) { - Type type = manifestModule.FindType(typeName); + var type = manifestModule.FindType(typeName); for (int i = 0; type == null && i < externalModules.Length; i++) - { if ((manifestModule.File.records[i].Flags & ContainsNoMetaData) == 0) - { type = GetModule(i).FindType(typeName); - } - } return type; } internal override Type FindTypeIgnoreCase(TypeName lowerCaseName) { - Type type = manifestModule.FindTypeIgnoreCase(lowerCaseName); + var type = manifestModule.FindTypeIgnoreCase(lowerCaseName); for (int i = 0; type == null && i < externalModules.Length; i++) - { if ((manifestModule.File.records[i].Flags & ContainsNoMetaData) == 0) - { type = GetModule(i).FindTypeIgnoreCase(lowerCaseName); - } - } + return type; } diff --git a/src/IKVM.Reflection/Reader/ModuleReader.cs b/src/IKVM.Reflection/Reader/ModuleReader.cs index 9b215566c6..27ea0e472c 100644 --- a/src/IKVM.Reflection/Reader/ModuleReader.cs +++ b/src/IKVM.Reflection/Reader/ModuleReader.cs @@ -1183,10 +1183,9 @@ public override void GetPEKind(out PortableExecutableKinds peKind, out ImageFile // (not setting any flag is ok) break; } + if (peFile.OptionalHeader.Magic == IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC) - { peKind |= PortableExecutableKinds.PE32Plus; - } machine = (ImageFileMachine)peFile.FileHeader.Machine; } @@ -1232,10 +1231,7 @@ public override IList __GetPlaceholderAssemblyCustomAttribu internal override void Dispose() { - if (stream != null) - { - stream.Dispose(); - } + stream?.Dispose(); } internal override void ExportTypes(AssemblyFileHandle fileToken, IKVM.Reflection.Emit.ModuleBuilder manifestModule) @@ -1244,19 +1240,19 @@ internal override void ExportTypes(AssemblyFileHandle fileToken, IKVM.Reflection manifestModule.ExportTypes(typeDefs, fileToken); } - protected override long GetImageBaseImpl() + protected override ulong GetImageBaseImpl() { - return (long)peFile.OptionalHeader.ImageBase; + return peFile.OptionalHeader.ImageBase; } - protected override long GetStackReserveImpl() + protected override ulong GetStackReserveImpl() { - return (long)peFile.OptionalHeader.SizeOfStackReserve; + return peFile.OptionalHeader.SizeOfStackReserve; } - protected override int GetFileAlignmentImpl() + protected override uint GetFileAlignmentImpl() { - return (int)peFile.OptionalHeader.FileAlignment; + return peFile.OptionalHeader.FileAlignment; } protected override DllCharacteristics GetDllCharacteristicsImpl() diff --git a/src/IKVM.Reflection/Universe.cs b/src/IKVM.Reflection/Universe.cs index d0959884b7..b7ba7909b4 100644 --- a/src/IKVM.Reflection/Universe.cs +++ b/src/IKVM.Reflection/Universe.cs @@ -737,7 +737,7 @@ public AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderA [Obsolete] public AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access, string dir, PermissionSet requiredPermissions, PermissionSet optionalPermissions, PermissionSet refusedPermissions) { - AssemblyBuilder ab = new AssemblyBuilder(this, name, dir, null); + var ab = new AssemblyBuilder(this, name, dir, null); AddLegacyPermissionSet(ab, requiredPermissions, System.Security.Permissions.SecurityAction.RequestMinimum); AddLegacyPermissionSet(ab, optionalPermissions, System.Security.Permissions.SecurityAction.RequestOptional); AddLegacyPermissionSet(ab, refusedPermissions, System.Security.Permissions.SecurityAction.RequestRefuse); diff --git a/src/IKVM.Reflection/Writer/ModuleWriter.cs b/src/IKVM.Reflection/Writer/ModuleWriter.cs index 5df54eaae4..603992585f 100644 --- a/src/IKVM.Reflection/Writer/ModuleWriter.cs +++ b/src/IKVM.Reflection/Writer/ModuleWriter.cs @@ -38,6 +38,29 @@ namespace IKVM.Reflection.Writer static class ModuleWriter { + const ulong DefaultExeBaseAddress32Bit = 0x00400000; + const ulong DefaultExeBaseAddress64Bit = 0x0000000140000000; + + const ulong DefaultDllBaseAddress32Bit = 0x10000000; + const ulong DefaultDllBaseAddress64Bit = 0x0000000180000000; + + const ulong DefaultSizeOfHeapReserve32Bit = 0x00100000; + const ulong DefaultSizeOfHeapReserve64Bit = 0x00400000; + + const ulong DefaultSizeOfHeapCommit32Bit = 0x1000; + const ulong DefaultSizeOfHeapCommit64Bit = 0x2000; + + const ulong DefaultSizeOfStackReserve32Bit = 0x00100000; + const ulong DefaultSizeOfStackReserve64Bit = 0x00400000; + + const ulong DefaultSizeOfStackCommit32Bit = 0x1000; + const ulong DefaultSizeOfStackCommit64Bit = 0x4000; + + const ushort DefaultFileAlignment32Bit = 0x200; + const ushort DefaultFileAlignment64Bit = 0x200; //both 32 and 64 bit binaries used this value in the native stack. + + const ushort DefaultSectionAlignment = 0x2000; + /// /// Writes the module specified by . /// @@ -48,10 +71,10 @@ static class ModuleWriter /// /// /// - /// - internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSectionBuilder nativeResources, MethodDefinitionHandle entryPointToken) + /// + internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSectionBuilder nativeResources, MethodInfo entryPoint) { - WriteModule(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPointToken, null); + WriteModule(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPoint, null); } /// @@ -64,9 +87,9 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IK /// /// /// - /// + /// /// - internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSectionBuilder nativeResources, MethodDefinitionHandle entryPointToken, Stream stream) + internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSectionBuilder nativeResources, MethodInfo entryPoint, Stream stream) { if (stream == null) { @@ -86,10 +109,7 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IK } using (var fs = new FileStream(fileName, FileMode.Create)) - { - var entryPoint = entryPointToken.IsNil == false ? entryPointToken : default; WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPoint, fs); - } // if we're running on Mono, mark the module as executable by using a Mono private API extension if (mono) @@ -97,7 +117,6 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IK } else { - var entryPoint = entryPointToken.IsNil == false ? entryPointToken : default; WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPoint, stream); } } @@ -115,7 +134,7 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IK /// /// /// - static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder module, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSectionBuilder nativeResources, MethodDefinitionHandle entryPoint, Stream stream) + static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder module, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSectionBuilder nativeResources, MethodInfo entryPoint, Stream stream) { module.ApplyUnmanagedExports(imageFileMachine); module.FixupMethodBodyTokens(); @@ -134,15 +153,30 @@ static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Re // write the module content WriteModuleImpl(module); + // are we outputing for a 64 bit architecture? + var is64BitArch = imageFileMachine is ImageFileMachine.AMD64 or ImageFileMachine.ARM64 or ImageFileMachine.IA64; + // initialize PE header builder var peHeaderBuilder = new PEHeaderBuilder( machine: GetMachine(imageFileMachine), - fileAlignment: module.__FileAlignment, - imageBase: (ulong)module.__ImageBase, + sectionAlignment: GetSectionAlignment(module, is64BitArch), + fileAlignment: GetFileAlignment(module, is64BitArch), + imageBase: GetImageBase(module, fileKind, is64BitArch), + majorLinkerVersion: 0x30, + minorLinkerVersion: 0, + majorOperatingSystemVersion: 4, + minorOperatingSystemVersion: 0, + majorImageVersion: 0, + minorImageVersion: 0, + majorSubsystemVersion: GetMajorSubsystemVersion(imageFileMachine, fileKind), + minorSubsystemVersion: GetMinorSubsystemVersion(imageFileMachine, fileKind), subsystem: GetSubsystem(fileKind), dllCharacteristics: (System.Reflection.PortableExecutable.DllCharacteristics)(int)module.__DllCharacteristics, imageCharacteristics: GetImageCharacteristics(imageFileMachine, fileKind), - sizeOfStackReserve: module.GetStackReserve(1048576)); + sizeOfStackReserve: GetSizeOfStackReserve(module, is64BitArch), + sizeOfStackCommit: GetSizeOfStackCommit(module, is64BitArch), + sizeOfHeapReserve: GetSizeOfHeapReserve(module, is64BitArch), + sizeOfHeapCommit: GetSizeOfHeapCommit(module, is64BitArch)); // initialize PE builder var strongNameSignatureSize = ComputeStrongNameSignatureLength(publicKey); @@ -153,7 +187,7 @@ static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Re managedResources: module.ResourceStream, nativeResources: nativeResources, strongNameSignatureSize: strongNameSignatureSize, - entryPoint: entryPoint, + entryPoint: entryPoint != null ? (MethodDefinitionHandle)MetadataTokens.EntityHandle(entryPoint.GetCurrentToken()) : default, flags: GetCorFlags(portableExecutableKind, keyPair), deterministicIdProvider: GetDeterministicIdProvider(module)); @@ -210,6 +244,7 @@ static Machine GetMachine(ImageFileMachine imageFileMachine) { return imageFileMachine switch { + ImageFileMachine.UNKNOWN => Machine.Unknown, ImageFileMachine.I386 => Machine.I386, ImageFileMachine.ARM => Machine.Arm, ImageFileMachine.AMD64 => Machine.Amd64, @@ -219,6 +254,73 @@ static Machine GetMachine(ImageFileMachine imageFileMachine) }; } + /// + /// Gets the appropriate section alignment for the image. + /// + /// + /// + /// + static int GetSectionAlignment(IKVM.Reflection.Emit.ModuleBuilder module, bool is64BitArch) + { + return DefaultSectionAlignment; + } + + /// + /// Gets the appropriate file alignment for the image. + /// + /// + /// + /// + static int GetFileAlignment(IKVM.Reflection.Emit.ModuleBuilder module, bool is64BitArch) + { + if (module.__FileAlignment == 0) + return is64BitArch ? DefaultFileAlignment64Bit : DefaultFileAlignment32Bit; + else + return (int)module.__FileAlignment; + } + + /// + /// Gets the base address of the image. + /// + /// + /// + /// + /// + /// + static ulong GetImageBase(IKVM.Reflection.Emit.ModuleBuilder module, IKVM.Reflection.Emit.PEFileKinds fileKind, bool is64BitArch) + { + var baseAddress = unchecked(module.__ImageBase + 0x8000) & (is64BitArch ? 0xffffffffffff0000 : 0x00000000ffff0000); + + // cover values smaller than 0x8000, overflow and default value 0): + if (baseAddress == 0) + { + if (fileKind is IKVM.Reflection.Emit.PEFileKinds.ConsoleApplication or IKVM.Reflection.Emit.PEFileKinds.WindowApplication) + return is64BitArch ? DefaultExeBaseAddress64Bit : DefaultExeBaseAddress32Bit; + else + return is64BitArch ? DefaultDllBaseAddress64Bit : DefaultDllBaseAddress32Bit; + } + + return baseAddress; + } + + /// + /// Gets the major subsystem verison. + /// + /// + static ushort GetMajorSubsystemVersion(ImageFileMachine imageFileMachine, IKVM.Reflection.Emit.PEFileKinds fileKinds) + { + return imageFileMachine == ImageFileMachine.ARM ? (ushort)6 : (ushort)4; + } + + /// + /// Gets the minor subsystem version. + /// + /// + static ushort GetMinorSubsystemVersion(ImageFileMachine imageFileMachine, IKVM.Reflection.Emit.PEFileKinds fileKinds) + { + return imageFileMachine == ImageFileMachine.ARM ? (ushort)2 : (ushort)0; + } + /// /// Obtains the appropriate value for a given . /// @@ -239,7 +341,7 @@ static Machine GetMachine(ImageFileMachine imageFileMachine) /// static Characteristics GetImageCharacteristics(ImageFileMachine imageFileMachine, IKVM.Reflection.Emit.PEFileKinds fileKind) { - var characteristics = default(Characteristics); + var characteristics = Characteristics.ExecutableImage; switch (imageFileMachine) { @@ -258,12 +360,60 @@ static Characteristics GetImageCharacteristics(ImageFileMachine imageFileMachine throw new ArgumentOutOfRangeException("imageFileMachine"); } - if (fileKind == IKVM.Reflection.Emit.PEFileKinds.Dll) - characteristics |= Characteristics.Dll; + switch (fileKind) + { + case IKVM.Reflection.Emit.PEFileKinds.Dll: + characteristics |= Characteristics.Dll; + break; + } return characteristics; } + /// + /// Gets the size of the stack reserve. + /// + /// + /// + /// + static ulong GetSizeOfStackReserve(IKVM.Reflection.Emit.ModuleBuilder module, bool is64BitArch) + { + return is64BitArch ? DefaultSizeOfStackReserve64Bit : DefaultSizeOfStackReserve32Bit; + } + + /// + /// Gets the size of the stack commit. + /// + /// + /// + /// + static ulong GetSizeOfStackCommit(IKVM.Reflection.Emit.ModuleBuilder module, bool is64BitArch) + { + return is64BitArch ? DefaultSizeOfStackCommit64Bit : DefaultSizeOfStackCommit32Bit; + } + + /// + /// Gets the size of the heap reserve. + /// + /// + /// + /// + static ulong GetSizeOfHeapReserve(IKVM.Reflection.Emit.ModuleBuilder module, bool is64BitArch) + { + return is64BitArch ? DefaultSizeOfHeapReserve64Bit : DefaultSizeOfHeapReserve32Bit; + } + + /// + /// Gets the size of the heap commit. + /// + /// + /// + /// + static ulong GetSizeOfHeapCommit(IKVM.Reflection.Emit.ModuleBuilder module, bool is64BitArch) + { + return is64BitArch ? DefaultSizeOfHeapCommit64Bit : DefaultSizeOfHeapCommit32Bit; + } + /// /// Obtains the appropriate value for the given and . /// diff --git a/src/IKVM.Tests/IKVM.Tests.csproj b/src/IKVM.Tests/IKVM.Tests.csproj index 96def1c349..69d2a485f6 100644 --- a/src/IKVM.Tests/IKVM.Tests.csproj +++ b/src/IKVM.Tests/IKVM.Tests.csproj @@ -35,6 +35,7 @@ + diff --git a/src/IKVM.Tests/JNI/JniTests.cs b/src/IKVM.Tests/JNI/JniTests.cs index 9ee45c8ea6..9bd11a0158 100644 --- a/src/IKVM.Tests/JNI/JniTests.cs +++ b/src/IKVM.Tests/JNI/JniTests.cs @@ -3,7 +3,7 @@ using FluentAssertions; -using IKVM.Tests.Util; +using IKVM.Java.Tests.Util; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/IKVM.Tests/Java/java/io/SerializableTests.cs b/src/IKVM.Tests/Java/java/io/SerializableTests.cs index 99845b832b..1f7e5fd40e 100644 --- a/src/IKVM.Tests/Java/java/io/SerializableTests.cs +++ b/src/IKVM.Tests/Java/java/io/SerializableTests.cs @@ -1,4 +1,4 @@ -using IKVM.Tests.Util; +using IKVM.Java.Tests.Util; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/IKVM.Tests/Java/java/lang/ClassTests.cs b/src/IKVM.Tests/Java/java/lang/ClassTests.cs index a86e1a0f44..e5e26d37ee 100644 --- a/src/IKVM.Tests/Java/java/lang/ClassTests.cs +++ b/src/IKVM.Tests/Java/java/lang/ClassTests.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; +using IKVM.Java.Tests.Util; using IKVM.Tests.Util; using java.nio.file; diff --git a/src/IKVM.Tests/Java/java/lang/ExceptionTests.cs b/src/IKVM.Tests/Java/java/lang/ExceptionTests.cs index d5cfac6d51..1bb1dce6a3 100644 --- a/src/IKVM.Tests/Java/java/lang/ExceptionTests.cs +++ b/src/IKVM.Tests/Java/java/lang/ExceptionTests.cs @@ -1,6 +1,6 @@ using FluentAssertions; -using IKVM.Tests.Util; +using IKVM.Java.Tests.Util; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/IKVM.Tests/Java/java/lang/ThrowableTests.cs b/src/IKVM.Tests/Java/java/lang/ThrowableTests.cs index 935273f56c..36a0bc1a3a 100644 --- a/src/IKVM.Tests/Java/java/lang/ThrowableTests.cs +++ b/src/IKVM.Tests/Java/java/lang/ThrowableTests.cs @@ -1,7 +1,7 @@ using System; using System.IO; -using IKVM.Tests.Util; +using IKVM.Java.Tests.Util; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/IKVM.Tests/Java/java/lang/annotation/TypeAnnotationTests.cs b/src/IKVM.Tests/Java/java/lang/annotation/TypeAnnotationTests.cs index 80fcf020a6..b9dfc3c654 100644 --- a/src/IKVM.Tests/Java/java/lang/annotation/TypeAnnotationTests.cs +++ b/src/IKVM.Tests/Java/java/lang/annotation/TypeAnnotationTests.cs @@ -3,7 +3,7 @@ using FluentAssertions; -using IKVM.Tests.Util; +using IKVM.Java.Tests.Util; using java.lang.reflect; diff --git a/src/IKVM.Tests/Java/java/lang/reflect/MethodInvokeTests.cs b/src/IKVM.Tests/Java/java/lang/reflect/MethodInvokeTests.cs index 8e433ad2f6..81dbab553f 100644 --- a/src/IKVM.Tests/Java/java/lang/reflect/MethodInvokeTests.cs +++ b/src/IKVM.Tests/Java/java/lang/reflect/MethodInvokeTests.cs @@ -2,7 +2,7 @@ using FluentAssertions; -using IKVM.Tests.Util; +using IKVM.Java.Tests.Util; using java.lang; diff --git a/src/IKVM.Tests/Java/javax/tools/JavaCompilerTests.cs b/src/IKVM.Tests/Java/javax/tools/JavaCompilerTests.cs index 0e21d3ca75..e03eaf67b8 100644 --- a/src/IKVM.Tests/Java/javax/tools/JavaCompilerTests.cs +++ b/src/IKVM.Tests/Java/javax/tools/JavaCompilerTests.cs @@ -1,6 +1,6 @@ using FluentAssertions; -using IKVM.Tests.Util; +using IKVM.Java.Tests.Util; using java.util; diff --git a/src/IKVM.Tests/Runtime/DefaultInterfaceMethodTests.cs b/src/IKVM.Tests/Runtime/DefaultInterfaceMethodTests.cs index 39a15993c8..5d2983c21a 100644 --- a/src/IKVM.Tests/Runtime/DefaultInterfaceMethodTests.cs +++ b/src/IKVM.Tests/Runtime/DefaultInterfaceMethodTests.cs @@ -1,6 +1,6 @@ using FluentAssertions; -using IKVM.Tests.Util; +using IKVM.Java.Tests.Util; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/IKVM.Tools.Importer/CompilerClassLoader.cs b/src/IKVM.Tools.Importer/CompilerClassLoader.cs index fdb27c758e..b95c9fe09e 100644 --- a/src/IKVM.Tools.Importer/CompilerClassLoader.cs +++ b/src/IKVM.Tools.Importer/CompilerClassLoader.cs @@ -3357,8 +3357,8 @@ sealed class CompilerOptions internal string classLoader; internal PortableExecutableKinds pekind = PortableExecutableKinds.ILOnly; internal ImageFileMachine imageFileMachine = ImageFileMachine.I386; - internal long baseAddress; - internal int fileAlignment; + internal ulong baseAddress; + internal uint fileAlignment; internal bool highentropyva; internal List sharedclassloader; // should *not* be deep copied in Copy(), because we want the list of all compilers that share a class loader internal Dictionary suppressWarnings = new Dictionary(); diff --git a/src/IKVM.Tools.Importer/IkvmImporterInternal.cs b/src/IKVM.Tools.Importer/IkvmImporterInternal.cs index e407325eb6..62cf96e800 100644 --- a/src/IKVM.Tools.Importer/IkvmImporterInternal.cs +++ b/src/IKVM.Tools.Importer/IkvmImporterInternal.cs @@ -404,10 +404,10 @@ void ParseCommandLine(RuntimeContext context, StaticCompiler compiler, IEnumerat void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, IEnumerator arglist, List targets, CompilerOptions options) { - List fileNames = new List(); + var fileNames = new List(); while (arglist.MoveNext()) { - string s = arglist.Current; + var s = arglist.Current; if (s == "{") { if (!nonleaf) @@ -494,11 +494,11 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I break; case "-platform:anycpu32bitpreferred": options.pekind = PortableExecutableKinds.ILOnly | PortableExecutableKinds.Preferred32Bit; - options.imageFileMachine = ImageFileMachine.I386; + options.imageFileMachine = ImageFileMachine.UNKNOWN; break; case "-platform:anycpu": options.pekind = PortableExecutableKinds.ILOnly; - options.imageFileMachine = ImageFileMachine.I386; + options.imageFileMachine = ImageFileMachine.UNKNOWN; break; default: throw new FatalCompilerErrorException(Message.UnrecognizedPlatform, s.Substring(10)); @@ -527,11 +527,10 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I } else if (s.StartsWith("-D")) { - string[] keyvalue = s.Substring(2).Split('='); + var keyvalue = s.Substring(2).Split('='); if (keyvalue.Length != 2) - { keyvalue = new string[] { keyvalue[0], "" }; - } + options.props[keyvalue[0]] = keyvalue[1]; } else if (s == "-ea" || s == "-enableassertions") @@ -560,7 +559,7 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I } else if (s.StartsWith("-reference:") || s.StartsWith("-r:")) { - string r = s.Substring(s.IndexOf(':') + 1); + var r = s.Substring(s.IndexOf(':') + 1); if (r == "") throw new FatalCompilerErrorException(Message.MissingFileSpecification, s); @@ -568,8 +567,9 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I } else if (s.StartsWith("-recurse:")) { - string spec = s.Substring(9); - bool exists = false; + var spec = s.Substring(9); + var exists = false; + // MONOBUG On Mono 1.0.2, Directory.Exists throws an exception if we pass an invalid directory name try { @@ -577,18 +577,20 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I } catch (IOException) { + } + bool found; if (exists) { - DirectoryInfo dir = new DirectoryInfo(spec); + var dir = new DirectoryInfo(spec); found = Recurse(context, compiler, options, dir, dir, "*"); } else { try { - DirectoryInfo dir = new DirectoryInfo(Path.GetDirectoryName(spec)); + var dir = new DirectoryInfo(Path.GetDirectoryName(spec)); if (dir.Exists) { found = Recurse(context, compiler, options, dir, dir, Path.GetFileName(spec)); @@ -611,10 +613,9 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I throw new FatalCompilerErrorException(Message.InvalidPath, spec); } } + if (!found) - { throw new FatalCompilerErrorException(Message.FileNotFound, spec); - } } else if (s.StartsWith("-resource:")) { @@ -628,24 +629,16 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I } else if (s.StartsWith("-externalresource:")) { - string[] spec = s.Substring(18).Split('='); + var spec = s.Substring(18).Split('='); if (spec.Length != 2) - { throw new FatalCompilerErrorException(Message.InvalidOptionSyntax, s); - } if (!File.Exists(spec[1])) - { throw new FatalCompilerErrorException(Message.ExternalResourceNotFound, spec[1]); - } if (Path.GetFileName(spec[1]) != spec[1]) - { throw new FatalCompilerErrorException(Message.ExternalResourceNameInvalid, spec[1]); - } - if (options.externalResources == null) - { - options.externalResources = new Dictionary(); - } + // TODO resource name clashes should be tested + options.externalResources ??= new Dictionary(); options.externalResources.Add(spec[0], spec[1]); } else if (s == "-nojni") @@ -658,11 +651,9 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I } else if (s.StartsWith("-version:")) { - string str = s.Substring(9); + var str = s.Substring(9); if (!TryParseVersion(s.Substring(9), out options.version)) - { throw new FatalCompilerErrorException(Message.InvalidVersionFormat, str); - } } else if (s.StartsWith("-fileversion:")) { @@ -719,24 +710,23 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I } else if (s.StartsWith("-privatepackage:")) { - string prefix = s.Substring(16); + var prefix = s.Substring(16); ArrayAppend(ref options.privatePackages, prefix); } else if (s.StartsWith("-publicpackage:")) { - string prefix = s.Substring(15); + var prefix = s.Substring(15); ArrayAppend(ref options.publicPackages, prefix); } else if (s.StartsWith("-nowarn:")) { - foreach (string w in s.Substring(8).Split(',')) + foreach (var w in s.Substring(8).Split(',')) { - string ws = w; // lame way to chop off the leading zeroes + string ws = w; while (ws.StartsWith("0")) - { ws = ws.Substring(1); - } + options.suppressWarnings[ws] = ws; } } @@ -748,12 +738,11 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I { foreach (string w in s.Substring(13).Split(',')) { - string ws = w; // lame way to chop off the leading zeroes + string ws = w; while (ws.StartsWith("0")) - { ws = ws.Substring(1); - } + options.errorWarnings[ws] = ws; } } @@ -772,36 +761,24 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I } else if (s == "-sharedclassloader") { - if (options.sharedclassloader == null) - { - options.sharedclassloader = new List(); - } + options.sharedclassloader ??= new List(); } else if (s.StartsWith("-baseaddress:")) { - string baseAddress = s.Substring(13); + var baseAddress = s.Substring(13); ulong baseAddressParsed; if (baseAddress.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) - { - baseAddressParsed = UInt64.Parse(baseAddress.Substring(2), System.Globalization.NumberStyles.AllowHexSpecifier); - } + baseAddressParsed = ulong.Parse(baseAddress.Substring(2), System.Globalization.NumberStyles.AllowHexSpecifier); else - { - // note that unlike CSC we don't support octal - baseAddressParsed = UInt64.Parse(baseAddress); - } - options.baseAddress = (long)(baseAddressParsed & 0xFFFFFFFFFFFF0000UL); + baseAddressParsed = ulong.Parse(baseAddress); // note that unlike CSC we don't support octal + + options.baseAddress = (baseAddressParsed & 0xFFFFFFFFFFFF0000UL); } else if (s.StartsWith("-filealign:")) { - int filealign; - if (!Int32.TryParse(s.Substring(11), out filealign) - || filealign < 512 - || filealign > 8192 - || (filealign & (filealign - 1)) != 0) - { + if (!uint.TryParse(s.Substring(11), out var filealign) || filealign < 512 || filealign > 8192 || (filealign & (filealign - 1)) != 0) throw new FatalCompilerErrorException(Message.InvalidFileAlignment, s.Substring(11)); - } + options.fileAlignment = filealign; } else if (s == "-nopeercrossreference") @@ -829,6 +806,7 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I else if (s.StartsWith("-writeSuppressWarningsFile:")) { options.writeSuppressWarningsFile = GetFileInfo(s.Substring(27)); + try { options.writeSuppressWarningsFile.Delete(); @@ -840,11 +818,10 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I } else if (s.StartsWith("-proxy:")) // currently undocumented! { - string proxy = s.Substring(7); + var proxy = s.Substring(7); if (options.proxies.Contains(proxy)) - { IssueMessage(compiler, Message.DuplicateProxy, proxy); - } + options.proxies.Add(proxy); } else if (s == "-nologo") @@ -904,29 +881,25 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I if (options.assembly == null) { - string basename = options.path == null ? defaultAssemblyName : options.path.Name; + var basename = options.path == null ? defaultAssemblyName : options.path.Name; if (basename == null) - { throw new FatalCompilerErrorException(Message.NoOutputFileSpecified); - } + int idx = basename.LastIndexOf('.'); if (idx > 0) - { options.assembly = basename.Substring(0, idx); - } else - { options.assembly = basename; - } } + if (options.path != null && options.guessFileKind) { if (options.path.Extension.Equals(".dll", StringComparison.OrdinalIgnoreCase)) - { options.target = PEFileKinds.Dll; - } + options.guessFileKind = false; } + if (options.mainClass == null && manifestMainClass != null && (options.guessFileKind || options.target != PEFileKinds.Dll)) { IssueMessage(compiler, options, Message.MainMethodFromManifest, manifestMainClass); From 1abb700305a5fda7581db9102931c753f5a61f1b Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sun, 14 Jan 2024 18:36:44 -0600 Subject: [PATCH 09/10] Don't include resource builder if no resources. --- src/IKVM.Java.Tests.Util/InMemoryCompiler.cs | 1 - src/IKVM.Reflection.Tests/ModuleWriterTests.cs | 8 +++++++- .../Writer/ModuleResourceSectionBuilder.cs | 5 +++++ src/IKVM.Reflection/Writer/ModuleWriter.cs | 10 ++++++---- src/IKVM.Reflection/Writer/ResourceDirectoryEntry.cs | 5 +++++ .../IKVM.Tools.Importer.Tests.csproj | 1 + src/IKVM.Tools.Importer.Tests/IkvmImporterTests.cs | 3 +++ 7 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/IKVM.Java.Tests.Util/InMemoryCompiler.cs b/src/IKVM.Java.Tests.Util/InMemoryCompiler.cs index c9b14f4a2d..647e1a9979 100644 --- a/src/IKVM.Java.Tests.Util/InMemoryCompiler.cs +++ b/src/IKVM.Java.Tests.Util/InMemoryCompiler.cs @@ -174,7 +174,6 @@ public override CharSequence getCharContent(bool ignoreEncodingErrors) public InMemoryCompiler(InMemoryCodeUnit[] source) { this.compiler = ToolProvider.getSystemJavaCompiler() ?? throw new System.Exception(); - this.units = source ?? throw new ArgumentNullException(nameof(source)); this.files = new InMemoryForwardingJavaFileManager(compiler.getStandardFileManager(null, null, null), streams); } diff --git a/src/IKVM.Reflection.Tests/ModuleWriterTests.cs b/src/IKVM.Reflection.Tests/ModuleWriterTests.cs index b2027025d4..73fd94e611 100644 --- a/src/IKVM.Reflection.Tests/ModuleWriterTests.cs +++ b/src/IKVM.Reflection.Tests/ModuleWriterTests.cs @@ -436,7 +436,13 @@ public void CanWriteWindowsApplication(FrameworkSpec framework) if (Init(framework, out var universe, out var resolver, out var verifier, out var tempPath, out var tempLoad) == false) return; + // obtain sample ico file + var ico = typeof(ModuleWriterTests).Assembly.GetManifestResourceStream("IKVM.Reflection.Tests.sample.ico"); + var buf = new byte[ico.Length]; + ico.Read(buf, 0, (int)ico.Length); + var assembly = universe.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save, tempPath); + assembly.__DefineIconResource(buf); var module = assembly.DefineDynamicModule("Test", "Test.exe", false); var type = module.DefineType("Type"); @@ -446,7 +452,7 @@ public void CanWriteWindowsApplication(FrameworkSpec framework) assembly.SetEntryPoint(mainMethod, PEFileKinds.WindowApplication); type.CreateType(); - assembly.Save("Test.exe", PortableExecutableKinds.ILOnly, ImageFileMachine.AMD64); + assembly.Save("Test.exe", PortableExecutableKinds.ILOnly | PortableExecutableKinds.PE32Plus, ImageFileMachine.AMD64); foreach (var v in verifier.Verify(new PEReader(File.OpenRead(Path.Combine(tempPath, "Test.exe"))))) v.Code.Should().Be(ILVerify.VerifierError.None); diff --git a/src/IKVM.Reflection/Writer/ModuleResourceSectionBuilder.cs b/src/IKVM.Reflection/Writer/ModuleResourceSectionBuilder.cs index cfbb82cd90..07f7b4ab15 100644 --- a/src/IKVM.Reflection/Writer/ModuleResourceSectionBuilder.cs +++ b/src/IKVM.Reflection/Writer/ModuleResourceSectionBuilder.cs @@ -42,6 +42,11 @@ public ModuleResourceSectionBuilder(ModuleResourceSectionBuilder other) root = new ResourceDirectoryEntry(other.root); } + /// + /// Gets the number of entries in the root of the builder. + /// + public int Count => root.Count; + /// /// Adds a VersionInfo structure. /// diff --git a/src/IKVM.Reflection/Writer/ModuleWriter.cs b/src/IKVM.Reflection/Writer/ModuleWriter.cs index 603992585f..ea00b01c71 100644 --- a/src/IKVM.Reflection/Writer/ModuleWriter.cs +++ b/src/IKVM.Reflection/Writer/ModuleWriter.cs @@ -72,7 +72,7 @@ static class ModuleWriter /// /// /// - internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSectionBuilder nativeResources, MethodInfo entryPoint) + internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ModuleResourceSectionBuilder nativeResources, MethodInfo entryPoint) { WriteModule(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPoint, null); } @@ -89,7 +89,7 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IK /// /// /// - internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSectionBuilder nativeResources, MethodInfo entryPoint, Stream stream) + internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder moduleBuilder, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ModuleResourceSectionBuilder nativeResources, MethodInfo entryPoint, Stream stream) { if (stream == null) { @@ -134,7 +134,7 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, IK /// /// /// - static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder module, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSectionBuilder nativeResources, MethodInfo entryPoint, Stream stream) + static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Reflection.Emit.ModuleBuilder module, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ModuleResourceSectionBuilder nativeResources, MethodInfo entryPoint, Stream stream) { module.ApplyUnmanagedExports(imageFileMachine); module.FixupMethodBodyTokens(); @@ -185,7 +185,7 @@ static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, IKVM.Re new MetadataRootBuilder(module.Metadata), module.ILStream, managedResources: module.ResourceStream, - nativeResources: nativeResources, + nativeResources: nativeResources.Count > 0 ? nativeResources : null, strongNameSignatureSize: strongNameSignatureSize, entryPoint: entryPoint != null ? (MethodDefinitionHandle)MetadataTokens.EntityHandle(entryPoint.GetCurrentToken()) : default, flags: GetCorFlags(portableExecutableKind, keyPair), @@ -345,6 +345,8 @@ static Characteristics GetImageCharacteristics(ImageFileMachine imageFileMachine switch (imageFileMachine) { + case ImageFileMachine.UNKNOWN: + break; case ImageFileMachine.I386: characteristics |= Characteristics.Bit32Machine; break; diff --git a/src/IKVM.Reflection/Writer/ResourceDirectoryEntry.cs b/src/IKVM.Reflection/Writer/ResourceDirectoryEntry.cs index f5f681719d..574310e975 100644 --- a/src/IKVM.Reflection/Writer/ResourceDirectoryEntry.cs +++ b/src/IKVM.Reflection/Writer/ResourceDirectoryEntry.cs @@ -60,6 +60,11 @@ internal ResourceDirectoryEntry(ResourceDirectoryEntry other) this.namedEntries = other.namedEntries; } + /// + /// Gets the number of entries added. + /// + public int Count => entries.Count; + /// /// Gets the directory entry specified by the given ID. /// diff --git a/src/IKVM.Tools.Importer.Tests/IKVM.Tools.Importer.Tests.csproj b/src/IKVM.Tools.Importer.Tests/IKVM.Tools.Importer.Tests.csproj index 1508b92c97..6305756282 100644 --- a/src/IKVM.Tools.Importer.Tests/IKVM.Tools.Importer.Tests.csproj +++ b/src/IKVM.Tools.Importer.Tests/IKVM.Tools.Importer.Tests.csproj @@ -18,6 +18,7 @@ + diff --git a/src/IKVM.Tools.Importer.Tests/IkvmImporterTests.cs b/src/IKVM.Tools.Importer.Tests/IkvmImporterTests.cs index ad8fb58e64..89805ffc1c 100644 --- a/src/IKVM.Tools.Importer.Tests/IkvmImporterTests.cs +++ b/src/IKVM.Tools.Importer.Tests/IkvmImporterTests.cs @@ -11,6 +11,9 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using IKVM.Java.Tests.Util; + + #if NETCOREAPP using Microsoft.Extensions.DependencyModel; #endif From 1dff3022dcb2d0efcc8ebfe1bef3d187437efe53 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sun, 14 Jan 2024 21:11:25 -0600 Subject: [PATCH 10/10] Delete unused files. --- src/IKVM.Reflection/Reader/ModuleReader.cs | 3 +- src/IKVM.Reflection/StrongNameKeyPair.cs | 6 +- .../Writer/IMAGE_FILE_HEADER.cs | 54 --- .../Writer/IMAGE_NT_HEADERS.cs | 38 -- .../Writer/IMAGE_OPTIONAL_HEADER.cs | 133 ------ src/IKVM.Reflection/Writer/SectionHeader.cs | 55 --- src/IKVM.Reflection/Writer/TextSection.cs | 415 ------------------ 7 files changed, 6 insertions(+), 698 deletions(-) delete mode 100644 src/IKVM.Reflection/Writer/IMAGE_FILE_HEADER.cs delete mode 100644 src/IKVM.Reflection/Writer/IMAGE_NT_HEADERS.cs delete mode 100644 src/IKVM.Reflection/Writer/IMAGE_OPTIONAL_HEADER.cs delete mode 100644 src/IKVM.Reflection/Writer/SectionHeader.cs delete mode 100644 src/IKVM.Reflection/Writer/TextSection.cs diff --git a/src/IKVM.Reflection/Reader/ModuleReader.cs b/src/IKVM.Reflection/Reader/ModuleReader.cs index 27ea0e472c..22b44e1371 100644 --- a/src/IKVM.Reflection/Reader/ModuleReader.cs +++ b/src/IKVM.Reflection/Reader/ModuleReader.cs @@ -1270,12 +1270,11 @@ public override int __EntryPointToken get { return (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0 ? (int)cliHeader.EntryPointToken : 0; } } -#if !NO_AUTHENTICODE public override System.Security.Cryptography.X509Certificates.X509Certificate GetSignerCertificate() { return Authenticode.GetSignerCertificate(GetStream()); } -#endif // !NO_AUTHENTICODE + } } diff --git a/src/IKVM.Reflection/StrongNameKeyPair.cs b/src/IKVM.Reflection/StrongNameKeyPair.cs index 2ebbd03cf9..36c2d72e3d 100644 --- a/src/IKVM.Reflection/StrongNameKeyPair.cs +++ b/src/IKVM.Reflection/StrongNameKeyPair.cs @@ -122,17 +122,21 @@ internal RSA CreateRSA() } else { +#if NETFRAMEWORK var parm = new CspParameters(); parm.KeyContainerName = keyPairContainer; // MONOBUG Mono doesn't like it when Flags or KeyNumber are set - if (!Universe.MonoRuntime) + if (Universe.MonoRuntime == false) { parm.Flags = CspProviderFlags.UseMachineKeyStore | CspProviderFlags.UseExistingKey; parm.KeyNumber = 2; // Signature } return new RSACryptoServiceProvider(parm); +#else + throw new PlatformNotSupportedException("Strong name key container support is only available when targeting .NET Framework."); +#endif } } catch diff --git a/src/IKVM.Reflection/Writer/IMAGE_FILE_HEADER.cs b/src/IKVM.Reflection/Writer/IMAGE_FILE_HEADER.cs deleted file mode 100644 index ead00a62d4..0000000000 --- a/src/IKVM.Reflection/Writer/IMAGE_FILE_HEADER.cs +++ /dev/null @@ -1,54 +0,0 @@ -/* - Copyright (C) 2008-2013 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 DWORD = System.UInt32; -using WORD = System.UInt16; - -namespace IKVM.Reflection.Writer -{ - - sealed class IMAGE_FILE_HEADER - { - - public const WORD IMAGE_FILE_MACHINE_I386 = 0x014c; - public const WORD IMAGE_FILE_MACHINE_ARM = 0x01c4; - public const WORD IMAGE_FILE_MACHINE_IA64 = 0x0200; - public const WORD IMAGE_FILE_MACHINE_AMD64 = 0x8664; - public const WORD IMAGE_FILE_MACHINE_ARM64 = 0xAA64; - - public const WORD IMAGE_FILE_32BIT_MACHINE = 0x0100; - public const WORD IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002; - public const WORD IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020; - public const WORD IMAGE_FILE_DLL = 0x2000; - - public WORD Machine; - public WORD NumberOfSections; - public DWORD TimeDateStamp; - public DWORD PointerToSymbolTable = 0; - public DWORD NumberOfSymbols = 0; - public WORD SizeOfOptionalHeader = 0xE0; - public WORD Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; - - } - -} diff --git a/src/IKVM.Reflection/Writer/IMAGE_NT_HEADERS.cs b/src/IKVM.Reflection/Writer/IMAGE_NT_HEADERS.cs deleted file mode 100644 index e315b26d7f..0000000000 --- a/src/IKVM.Reflection/Writer/IMAGE_NT_HEADERS.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright (C) 2008-2013 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 DWORD = System.UInt32; - -namespace IKVM.Reflection.Writer -{ - - sealed class IMAGE_NT_HEADERS - { - - public DWORD Signature = 0x00004550; // "PE\0\0" - public IMAGE_FILE_HEADER FileHeader = new IMAGE_FILE_HEADER(); - public IMAGE_OPTIONAL_HEADER OptionalHeader = new IMAGE_OPTIONAL_HEADER(); - - } - -} diff --git a/src/IKVM.Reflection/Writer/IMAGE_OPTIONAL_HEADER.cs b/src/IKVM.Reflection/Writer/IMAGE_OPTIONAL_HEADER.cs deleted file mode 100644 index 3a52a4df71..0000000000 --- a/src/IKVM.Reflection/Writer/IMAGE_OPTIONAL_HEADER.cs +++ /dev/null @@ -1,133 +0,0 @@ -/* - Copyright (C) 2008-2013 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.IO; - -using IKVM.Reflection.Reader; - -using BYTE = System.Byte; -using DWORD = System.UInt32; -using ULONGLONG = System.UInt64; -using WORD = System.UInt16; - -namespace IKVM.Reflection.Writer -{ - - sealed class IMAGE_OPTIONAL_HEADER - { - - public const WORD IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b; - public const WORD IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b; - - public const WORD IMAGE_SUBSYSTEM_WINDOWS_GUI = 2; - public const WORD IMAGE_SUBSYSTEM_WINDOWS_CUI = 3; - - public WORD Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC; - public BYTE MajorLinkerVersion = 8; - public BYTE MinorLinkerVersion = 0; - public DWORD SizeOfCode; - public DWORD SizeOfInitializedData; - public DWORD SizeOfUninitializedData; - public DWORD AddressOfEntryPoint; - public DWORD BaseOfCode; - public DWORD BaseOfData; - public ULONGLONG ImageBase; - public DWORD SectionAlignment = 0x2000; - public DWORD FileAlignment; - public WORD MajorOperatingSystemVersion = 4; - public WORD MinorOperatingSystemVersion = 0; - public WORD MajorImageVersion = 0; - public WORD MinorImageVersion = 0; - public WORD MajorSubsystemVersion = 4; - public WORD MinorSubsystemVersion = 0; - public DWORD Win32VersionValue = 0; - public DWORD SizeOfImage; - public DWORD SizeOfHeaders; - public DWORD CheckSum = 0; - public WORD Subsystem; - public WORD DllCharacteristics; - public ULONGLONG SizeOfStackReserve; - public ULONGLONG SizeOfStackCommit = 0x1000; - public ULONGLONG SizeOfHeapReserve = 0x100000; - public ULONGLONG SizeOfHeapCommit = 0x1000; - public DWORD LoaderFlags = 0; - public DWORD NumberOfRvaAndSizes = 16; - public IMAGE_DATA_DIRECTORY[] DataDirectory = new IMAGE_DATA_DIRECTORY[16]; - - internal void Write(BinaryWriter bw) - { - bw.Write(Magic); - bw.Write(MajorLinkerVersion); - bw.Write(MinorLinkerVersion); - bw.Write(SizeOfCode); - bw.Write(SizeOfInitializedData); - bw.Write(SizeOfUninitializedData); - bw.Write(AddressOfEntryPoint); - bw.Write(BaseOfCode); - if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - bw.Write(BaseOfData); - bw.Write((DWORD)ImageBase); - } - else - { - bw.Write(ImageBase); - } - bw.Write(SectionAlignment); - bw.Write(FileAlignment); - bw.Write(MajorOperatingSystemVersion); - bw.Write(MinorOperatingSystemVersion); - bw.Write(MajorImageVersion); - bw.Write(MinorImageVersion); - bw.Write(MajorSubsystemVersion); - bw.Write(MinorSubsystemVersion); - bw.Write(Win32VersionValue); - bw.Write(SizeOfImage); - bw.Write(SizeOfHeaders); - bw.Write(CheckSum); - bw.Write(Subsystem); - bw.Write(DllCharacteristics); - if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - bw.Write((DWORD)SizeOfStackReserve); - bw.Write((DWORD)SizeOfStackCommit); - bw.Write((DWORD)SizeOfHeapReserve); - bw.Write((DWORD)SizeOfHeapCommit); - } - else - { - bw.Write(SizeOfStackReserve); - bw.Write(SizeOfStackCommit); - bw.Write(SizeOfHeapReserve); - bw.Write(SizeOfHeapCommit); - } - bw.Write(LoaderFlags); - bw.Write(NumberOfRvaAndSizes); - for (int i = 0; i < DataDirectory.Length; i++) - { - bw.Write(DataDirectory[i].VirtualAddress); - bw.Write(DataDirectory[i].Size); - } - } - } -} diff --git a/src/IKVM.Reflection/Writer/SectionHeader.cs b/src/IKVM.Reflection/Writer/SectionHeader.cs deleted file mode 100644 index ec8dabafd7..0000000000 --- a/src/IKVM.Reflection/Writer/SectionHeader.cs +++ /dev/null @@ -1,55 +0,0 @@ -/* - Copyright (C) 2008-2013 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 DWORD = System.UInt32; -using WORD = System.UInt16; - -namespace IKVM.Reflection.Writer -{ - - class SectionHeader - { - - public const DWORD IMAGE_SCN_CNT_CODE = 0x00000020; - public const DWORD IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040; - public const DWORD IMAGE_SCN_MEM_DISCARDABLE = 0x02000000; - public const DWORD IMAGE_SCN_MEM_EXECUTE = 0x20000000; - public const DWORD IMAGE_SCN_MEM_READ = 0x40000000; - public const DWORD IMAGE_SCN_MEM_WRITE = 0x80000000; - - public string Name; // 8 byte UTF8 encoded 0-padded - public DWORD VirtualSize; - public DWORD VirtualAddress; - public DWORD SizeOfRawData; - public DWORD PointerToRawData; -#pragma warning disable 649 // the follow fields are never assigned to - public DWORD PointerToRelocations; - public DWORD PointerToLinenumbers; - public WORD NumberOfRelocations; - public WORD NumberOfLinenumbers; -#pragma warning restore 649 - public DWORD Characteristics; - - } - -} diff --git a/src/IKVM.Reflection/Writer/TextSection.cs b/src/IKVM.Reflection/Writer/TextSection.cs deleted file mode 100644 index 1926b623fe..0000000000 --- a/src/IKVM.Reflection/Writer/TextSection.cs +++ /dev/null @@ -1,415 +0,0 @@ -///* -// Copyright (C) 2008-2013 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; - -//using IKVM.Reflection.Emit; -//using IKVM.Reflection.Impl; -//using IKVM.Reflection.Metadata; - -//namespace IKVM.Reflection.Writer -//{ - -// sealed class TextSection -// { - -// readonly PEWriter peWriter; -// readonly CliHeader cliHeader; -// readonly ModuleBuilder moduleBuilder; -// readonly uint strongNameSignatureLength; -// readonly uint manifestResourcesLength; -// readonly ExportTables exportTables; -// readonly List relocations = new List(); - -// /// -// /// Initializes a new instance. -// /// -// /// -// /// -// /// -// /// -// internal TextSection(PEWriter peWriter, CliHeader cliHeader, ModuleBuilder moduleBuilder, int strongNameSignatureLength) -// { -// this.peWriter = peWriter; -// this.cliHeader = cliHeader; -// this.moduleBuilder = moduleBuilder; -// this.strongNameSignatureLength = (uint)strongNameSignatureLength; -// this.manifestResourcesLength = (uint)moduleBuilder.GetManifestResourcesLength(); -// if (moduleBuilder.unmanagedExports.Count != 0) -// this.exportTables = new ExportTables(this); -// } - -// internal uint PointerToRawData => peWriter.ToFileAlignment(peWriter.HeaderSize); - -// internal uint BaseRVA => peWriter.Headers.OptionalHeader.SectionAlignment; - -// internal uint ImportAddressTableRVA => BaseRVA; - -// internal uint ImportAddressTableLength => peWriter.Is32Bit ? 8u : 16u; - -// internal uint ComDescriptorRVA => ImportAddressTableRVA + ImportAddressTableLength; - -// internal uint ComDescriptorLength => cliHeader.Cb; - -// internal uint MethodBodiesRVA => (ComDescriptorRVA + ComDescriptorLength + 7) & ~7U; - -// uint MethodBodiesLength => (uint)moduleBuilder.methodBodies.Length; - -// uint ResourcesRVA => peWriter.Headers.FileHeader.Machine switch -// { -// IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386 or IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM => (MethodBodiesRVA + MethodBodiesLength + 3) & ~3U, -// _ => (MethodBodiesRVA + MethodBodiesLength + 15) & ~15U, -// }; - -// uint ResourcesLength => manifestResourcesLength; - -// internal uint StrongNameSignatureRVA => (ResourcesRVA + ResourcesLength + 3) & ~3U; - -// internal uint StrongNameSignatureLength => strongNameSignatureLength; - -// uint MetadataRVA => (StrongNameSignatureRVA + StrongNameSignatureLength + 3) & ~3U; - -// //uint MetadataLength => (uint)moduleBuilder.MetadataLength; - -// //uint VTableFixupsRVA => (MetadataRVA + MetadataLength + 7) & ~7U; - -// uint VTableFixupsLength => (uint)moduleBuilder.vtablefixups.Count * 8; - -// //internal uint DebugDirectoryRVA -// //{ -// // get { return VTableFixupsRVA + VTableFixupsLength; } -// //} - -// internal uint DebugDirectoryLength => DebugDirectoryContentsLength != 0 ? 28 : (uint)0; - -// 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; -// } -// } - -// //internal uint ExportDirectoryRVA => (DebugDirectoryRVA + DebugDirectoryLength + DebugDirectoryContentsLength + 15) & ~15U; - -// internal uint ExportDirectoryLength => moduleBuilder.unmanagedExports.Count == 0 ? 0U : 40U; - -// //uint ExportTablesRVA => ExportDirectoryRVA + ExportDirectoryLength; - -// uint ExportTablesLength => exportTables == null ? 0U : exportTables.Length; - -// //internal uint ImportDirectoryRVA -// //{ -// // // on AMD64 (and probably IA64) the import directory needs to be 16 byte aligned (on I386 4 byte alignment is sufficient) -// // //get { return (ExportTablesRVA + ExportTablesLength + 15) & ~15U; } -// //} - -// //internal uint ImportDirectoryLength => (ImportHintNameTableRVA - ImportDirectoryRVA) + 27; - -// //uint ImportHintNameTableRVA => peWriter.Is32Bit -// // ? (ImportDirectoryRVA + 48 + 15) & ~15U -// // : (ImportDirectoryRVA + 52 + 15) & ~15U; - -// //internal uint StartupStubRVA -// //{ -// // get -// // { -// // if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64) -// // { -// // // note that the alignment is driven by the requirement that the two relocation fixups are in a single page -// // return (ImportDirectoryRVA + ImportDirectoryLength + 15U) & ~15U; -// // } -// // else -// // { -// // // the additional 2 bytes padding are to align the address in the jump (which is a relocation fixup) -// // return 2 + ((ImportDirectoryRVA + ImportDirectoryLength + 3U) & ~3U); -// // } -// // } -// //} - -// internal uint StartupStubLength => peWriter.Headers.FileHeader.Machine switch -// { -// IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386 => 6, -// IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64 or IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM => 12, -// IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64 => 48, -// _ => throw new NotSupportedException(), -// }; - -// sealed class ExportTables -// { - -// readonly TextSection text; -// internal readonly uint entries; -// internal readonly uint ordinalBase; -// internal readonly uint nameCount; -// internal readonly uint namesLength; -// internal readonly uint exportAddressTableRVA; -// internal readonly uint exportNamePointerTableRVA; -// internal readonly uint exportOrdinalTableRVA; -// internal readonly uint namesRVA; -// internal readonly uint stubsRVA; -// readonly uint stubLength; - -// /// -// /// Initializes a new instance. -// /// -// /// -// /// -// internal ExportTables(TextSection text) -// { -// this.text = text; -// ordinalBase = GetOrdinalBase(out entries); -// namesLength = GetExportNamesLength(out nameCount); -// exportAddressTableRVA = text.ExportTablesRVA; -// exportNamePointerTableRVA = exportAddressTableRVA + 4 * entries; -// exportOrdinalTableRVA = exportNamePointerTableRVA + 4 * nameCount; -// namesRVA = exportOrdinalTableRVA + 2 * nameCount; -// stubsRVA = (namesRVA + namesLength + 15) & ~15U; - -// // note that we align the stubs to avoid having to deal with the relocation crossing a page boundary -// stubLength = text.peWriter.Headers.FileHeader.Machine switch -// { -// IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386 => 8, -// IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64 or IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM => 16, -// _ => throw new NotSupportedException(), -// }; -// } - -// internal uint Length => stubsRVA + stubLength * (uint)text.moduleBuilder.unmanagedExports.Count - text.ExportTablesRVA; - -// uint GetOrdinalBase(out uint entries) -// { -// var min = uint.MaxValue; -// var max = uint.MinValue; -// foreach (var exp in text.moduleBuilder.unmanagedExports) -// { -// var ordinal = (uint)exp.ordinal; -// min = Math.Min(min, ordinal); -// max = Math.Max(max, ordinal); -// } - -// entries = 1 + (max - min); -// return min; -// } - -// uint GetExportNamesLength(out uint nameCount) -// { -// nameCount = 0; - -// // the first name in the names list is the module name (the Export Directory contains a name of the current module) -// var length = (uint)text.moduleBuilder.fileName.Length + 1; -// foreach (var exp in text.moduleBuilder.unmanagedExports) -// { -// if (exp.name != null) -// { -// nameCount++; -// length += (uint)exp.name.Length + 1; -// } -// } - -// return length; -// } - -// static int CompareUnmanagedExportNames(UnmanagedExport x, UnmanagedExport y) -// { -// if (x.name == null) -// return y.name == null ? 0 : 1; -// if (y.name == null) -// return -1; - -// return string.CompareOrdinal(x.name, y.name); -// } - -// static int CompareUnmanagedExportOrdinals(UnmanagedExport x, UnmanagedExport y) -// { -// return x.ordinal.CompareTo(y.ordinal); -// } - -// internal void GetRelocations(List list) -// { -// ushort type; -// uint rva; -// switch (text.peWriter.Headers.FileHeader.Machine) -// { -// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386: -// type = 0x3000; -// rva = stubsRVA + 2; -// break; -// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: -// type = 0xA000; -// rva = stubsRVA + 2; -// break; -// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM: -// type = 0x3000; -// rva = stubsRVA + 12; -// break; -// default: -// throw new NotSupportedException(); -// } - -// // we assume that unmanagedExports is still sorted by ordinal -// for (int i = 0, pos = 0; i < entries; i++) -// { -// if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase) -// { -// list.Add(new Relocation(type, rva + (uint)pos * stubLength)); -// pos++; -// } -// } -// } -// } - -// uint GetOrdinalBase(out uint entries) -// { -// var min = uint.MaxValue; -// var max = uint.MinValue; -// foreach (var exp in moduleBuilder.unmanagedExports) -// { -// var ordinal = (uint)exp.ordinal; -// min = Math.Min(min, ordinal); -// max = Math.Max(max, ordinal); -// } - -// entries = 1 + (max - min); -// return min; -// } - -// uint GetExportNamesLength(out uint nameCount) -// { -// nameCount = 0; - -// uint length = 0; -// foreach (var exp in moduleBuilder.unmanagedExports) -// { -// if (exp.name != null) -// { -// nameCount++; -// length += (uint)exp.name.Length + 1; -// } -// } - -// return length; -// } - -// internal int Length -// { -// get { return (int)(StartupStubRVA - BaseRVA + StartupStubLength); } -// } - -// struct Relocation : IComparable -// { - -// internal readonly uint rva; -// internal readonly ushort type; - -// /// -// /// Initializes a new instance. -// /// -// /// -// /// -// internal Relocation(ushort type, uint rva) -// { -// this.type = type; -// this.rva = rva; -// } - -// readonly int IComparable.CompareTo(Relocation other) => rva.CompareTo(other.rva); - -// } - -// struct RelocationBlock -// { - -// internal readonly uint PageRVA; -// internal readonly ushort[] TypeOffset; - -// /// -// /// Initializes a new instance. -// /// -// /// -// /// -// internal RelocationBlock(uint pageRva, ushort[] typeOffset) -// { -// PageRVA = pageRva; -// TypeOffset = typeOffset; -// } - -// } - -// internal uint PackRelocations() -// { -// var list = new List(); -// switch (peWriter.Headers.FileHeader.Machine) -// { -// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386: -// list.Add(new Relocation(0x3000, this.StartupStubRVA + 2)); -// break; -// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64: -// list.Add(new Relocation(0xA000, this.StartupStubRVA + 2)); -// break; -// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64: -// list.Add(new Relocation(0xA000, this.StartupStubRVA + 0x20)); -// list.Add(new Relocation(0xA000, this.StartupStubRVA + 0x28)); -// break; -// case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM: -// list.Add(new Relocation(0x7000, this.StartupStubRVA)); -// break; -// default: -// throw new NotSupportedException(); -// } - -// exportTables?.GetRelocations(list); - -// list.Sort(); -// uint size = 0; -// for (int i = 0; i < list.Count;) -// { -// uint pageRVA = list[i].rva & ~0xFFFU; -// int count = 1; -// while (i + count < list.Count && (list[i + count].rva & ~0xFFFU) == pageRVA) -// count++; - -// var typeOffset = new ushort[(count + 1) & ~1]; -// for (int j = 0; j < count; j++, i++) -// typeOffset[j] = (ushort)(list[i].type + (list[i].rva - pageRVA)); - -// relocations.Add(new RelocationBlock(pageRVA, typeOffset)); -// size += (uint)(8 + typeOffset.Length * 2); -// } - -// return size; -// } - -// } - -//}