diff --git a/IKVM.sln b/IKVM.sln index ea5ffb12bf..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,6 +319,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("{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 Debug|Any CPU = Debug|Any CPU @@ -803,6 +799,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.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.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..1b6ae8895c --- /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..647e1a9979 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 { /// @@ -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.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.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.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..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 @@ -6,13 +6,29 @@ + + + + + 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 f91a56dc5a..73fd94e611 100644 --- a/src/IKVM.Reflection.Tests/ModuleWriterTests.cs +++ b/src/IKVM.Reflection.Tests/ModuleWriterTests.cs @@ -1,46 +1,467 @@ -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; + } - [TestMethod] - public void CanWriteNetFxModule() + } + + readonly ITestOutputHelper output; + + /// + /// Initializes a new instance. + /// + /// + public ModuleWriterTests(ITestOutputHelper output) { - var d = Path.Combine(TestContext.TestRunResultsDirectory, "IKVM.Reflection.Tests", "ModuleWriterTests"); - if (Directory.Exists(d)) - Directory.Delete(d, true); - Directory.CreateDirectory(d); + this.output = output ?? throw new ArgumentNullException(nameof(output)); + } + + /// + /// 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) + { + 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; - var u = new Universe("mscorlib"); - 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"); + // 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; } - [TestMethod] - public void CanWriteNetCoreModule() + [Theory] + [MemberData(nameof(FrameworkSpec.GetFrameworkTestData), MemberType = typeof(FrameworkSpec))] + public void CanWriteModule(FrameworkSpec framework) { - var d = Path.Combine(TestContext.TestRunResultsDirectory, "IKVM.Reflection.Tests", "ModuleWriterTests"); - if (Directory.Exists(d)) - Directory.Delete(d, true); - Directory.CreateDirectory(d); + 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); + + 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"); + } + + [Theory] + [MemberData(nameof(FrameworkSpec.GetFrameworkTestData), MemberType = typeof(FrameworkSpec))] + public void CanWriteInterfaceImplementation(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 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(); + 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 }); + } + + [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")); + } + + [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; + + // 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"); + + 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 | 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 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"); + 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.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.Tests/sample.ico b/src/IKVM.Reflection.Tests/sample.ico new file mode 100644 index 0000000000..e88b760e08 Binary files /dev/null and b/src/IKVM.Reflection.Tests/sample.ico differ 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..6040857826 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; @@ -108,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) { @@ -121,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); } @@ -330,24 +327,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 +363,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,13 +372,14 @@ 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; + // 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()); @@ -378,34 +387,36 @@ 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) - { - // 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); 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) @@ -414,69 +425,59 @@ 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; - + // write each non-manifest module foreach (var moduleBuilder in modules) { moduleBuilder.FillAssemblyRefTable(); - moduleBuilder.EmitResources(); 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.nativeResources, default); fileToken = AddFile(manifestModule, moduleBuilder.fileName, 0 /*ContainsMetaData*/); } moduleBuilder.ExportTypes(fileToken, manifestModule); } - - moduleBuilder.CloseResources(); } + // import existing modules 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; - // 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, entryPoint, 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 +487,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; @@ -502,13 +503,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; @@ -528,9 +528,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; @@ -542,27 +541,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). @@ -578,57 +574,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; } @@ -643,27 +634,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) { @@ -672,40 +647,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; } @@ -748,14 +712,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/CustomAttributeBuilder.cs b/src/IKVM.Reflection/Emit/CustomAttributeBuilder.cs index 2fb11e456f..8f18c1425f 100644 --- a/src/IKVM.Reflection/Emit/CustomAttributeBuilder.cs +++ b/src/IKVM.Reflection/Emit/CustomAttributeBuilder.cs @@ -24,6 +24,7 @@ Jeroen Frijters using System; using System.Collections.Generic; using System.Diagnostics; +using System.Reflection.Metadata; using System.Text; using IKVM.Reflection.Writer; @@ -517,7 +518,7 @@ internal ConstructorInfo Constructor get { return con; } } - internal int WriteBlob(ModuleBuilder moduleBuilder) + internal BlobHandle WriteBlob(ModuleBuilder moduleBuilder) { ByteBuffer bb; if (blob != null) @@ -527,10 +528,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 +601,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 +631,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..9f919cb78c 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,24 +32,24 @@ 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; - readonly int eventtype; + readonly int eventType; MethodBuilder addOnMethod; MethodBuilder removeOnMethod; MethodBuilder fireMethod; readonly List accessors = new List(); int lazyPseudoToken; - struct Accessor - { - - internal short Semantics; - internal MethodBuilder Method; - - } - /// /// Initializes a new instance. /// @@ -61,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) @@ -184,17 +185,17 @@ public EventToken GetEventToken() public override Type EventHandlerType { - get { return typeBuilder.ModuleBuilder.ResolveType(eventtype); } + get { return typeBuilder.ModuleBuilder.ResolveType(eventType); } } internal void Bake() { var rec = new EventTable.Record(); rec.EventFlags = (short)attributes; - rec.Name = typeBuilder.ModuleBuilder.Strings.Add(name); - rec.EventType = eventtype; - var token = 0x14000000 | typeBuilder.ModuleBuilder.Event.AddRecord(rec); + rec.Name = typeBuilder.ModuleBuilder.GetOrAddString(name); + 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/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..bf3a65b5fe 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 @@ -191,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); } @@ -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; } @@ -262,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 7c287e5dd0..b4e6c2dcf1 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; @@ -384,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: @@ -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..74909ee44f 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); + typeBuilder.ModuleBuilder.RegisterTokenFixup(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 c9eac0a4d0..c61161208b 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 { @@ -113,28 +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(); - var rec = new ManifestResourceTable.Record(); - rec.Offset = offset; - rec.Flags = (int)attributes; - rec.Name = mb.Strings.Add(name); - rec.Implementation = 0; - mb.ManifestResource.AddRecord(rec); - } - - internal readonly int GetLength() => 4 + (int)stream.Length; + // align the start of the resource + module.resourceStream.Align(8); + var offset = module.resourceStream.Count; - internal readonly void Write(MetadataWriter mw) - { - mw.Write((int)stream.Length); + // 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) - mw.Write(buffer, 0, length); + module.resourceStream.WriteBytes(buffer, 0, length); + + // add the resource record + var rec = new ManifestResourceTable.Record(); + rec.Offset = offset; + rec.Flags = (int)attributes; + rec.Name = module.GetOrAddString(name); + rec.Implementation = 0; + module.ManifestResource.AddRecord(rec); } internal readonly void Close() @@ -231,6 +203,46 @@ public bool Equals(MethodSpecKey other) } + static readonly bool usePublicKeyAssemblyReference = false; + + readonly MetadataBuilder metadata; + readonly BlobBuilder ilStream; + readonly BlobBuilder resourceStream; + readonly AssemblyBuilder asm; + Guid mvid; + uint timestamp; + 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; +#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 ModuleResourceSectionBuilder nativeResources; + 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 +251,15 @@ 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.resourceStream = 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 +280,90 @@ 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 reference to the for the resource stream. + /// + internal BlobBuilder ResourceStream => resourceStream; + + /// + /// 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 +373,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 +539,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 +572,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 +592,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 +608,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 +646,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 +661,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) @@ -586,49 +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(); - } - } - - internal void WriteResources(MetadataWriter mw) + /// + /// Writes the defined resources to the resource blob and metadata tables. + /// + /// + 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; - } - } - - 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 @@ -700,14 +765,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 +823,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 +868,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); } @@ -833,10 +898,11 @@ 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); - token = 0x2B000000 | MethodSpec.FindOrAddRecord(rec); + rec.Instantiation = GetOrAddBlob(spec.ToArray()); + token = MetadataTokens.GetToken(MetadataTokens.MethodSpecificationHandle(MethodSpec.FindOrAddRecord(rec))); importedMethodSpecs.Add(key, token); } @@ -852,7 +918,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 { @@ -865,7 +931,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); } @@ -926,19 +992,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() @@ -1025,17 +1091,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++) { @@ -1045,104 +1112,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 - { - get - { - return GetHeaderLength() + (Blobs.IsEmpty ? 0 : Blobs.Length) + Tables.Length + Strings.Length + UserStrings.Length + Guids.Length; - } - } - - internal void WriteMetadata(MetadataWriter mw, out uint guidHeapOffset) + /// + /// Writes all of the metadata of the module. + /// + internal void WriteMetadata() { - 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) @@ -1157,38 +1134,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)); @@ -1196,93 +1172,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 = defaultValue; + Constant.AddRecord(rec); } ModuleBuilder ITypeOwner.ModuleBuilder @@ -1422,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() @@ -1455,17 +1444,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) @@ -1483,59 +1474,43 @@ internal override Type GetModuleType() return moduleType; } - internal override IKVM.Reflection.Reader.ByteReader GetBlob(int blobIndex) + internal BlobHandle GetSignatureBlobIndex(Signature sig) { - return Blobs.GetBlob(blobIndex); - } - - internal int 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 - 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; } @@ -1572,35 +1547,32 @@ 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(); - 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) { @@ -1610,18 +1582,19 @@ 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); - CloseResources(); + ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, nativeResources, default, streamOrNull); } public void __AddAssemblyReference(AssemblyName assemblyName) @@ -1631,67 +1604,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(); } @@ -1702,21 +1660,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) @@ -1727,19 +1685,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); } @@ -1750,7 +1707,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; @@ -1762,30 +1719,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); } @@ -1793,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; } } @@ -1810,17 +1761,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; } @@ -1829,11 +1777,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..434f43fd36 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; } @@ -511,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(); @@ -521,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(); @@ -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..754032f372 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/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/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..7eb75c7b0c 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 { @@ -31,20 +34,22 @@ sealed class AssemblyTable : Table internal struct Record { + internal int HashAlgId; internal ushort MajorVersion; internal ushort MinorVersion; 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 +59,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..b278aaf9f3 100644 --- a/src/IKVM.Reflection/Metadata/ClassLayoutTable.cs +++ b/src/IKVM.Reflection/Metadata/ClassLayoutTable.cs @@ -21,8 +21,11 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { @@ -36,44 +39,35 @@ internal struct Record : IRecord internal int ClassSize; internal int Parent; - 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 = (int)TableIndex.ClassLayout; - int IRecord.FilterKey => Parent; + 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( + (TypeDefinitionHandle)MetadataTokens.EntityHandle(records[i].Parent), + (ushort)records[i].PackingSize, + (uint)records[i].ClassSize); } - 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; - } - - } + } } 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..d581f5175a 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.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 { + sealed class ConstantTable : SortedTable { @@ -37,68 +40,63 @@ internal struct Record : IRecord internal short Type; internal int Parent; - internal int Value; + internal BlobHandle Offset; + internal object Value; + + readonly int IRecord.FilterKey => Parent; - int IRecord.SortKey => EncodeHasConstant(Parent); + public readonly int CompareTo(Record other) => Comparer.Default.Compare(EncodeHasConstant(Parent), EncodeHasConstant(other.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) + 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(); } - 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) { 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..34650c288a 100644 --- a/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs +++ b/src/IKVM.Reflection/Metadata/CustomAttributeTable.cs @@ -22,10 +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; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -36,96 +38,87 @@ internal struct Record : IRecord { internal int Parent; - internal int Type; - internal int Value; - - readonly int IRecord.SortKey => EncodeHasCustomAttribute(Parent); + internal int Constructor; + internal BlobHandle Value; readonly int IRecord.FilterKey => Parent; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(EncodeHasCustomAttribute(Parent), EncodeHasCustomAttribute(other.Parent)); + } 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) - { - return (token >> 24) switch + 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 + 1)); + } + } + + internal void Fixup(ModuleBuilder moduleBuilder) + { + var genericParamFixup = moduleBuilder.GenericParam.GetIndexFixup(); + + for (int i = 0; i < rowCount; i++) { - 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(), - }; + moduleBuilder.FixupPseudoToken(ref records[i].Constructor); + moduleBuilder.FixupPseudoToken(ref records[i].Parent); + 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 + // we need to fix them up here (because they are sorted tables, like GenericParam) + } + + Sort(); } - } + internal static int EncodeHasCustomAttribute(int token) => (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(), + }; + + } } diff --git a/src/IKVM.Reflection/Metadata/DeclSecurityTable.cs b/src/IKVM.Reflection/Metadata/DeclSecurityTable.cs index 178ef9894f..d799b21f58 100644 --- a/src/IKVM.Reflection/Metadata/DeclSecurityTable.cs +++ b/src/IKVM.Reflection/Metadata/DeclSecurityTable.cs @@ -22,10 +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; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -34,53 +36,48 @@ sealed class DeclSecurityTable : SortedTable internal struct Record : IRecord { + internal short Action; internal int Parent; - internal int PermissionSet; - - readonly int IRecord.SortKey => Parent; + internal BlobHandle PermissionSet; readonly int IRecord.FilterKey => Parent; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(Parent, other.Parent); + } 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 +87,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..0dc7e23bad 100644 --- a/src/IKVM.Reflection/Metadata/EventMapTable.cs +++ b/src/IKVM.Reflection/Metadata/EventMapTable.cs @@ -21,58 +21,49 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +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 { internal struct Record : IRecord { + internal int Parent; internal int EventList; - int IRecord.SortKey - { - get { return Parent; } - } + readonly int IRecord.FilterKey => Parent; + + public readonly int CompareTo(Record other) => Comparer.Default.Compare(Parent, other.Parent); + + } + + internal const int Index = 0x12; - int IRecord.FilterKey + internal override void Read(Reader.MetadataReader mr) + { + for (int i = 0; i < records.Length; i++) { - get { return Parent; } + records[i].Parent = mr.ReadTypeDef(); + records[i].EventList = mr.ReadEvent(); } } - internal const int Index = 0x12; + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + module.Metadata.AddEventMap( + (TypeDefinitionHandle)MetadataTokens.EntityHandle(records[i].Parent), + (EventDefinitionHandle)MetadataTokens.EntityHandle(records[i].EventList)); + } - 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); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteTypeDef() - .WriteEvent() - .Value; - } - - } + } } 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..016700d66b 100644 --- a/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs +++ b/src/IKVM.Reflection/Metadata/FieldLayoutTable.cs @@ -21,9 +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; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -37,47 +39,39 @@ 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; - 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( + (FieldDefinitionHandle)MetadataTokens.EntityHandle(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..1f4ce0e998 100644 --- a/src/IKVM.Reflection/Metadata/FieldMarshalTable.cs +++ b/src/IKVM.Reflection/Metadata/FieldMarshalTable.cs @@ -22,13 +22,15 @@ Jeroen Frijters */ using System; +using System.Collections.Generic; +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 FieldMarshalTable : SortedTable { @@ -36,40 +38,31 @@ internal struct Record : IRecord { internal int Parent; - internal int NativeType; - - readonly int IRecord.SortKey => EncodeHasFieldMarshal(Parent); + internal BlobHandle NativeType; readonly int IRecord.FilterKey => Parent; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(EncodeHasFieldMarshal(Parent), EncodeHasFieldMarshal(other.Parent)); + } 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..d8758f4519 100644 --- a/src/IKVM.Reflection/Metadata/FieldRVATable.cs +++ b/src/IKVM.Reflection/Metadata/FieldRVATable.cs @@ -21,12 +21,13 @@ Jeroen Frijters jeroen@frijters.net */ +using System.Collections.Generic; + using IKVM.Reflection.Emit; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { + sealed class FieldRVATable : SortedTable { @@ -36,15 +37,15 @@ 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); } 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 +54,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..b21451f82a 100644 --- a/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs +++ b/src/IKVM.Reflection/Metadata/GenericParamConstraintTable.cs @@ -21,9 +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; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -36,47 +39,44 @@ 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; - 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( + (GenericParameterHandle)MetadataTokens.EntityHandle(records[i].Owner), + MetadataTokens.EntityHandle(records[i].Constraint)); + + Debug.Assert(h == MetadataTokens.GenericParameterConstraintHandle(i + 1)); + } + } + + internal void Fixup(ModuleBuilder moduleBuilder) + { + var fixups = moduleBuilder.GenericParam.GetIndexFixup(); + for (int i = 0; i < rowCount; i++) + 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 cbdac3f8be..b0018a939f 100644 --- a/src/IKVM.Reflection/Metadata/GenericParamTable.cs +++ b/src/IKVM.Reflection/Metadata/GenericParamTable.cs @@ -23,15 +23,16 @@ 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 { - sealed class GenericParamTable : SortedTable, IComparer + sealed class GenericParamTable : SortedTable { internal struct Record : IRecord @@ -40,101 +41,92 @@ 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; - - readonly int IRecord.SortKey => 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; - 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); - - // 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(), - }; - - records[i].unsortedIndex = i; - } - - 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); - - return x.Owner > y.Owner ? 1 : -1; - } - - 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; - - return array; - } - - internal int FindFirstByOwner(int token) - { - foreach (int i in Filter(token)) - return i; - - return -1; - } - - } + 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++) + { + moduleBuilder.FixupPseudoToken(ref records[i].Owner); + records[i].UnsortedIndex = i; + } + + 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(), + }; + + 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; + + return array; + } + + internal int FindFirstByOwner(int token) + { + foreach (int i in Filter(token)) + return i; + + return -1; + } + + } } diff --git a/src/IKVM.Reflection/Metadata/ImplMapTable.cs b/src/IKVM.Reflection/Metadata/ImplMapTable.cs index 7bd70bd72c..13fe111338 100644 --- a/src/IKVM.Reflection/Metadata/ImplMapTable.cs +++ b/src/IKVM.Reflection/Metadata/ImplMapTable.cs @@ -21,9 +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; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -36,57 +38,46 @@ internal struct Record : IRecord internal short MappingFlags; internal int MemberForwarded; - internal int ImportName; + 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; - 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( + (MethodDefinitionHandle)MetadataTokens.EntityHandle(records[i].MemberForwarded), + (System.Reflection.MethodImportAttributes)records[i].MappingFlags, + records[i].ImportName, + (ModuleReferenceHandle)MetadataTokens.EntityHandle(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..69ec083e06 100644 --- a/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs +++ b/src/IKVM.Reflection/Metadata/InterfaceImplTable.cs @@ -21,10 +21,12 @@ 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.Reader; -using IKVM.Reflection.Writer; +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { @@ -38,70 +40,49 @@ internal struct Record : IRecord internal int Class; internal int Interface; - int IRecord.SortKey => Class; + readonly int IRecord.FilterKey => Class; - int IRecord.FilterKey => Class; + public readonly int CompareTo(Record other) => Comparer.Default.Compare(Class, other.Class); + + } + + 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( + (TypeDefinitionHandle)MetadataTokens.EntityHandle(records[i].Class), + MetadataTokens.EntityHandle(records[i].Interface)); + + Debug.Assert(h == MetadataTokens.InterfaceImplementationHandle(i + 1)); + } + } + + 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). + Sort(); } - 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(); - } - - } + } } 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..ee6e74265a 100644 --- a/src/IKVM.Reflection/Metadata/MethodImplTable.cs +++ b/src/IKVM.Reflection/Metadata/MethodImplTable.cs @@ -21,9 +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; -using IKVM.Reflection.Writer; namespace IKVM.Reflection.Metadata { @@ -38,53 +41,47 @@ 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; - 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( + (TypeDefinitionHandle)MetadataTokens.EntityHandle(records[i].Class), + MetadataTokens.EntityHandle(records[i].MethodBody), + MetadataTokens.EntityHandle(records[i].MethodDeclaration)); + + Debug.Assert(h == 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..c032d6f865 100644 --- a/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs +++ b/src/IKVM.Reflection/Metadata/MethodSemanticsTable.cs @@ -23,10 +23,9 @@ Jeroen Frijters */ using System; 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 { @@ -41,116 +40,102 @@ internal struct Record : IRecord internal int Method; internal int Association; - readonly int IRecord.SortKey => 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; - // 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; - // do the HasSemantics encoding, so that we can sort the table - token = (token >> 24) switch + // 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( + MetadataTokens.EntityHandle(records[i].Association), + (System.Reflection.MethodSemanticsAttributes)records[i].Semantics, + 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); + + 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) { - EventTable.Index => (token & 0xFFFFFF) << 1 | 0, - 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; - } - } - - } + 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..387c4b1b45 100644 --- a/src/IKVM.Reflection/Metadata/NestedClassTable.cs +++ b/src/IKVM.Reflection/Metadata/NestedClassTable.cs @@ -22,9 +22,10 @@ Jeroen Frijters */ using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { @@ -37,15 +38,15 @@ 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; - internal override void Read(MetadataReader mr) + internal override void Read(Reader.MetadataReader mr) { for (int i = 0; i < records.Length; i++) { @@ -54,21 +55,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( + (TypeDefinitionHandle)MetadataTokens.EntityHandle(records[i].NestedClass), + (TypeDefinitionHandle)MetadataTokens.EntityHandle(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..b9d758c9e7 100644 --- a/src/IKVM.Reflection/Metadata/PropertyMapTable.cs +++ b/src/IKVM.Reflection/Metadata/PropertyMapTable.cs @@ -21,13 +21,17 @@ Jeroen Frijters jeroen@frijters.net */ -using IKVM.Reflection.Reader; -using IKVM.Reflection.Writer; +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using IKVM.Reflection.Emit; namespace IKVM.Reflection.Metadata { + sealed class PropertyMapTable : SortedTable - { + { internal struct Record : IRecord { @@ -35,39 +39,30 @@ 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; - 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); - } - } - - protected override int GetRowSize(RowSizeCalc rsc) - { - return rsc - .WriteTypeDef() - .WriteProperty() - .Value; - } - } + 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(); + } + } + + internal override void Write(ModuleBuilder module) + { + for (int i = 0; i < rowCount; i++) + module.Metadata.AddPropertyMap( + (TypeDefinitionHandle)MetadataTokens.EntityHandle(records[i].Parent), + (PropertyDefinitionHandle)MetadataTokens.EntityHandle(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/SortedTable.cs b/src/IKVM.Reflection/Metadata/SortedTable.cs index 76521ac919..176a08e3ab 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 { @@ -32,11 +31,9 @@ abstract class SortedTable : Table where T : SortedTable.IRecord { - internal interface IRecord + internal interface IRecord : IComparable { - int SortKey { get; } - int FilterKey { get; } } @@ -61,7 +58,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); @@ -148,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/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..fd0299ad75 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; @@ -429,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 { @@ -518,7 +513,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 +529,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 +574,7 @@ internal sealed override Type GetModuleType() throw InvalidOperationException(); } - internal sealed override ByteReader GetBlob(int blobIndex) + internal sealed override ByteReader GetBlobReader(BlobHandle handle) { throw InvalidOperationException(); } @@ -604,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 e5c0300ea0..a426295869 100644 --- a/src/IKVM.Reflection/Reader/AssemblyReader.cs +++ b/src/IKVM.Reflection/Reader/AssemblyReader.cs @@ -67,29 +67,23 @@ 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; 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,41 +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; } @@ -197,35 +183,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..22b44e1371 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); } @@ -1182,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; } @@ -1231,31 +1231,28 @@ public override IList __GetPlaceholderAssemblyCustomAttribu internal override void Dispose() { - if (stream != null) - { - stream.Dispose(); - } + stream?.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); } - 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() @@ -1273,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/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/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..36c2d72e3d 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)); @@ -121,17 +122,21 @@ internal RSACryptoServiceProvider 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/Universe.cs b/src/IKVM.Reflection/Universe.cs index 69093a0643..b7ba7909b4 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 @@ -734,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/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/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/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/ResourceSection.cs b/src/IKVM.Reflection/Writer/ModuleResourceSectionBuilder.cs similarity index 53% rename from src/IKVM.Reflection/Writer/ResourceSection.cs rename to src/IKVM.Reflection/Writer/ModuleResourceSectionBuilder.cs index 10a9255299..07f7b4ab15 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,47 @@ 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); + } + + /// + /// Gets the number of entries in the root of the builder. + /// + public int Count => root.Count; + + /// + /// 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 +99,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,35 +127,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; } - } - - internal void Write(MetadataWriter mw, uint rva) - { foreach (int offset in linkOffsets) { bb.Position = offset; - bb.Write(bb.GetInt32AtCurrentPosition() + (int)rva); + bb.Write(bb.GetInt32AtCurrentPosition() + (int)location.RelativeVirtualAddress); } - mw.Write(bb); + builder.WriteBytes(bb.ToArray()); } } diff --git a/src/IKVM.Reflection/Writer/ModuleWriter.cs b/src/IKVM.Reflection/Writer/ModuleWriter.cs index f17ba0b8be..ea00b01c71 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,58 @@ 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) + 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 . + /// + /// + /// + /// + /// + /// + /// + /// + /// + 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, resources, entryPointToken, null); + WriteModule(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, nativeResources, entryPoint, 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, ModuleResourceSectionBuilder nativeResources, MethodInfo entryPoint, Stream stream) { if (stream == null) { @@ -59,7 +109,7 @@ 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); + 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) @@ -67,286 +117,348 @@ internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, Mo } else { - WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, stream); + WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, nativeResources, 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 module, IKVM.Reflection.Emit.PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ModuleResourceSectionBuilder nativeResources, MethodInfo entryPoint, Stream stream) { - moduleBuilder.ApplyUnmanagedExports(imageFileMachine); - moduleBuilder.FixupMethodBodyTokens(); + module.ApplyUnmanagedExports(imageFileMachine); + module.FixupMethodBodyTokens(); - int moduleVersionIdIndex = moduleBuilder.Guids.Add(moduleBuilder.GetModuleVersionIdOrEmpty()); - moduleBuilder.ModuleTable.Add(0, moduleBuilder.Strings.Add(moduleBuilder.moduleName), moduleVersionIdIndex, 0, 0); + // for compatibility with Reflection.Emit, if there aren't any user strings, we add one + module.Metadata.GetOrAddUserString(""); - if (moduleBuilder.UserStrings.IsEmpty) +#if NETFRAMEWORK + if (module.symbolWriter != null) { - // for compat with Ref.Emit, if there aren't any user strings, we add one - moduleBuilder.UserStrings.Add(" "); + module.WriteSymbolTokenMap(); + module.symbolWriter.Close(); } +#endif - if (resources != null) - resources.Finish(); + // 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), + 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: GetSizeOfStackReserve(module, is64BitArch), + sizeOfStackCommit: GetSizeOfStackCommit(module, is64BitArch), + sizeOfHeapReserve: GetSizeOfHeapReserve(module, is64BitArch), + sizeOfHeapCommit: GetSizeOfHeapCommit(module, is64BitArch)); + + // initialize PE builder + var strongNameSignatureSize = ComputeStrongNameSignatureLength(publicKey); + var peBuilder = new ManagedPEBuilder( + peHeaderBuilder, + new MetadataRootBuilder(module.Metadata), + module.ILStream, + managedResources: module.ResourceStream, + nativeResources: nativeResources.Count > 0 ? nativeResources : null, + strongNameSignatureSize: strongNameSignatureSize, + entryPoint: entryPoint != null ? (MethodDefinitionHandle)MetadataTokens.EntityHandle(entryPoint.GetCurrentToken()) : default, + flags: GetCorFlags(portableExecutableKind, keyPair), + deterministicIdProvider: GetDeterministicIdProvider(module)); + + // 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, strongNameSignatureSize)); - 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); - 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; - 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; - break; - default: - throw new ArgumentOutOfRangeException("imageFileMachine"); - } + // write the final content to the output stream + pe.WriteContentTo(stream); + } - if (fileKind == PEFileKinds.Dll) - writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_DLL; + /// + /// 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); + 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); + + moduleBuilder.ILStream.WriteBytes(moduleBuilder.methodBodies.ToArray()); + moduleBuilder.WriteResources(); + moduleBuilder.WriteMetadata(); + } - writer.Headers.OptionalHeader.Subsystem = fileKind switch + /// + /// Translates the parameter into a value. + /// + /// + /// + /// + static Machine GetMachine(ImageFileMachine imageFileMachine) + { + return imageFileMachine switch { - PEFileKinds.WindowApplication => IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_GUI, - _ => IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_CUI, + ImageFileMachine.UNKNOWN => Machine.Unknown, + ImageFileMachine.I386 => Machine.I386, + ImageFileMachine.ARM => Machine.Arm, + ImageFileMachine.AMD64 => Machine.Amd64, + ImageFileMachine.IA64 => Machine.IA64, + ImageFileMachine.ARM64 => Machine.Arm64, + _ => throw new ArgumentOutOfRangeException("imageFileMachine"), }; + } - writer.Headers.OptionalHeader.DllCharacteristics = (ushort)moduleBuilder.__DllCharacteristics; - - var cliHeader = new CliHeader(); - cliHeader.Cb = 0x48; - cliHeader.MajorRuntimeVersion = 2; - cliHeader.MinorRuntimeVersion = moduleBuilder.MDStreamVersion < 0x20000 ? (ushort)0 : (ushort)5; - - if ((portableExecutableKind & PortableExecutableKinds.ILOnly) != 0) - cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_ILONLY; - - if ((portableExecutableKind & PortableExecutableKinds.Required32Bit) != 0) - cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED; - - if ((portableExecutableKind & PortableExecutableKinds.Preferred32Bit) != 0) - cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED; - - 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)); + /// + /// Gets the appropriate section alignment for the image. + /// + /// + /// + /// + static int GetSectionAlignment(IKVM.Reflection.Emit.ModuleBuilder module, bool is64BitArch) + { + return DefaultSectionAlignment; + } - // Export Directory - if (code.ExportDirectoryLength != 0) - { - writer.Headers.OptionalHeader.DataDirectory[0].VirtualAddress = code.ExportDirectoryRVA; - writer.Headers.OptionalHeader.DataDirectory[0].Size = code.ExportDirectoryLength; - } + /// + /// 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; + } - // Import Directory - if (code.ImportDirectoryLength != 0) - { - writer.Headers.OptionalHeader.DataDirectory[1].VirtualAddress = code.ImportDirectoryRVA; - writer.Headers.OptionalHeader.DataDirectory[1].Size = code.ImportDirectoryLength; - } + /// + /// 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); - // Import Address Table Directory - if (code.ImportAddressTableLength != 0) + // cover values smaller than 0x8000, overflow and default value 0): + if (baseAddress == 0) { - writer.Headers.OptionalHeader.DataDirectory[12].VirtualAddress = code.ImportAddressTableRVA; - writer.Headers.OptionalHeader.DataDirectory[12].Size = code.ImportAddressTableLength; + if (fileKind is IKVM.Reflection.Emit.PEFileKinds.ConsoleApplication or IKVM.Reflection.Emit.PEFileKinds.WindowApplication) + return is64BitArch ? DefaultExeBaseAddress64Bit : DefaultExeBaseAddress32Bit; + else + return is64BitArch ? DefaultDllBaseAddress64Bit : DefaultDllBaseAddress32Bit; } - // 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; - } + return baseAddress; + } - // Set the PE File timestamp - writer.Headers.FileHeader.TimeDateStamp = moduleBuilder.GetTimeDateStamp(); + /// + /// Gets the major subsystem verison. + /// + /// + static ushort GetMajorSubsystemVersion(ImageFileMachine imageFileMachine, IKVM.Reflection.Emit.PEFileKinds fileKinds) + { + return imageFileMachine == ImageFileMachine.ARM ? (ushort)6 : (ushort)4; + } - // we need to start by computing the number of sections, because code.PointerToRawData depends on that - writer.Headers.FileHeader.NumberOfSections = 2; + /// + /// Gets the minor subsystem version. + /// + /// + static ushort GetMinorSubsystemVersion(ImageFileMachine imageFileMachine, IKVM.Reflection.Emit.PEFileKinds fileKinds) + { + return imageFileMachine == ImageFileMachine.ARM ? (ushort)2 : (ushort)0; + } - if (moduleBuilder.initializedData.Length != 0) - { - // .sdata - writer.Headers.FileHeader.NumberOfSections++; - } + /// + /// 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, + }; - if (resources != null) - { - // .rsrc - writer.Headers.FileHeader.NumberOfSections++; - } + /// + /// Obtains the appropriate value for the given and . + /// + /// + /// + /// + /// + static Characteristics GetImageCharacteristics(ImageFileMachine imageFileMachine, IKVM.Reflection.Emit.PEFileKinds fileKind) + { + var characteristics = Characteristics.ExecutableImage; - 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) + switch (imageFileMachine) { - // Resource Directory - writer.Headers.OptionalHeader.DataDirectory[2].VirtualAddress = rsrc.VirtualAddress; - writer.Headers.OptionalHeader.DataDirectory[2].Size = rsrc.VirtualSize; + case ImageFileMachine.UNKNOWN: + break; + case ImageFileMachine.I386: + characteristics |= Characteristics.Bit32Machine; + break; + case ImageFileMachine.ARM: + characteristics |= Characteristics.Bit32Machine | Characteristics.LargeAddressAware; + break; + case ImageFileMachine.AMD64: + case ImageFileMachine.IA64: + case ImageFileMachine.ARM64: + characteristics |= Characteristics.LargeAddressAware; + break; + default: + throw new ArgumentOutOfRangeException("imageFileMachine"); } - 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) + switch (fileKind) { - // Base Relocation Directory - writer.Headers.OptionalHeader.DataDirectory[5].VirtualAddress = reloc.VirtualAddress; - writer.Headers.OptionalHeader.DataDirectory[5].Size = reloc.VirtualSize; + case IKVM.Reflection.Emit.PEFileKinds.Dll: + characteristics |= Characteristics.Dll; + break; } - 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; - - 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; - } - else - { - writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA + writer.Thumb; - } + return characteristics; + } - 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); + /// + /// Gets the size of the stack reserve. + /// + /// + /// + /// + static ulong GetSizeOfStackReserve(IKVM.Reflection.Emit.ModuleBuilder module, bool is64BitArch) + { + return is64BitArch ? DefaultSizeOfStackReserve64Bit : DefaultSizeOfStackReserve32Bit; + } - stream.Seek(text.PointerToRawData, SeekOrigin.Begin); - code.Write(mw, sdata.VirtualAddress, out var guidHeapOffset); + /// + /// Gets the size of the stack commit. + /// + /// + /// + /// + static ulong GetSizeOfStackCommit(IKVM.Reflection.Emit.ModuleBuilder module, bool is64BitArch) + { + return is64BitArch ? DefaultSizeOfStackCommit64Bit : DefaultSizeOfStackCommit32Bit; + } - if (sdata.SizeOfRawData != 0) - { - stream.Seek(sdata.PointerToRawData, SeekOrigin.Begin); - mw.Write(moduleBuilder.initializedData); - } + /// + /// Gets the size of the heap reserve. + /// + /// + /// + /// + static ulong GetSizeOfHeapReserve(IKVM.Reflection.Emit.ModuleBuilder module, bool is64BitArch) + { + return is64BitArch ? DefaultSizeOfHeapReserve64Bit : DefaultSizeOfHeapReserve32Bit; + } - if (rsrc.SizeOfRawData != 0) - { - stream.Seek(rsrc.PointerToRawData, SeekOrigin.Begin); - resources.Write(mw, rsrc.VirtualAddress); - } + /// + /// Gets the size of the heap commit. + /// + /// + /// + /// + static ulong GetSizeOfHeapCommit(IKVM.Reflection.Emit.ModuleBuilder module, bool is64BitArch) + { + return is64BitArch ? DefaultSizeOfHeapCommit64Bit : DefaultSizeOfHeapCommit32Bit; + } - if (reloc.SizeOfRawData != 0) - { - stream.Seek(reloc.PointerToRawData, SeekOrigin.Begin); - code.WriteRelocations(mw); - } + /// + /// Obtains the appropriate value for the given and . + /// + /// + /// + /// + static CorFlags GetCorFlags(PortableExecutableKinds portableExecutableKind, StrongNameKeyPair keyPair) + { + var flags = default(CorFlags); - // file alignment - stream.SetLength(reloc.PointerToRawData + reloc.SizeOfRawData); + if ((portableExecutableKind & PortableExecutableKinds.ILOnly) != 0) + flags |= CorFlags.ILOnly; + if ((portableExecutableKind & PortableExecutableKinds.Required32Bit) != 0) + flags |= CorFlags.Requires32Bit; + if ((portableExecutableKind & PortableExecutableKinds.Preferred32Bit) != 0) + flags |= CorFlags.Requires32Bit | CorFlags.Prefers32Bit; + if (keyPair != null) + flags |= CorFlags.StrongNameSigned; - // 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); - } + return flags; + } - // do the strong naming - if (keyPair != null) - StrongName(stream, keyPair, writer.HeaderSize, text.PointerToRawData, code.StrongNameSignatureRVA - text.VirtualAddress + text.PointerToRawData, code.StrongNameSignatureLength); + /// + /// 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 + return BlobContentId.GetTimeBasedProvider(); -#if NETFRAMEWORK - if (moduleBuilder.symbolWriter != null) - { - moduleBuilder.WriteSymbolTokenMap(); - moduleBuilder.symbolWriter.Close(); - } -#endif } + /// + /// Computes the length of the strong name signature. + /// + /// + /// static int ComputeStrongNameSignatureLength(byte[] publicKey) { if (publicKey == null) @@ -366,147 +478,46 @@ 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 + foreach (var blob in blobs) { - stream.Seek(0, SeekOrigin.Begin); - SHA1.HashData(stream, hash); - } - finally - { - 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); - } + sha1.TransformFinalBlock(Array.Empty(), 0, 0); -#else - - /// - /// 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, int strongNameSignatureSize) { - 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), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + Array.Reverse(signature); -#endif + // check that our signature length matches + if (signature.Length != strongNameSignatureSize) + throw new InvalidOperationException("Signature length mismatch."); - /// - /// 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/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/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/ResourceDirectoryEntry.cs b/src/IKVM.Reflection/Writer/ResourceDirectoryEntry.cs index 28027b2db1..574310e975 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,60 @@ 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 number of entries added. + /// + public int Count => entries.Count; + + /// + /// 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 +98,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 +112,11 @@ internal ResourceDirectoryEntry this[OrdinalOrName id] } } - private int DirectoryLength + int DirectoryLength { get { - if (Data != null) + if (data != null) { return 16; } @@ -127,16 +154,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 +176,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 +211,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.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/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 deleted file mode 100644 index 8acd4165f4..0000000000 --- a/src/IKVM.Reflection/Writer/TextSection.cs +++ /dev/null @@ -1,808 +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(), - }; - - 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; - } - - } - -} 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); - } - } - - } - -} 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/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..12b720a5f6 100644 --- a/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj +++ b/src/IKVM.Tests.Util/IKVM.Tests.Util.csproj @@ -6,9 +6,6 @@ - + - - - 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.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.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 diff --git a/src/IKVM.Tools.Importer/CompilerClassLoader.cs b/src/IKVM.Tools.Importer/CompilerClassLoader.cs index ed4c6c9c93..b95c9fe09e 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 }); @@ -3376,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/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/IKVM.Tools.Importer/IkvmImporterInternal.cs b/src/IKVM.Tools.Importer/IkvmImporterInternal.cs index 0d7c4378cb..62cf96e800 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; - } } } } @@ -406,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) @@ -496,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)); @@ -529,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") @@ -562,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); @@ -570,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 { @@ -579,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)); @@ -613,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:")) { @@ -630,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") @@ -660,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:")) { @@ -721,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; } } @@ -750,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; } } @@ -774,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") @@ -831,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(); @@ -842,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") @@ -906,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); @@ -1055,15 +1026,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) { 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 @@ + 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