diff --git a/.runsettings b/.runsettings new file mode 100644 index 00000000..fe2e508b --- /dev/null +++ b/.runsettings @@ -0,0 +1,9 @@ + + + + + 120000 + net472 + x64 + + \ No newline at end of file diff --git a/MetadataProcessor.Console/Program.cs b/MetadataProcessor.Console/Program.cs index 87d7c29a..3d4e121e 100644 --- a/MetadataProcessor.Console/Program.cs +++ b/MetadataProcessor.Console/Program.cs @@ -1,18 +1,14 @@ -// -// Copyright (c) .NET Foundation and Contributors -// Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Mono.Cecil; -using nanoFramework.Tools.MetadataProcessor.Core; using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; -using System.Reflection; using System.Xml; +using Mono.Cecil; +using nanoFramework.Tools.MetadataProcessor.Core; namespace nanoFramework.Tools.MetadataProcessor.Console { @@ -93,10 +89,7 @@ public void Compile( _assemblyBuilder.Write(GetBinaryWriter(writer)); } - using (var writer = XmlWriter.Create(Path.ChangeExtension(fileName, "pdbx"))) - { - _assemblyBuilder.Write(writer); - } + _assemblyBuilder.Write(Path.ChangeExtension(fileName, "pdbx")); if (DumpMetadata) { @@ -188,7 +181,7 @@ public void GenerateDependency(string fileName) public static void Main(string[] args) { - FileVersionInfo fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location); + FileVersionInfo fileVersion = FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location); bool isCoreLibrary = false; diff --git a/MetadataProcessor.Console/Properties/AssemblyInfo.cs b/MetadataProcessor.Console/Properties/AssemblyInfo.cs index 90979639..f363be35 100644 --- a/MetadataProcessor.Console/Properties/AssemblyInfo.cs +++ b/MetadataProcessor.Console/Properties/AssemblyInfo.cs @@ -1,10 +1,12 @@ -using System.Reflection; -using System.Runtime.CompilerServices; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; // Information about this assembly is defined by the following attributes. // Change them to the values specific to your project. -[assembly: AssemblyTitle ("nanoFramework.MetadataProcessor.Console")] +[assembly: AssemblyTitle("nanoFramework.MetadataProcessor.Console")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("nanoFramework project contributors")] diff --git a/MetadataProcessor.Core/MetadataProcessor.Core.csproj b/MetadataProcessor.Core/MetadataProcessor.Core.csproj index 01d934d4..c93da7b0 100644 --- a/MetadataProcessor.Core/MetadataProcessor.Core.csproj +++ b/MetadataProcessor.Core/MetadataProcessor.Core.csproj @@ -59,6 +59,16 @@ + + 8.0.0 + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + 8.0.0 + runtime; build; native; contentfiles; analyzers; buildtransitive + all + 8.0.0 runtime; build; native; contentfiles; analyzers; buildtransitive @@ -75,6 +85,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + + 8.0.5 + diff --git a/MetadataProcessor.Core/Properties/AssemblyInfo.cs b/MetadataProcessor.Core/Properties/AssemblyInfo.cs index 7a7628c6..e447b7b5 100644 --- a/MetadataProcessor.Core/Properties/AssemblyInfo.cs +++ b/MetadataProcessor.Core/Properties/AssemblyInfo.cs @@ -1,13 +1,16 @@ -using System.Reflection; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; using System.Runtime.CompilerServices; // Information about this assembly is defined by the following attributes. // Change them to the values specific to your project. -[assembly: AssemblyTitle ("nanoFramework.MetadataProcessor.Core")] -[assembly: AssemblyDescription ("")] -[assembly: AssemblyConfiguration ("")] -[assembly: AssemblyCompany ("nanoFramework project contributors")] -[assembly: AssemblyProduct ("")] -[assembly: AssemblyCopyright ("Copyright (c) 2019 The nanoFramework project contributors")] +[assembly: AssemblyTitle("nanoFramework.MetadataProcessor.Core")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("nanoFramework project contributors")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Copyright (c) 2019 The nanoFramework project contributors")] -[assembly: InternalsVisibleTo("nanoFramework.Tools.MetadataProcessor.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010035b49090a010c2970b2f8df8f66ad47a09583d654c0f2375980cf4afcfb48141ec9fd27d464b93a3216545588a5119d779c0ec66eed7c715567c2315cb908f70403b3bb59018b34096ad29c1c91f8d3c83ad407052ead9112e694660dec0ce7a361bff67781cf041e19d78afd128603dd188eb238186ac5aa6caf418891d5bb2")] \ No newline at end of file +[assembly: InternalsVisibleTo("nanoFramework.Tools.MetadataProcessor.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001001120aa3e809b3da4f65e1b1f65c0a3a1bf6335c39860ca41acb3c48de278c6b63c5df38239ec1f2e32d58cb897c8c174a5f8e78a9c0b6087d3aef373d7d0f3d9be67700fc2a5a38de1fb71b5b6f6046d841ff35abee2e0b0840a6291a312be184eb311baff5fef0ff6895b9a5f2253aed32fb06b819134f6bb9d531488a87ea2")] \ No newline at end of file diff --git a/MetadataProcessor.Core/key.snk b/MetadataProcessor.Core/key.snk index bf5ef8f7..67c9bb0a 100644 Binary files a/MetadataProcessor.Core/key.snk and b/MetadataProcessor.Core/key.snk differ diff --git a/MetadataProcessor.Core/packages.lock.json b/MetadataProcessor.Core/packages.lock.json index 6753ecc4..1081cf76 100644 --- a/MetadataProcessor.Core/packages.lock.json +++ b/MetadataProcessor.Core/packages.lock.json @@ -2,6 +2,18 @@ "version": 1, "dependencies": { ".NETFramework,Version=v4.7.2": { + "Microsoft.Build.Tasks.Git": { + "type": "Direct", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" + }, + "Microsoft.SourceLink.Common": { + "type": "Direct", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" + }, "Microsoft.SourceLink.GitHub": { "type": "Direct", "requested": "[8.0.0, )", @@ -30,15 +42,76 @@ "resolved": "3.7.115", "contentHash": "EpXamaAdRfG/BMxGgvZlTM0npRnkmXUjAj8OdNKd17t4oN+2nvjdv/KnFmzOOMDqvlwB49UCwtOHJrAQTfUBtQ==" }, - "Microsoft.Build.Tasks.Git": { + "System.Text.Json": { + "type": "Direct", + "requested": "[8.0.5, )", + "resolved": "8.0.5", + "contentHash": "0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "8.0.0", + "System.Buffers": "4.5.1", + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "6.0.0", + "System.Text.Encodings.Web": "8.0.0", + "System.Threading.Tasks.Extensions": "4.5.4", + "System.ValueTuple": "4.5.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", "resolved": "8.0.0", - "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" + "contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==", + "dependencies": { + "System.Threading.Tasks.Extensions": "4.5.4" + } }, - "Microsoft.SourceLink.Common": { + "System.Buffers": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.5", + "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } + }, + "System.Numerics.Vectors": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, + "System.Text.Encodings.Web": { "type": "Transitive", "resolved": "8.0.0", - "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" + "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } + }, + "System.ValueTuple": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==" } }, ".NETFramework,Version=v4.7.2/win": {}, diff --git a/MetadataProcessor.MsBuildTask/MetaDataProcessorTask.cs b/MetadataProcessor.MsBuildTask/MetaDataProcessorTask.cs index 2109dc6e..a458b085 100644 --- a/MetadataProcessor.MsBuildTask/MetaDataProcessorTask.cs +++ b/MetadataProcessor.MsBuildTask/MetaDataProcessorTask.cs @@ -1,20 +1,17 @@ -// -// Copyright (c) .NET Foundation and Contributors -// Portions Copyright (c) Microsoft Corporation. All rights reserved. -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using System.ComponentModel; using System; +using System.Collections.Generic; +using System.ComponentModel; using System.IO; using System.Linq; -using System.Collections.Generic; -using nanoFramework.Tools.Utilities; using System.Xml; -using nanoFramework.Tools.MetadataProcessor.Core; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; using Mono.Cecil; +using nanoFramework.Tools.MetadataProcessor.Core; +using nanoFramework.Tools.Utilities; namespace nanoFramework.Tools.MetadataProcessor.MsBuildTask { @@ -126,7 +123,7 @@ public override bool Execute() // developer note: to debug this task set an environment variable like this: // set NFBUILD_TASKS_DEBUG=1 // this will cause the execution to pause bellow so a debugger can be attached - DebuggerHelper.WaitForDebuggerIfEnabled(TasksConstants.BuildTaskDebugVar); + DebuggerHelper.WaitForDebuggerIfEnabled(TasksConstants.BuildTaskDebugVar, Log); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// try @@ -298,6 +295,26 @@ private void ExecuteParse( private void ExecuteCompile( string fileName) { + FileStream logOutputStream = null; + StreamWriter logWriter = null; + string logFile = ""; + + try + { + if (Verbose) + { + logFile = Path.ChangeExtension(fileName, "log.txt"); + + logOutputStream = new FileStream(logFile, FileMode.OpenOrCreate, FileAccess.Write); + logWriter = new StreamWriter(logOutputStream); + Console.SetOut(logWriter); + } + } + catch + { + Log.LogError($"Unable to create log file '{logFile}'."); + } + try { // compile assembly (1st pass) @@ -319,6 +336,12 @@ private void ExecuteCompile( { Log.LogError($"Unable to compile output assembly file '{fileName}' - check parse command results"); + if (Verbose) + { + logWriter?.Close(); + logOutputStream?.Close(); + } + throw; } @@ -342,10 +365,7 @@ private void ExecuteCompile( } // output PDBX - using (var writer = XmlWriter.Create(Path.ChangeExtension(fileName, "pdbx"))) - { - _assemblyBuilder.Write(writer); - } + _assemblyBuilder.Write(Path.ChangeExtension(fileName, "pdbx")); // output assembly metadata if (DumpMetadata) @@ -375,6 +395,14 @@ private void ExecuteCompile( Log.LogError($"Exception minimizing assembly"); throw; } + finally + { + if (Verbose) + { + logWriter?.Close(); + logOutputStream?.Close(); + } + } } private void AddClassToExclude( diff --git a/MetadataProcessor.MsBuildTask/MetadataProcessor.MsBuildTask.csproj b/MetadataProcessor.MsBuildTask/MetadataProcessor.MsBuildTask.csproj index ea5599c8..3ad7a915 100644 --- a/MetadataProcessor.MsBuildTask/MetadataProcessor.MsBuildTask.csproj +++ b/MetadataProcessor.MsBuildTask/MetadataProcessor.MsBuildTask.csproj @@ -15,6 +15,8 @@ git nf-logo.png LICENSE.md + true + true @@ -61,7 +63,8 @@ - + + diff --git a/MetadataProcessor.MsBuildTask/TasksConstants.cs b/MetadataProcessor.MsBuildTask/TasksConstants.cs index 3dc34158..85094792 100644 --- a/MetadataProcessor.MsBuildTask/TasksConstants.cs +++ b/MetadataProcessor.MsBuildTask/TasksConstants.cs @@ -1,13 +1,10 @@ -// -// Copyright (c) .NET Foundation and Contributors -// Portions Copyright (c) Microsoft Corporation. All rights reserved. -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace nanoFramework.Tools { internal class TasksConstants { - public const string BuildTaskDebugVar = "NFBUILD_TASKS_DEBUG"; + public const string BuildTaskDebugVar = "NF_MDP_MSBUILD_TASK_DEBUG"; } } diff --git a/MetadataProcessor.MsBuildTask/Utilities/DebuggerHelper.cs b/MetadataProcessor.MsBuildTask/Utilities/DebuggerHelper.cs index 8e58c240..72217024 100644 --- a/MetadataProcessor.MsBuildTask/Utilities/DebuggerHelper.cs +++ b/MetadataProcessor.MsBuildTask/Utilities/DebuggerHelper.cs @@ -1,18 +1,17 @@ -// -// Copyright (c) .NET Foundation and Contributors -// Portions Copyright (c) Microsoft Corporation. All rights reserved. -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics; using System.Threading; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; namespace nanoFramework.Tools.Utilities { internal static class DebuggerHelper { - public static void WaitForDebuggerIfEnabled(string varName, int timeoutSeconds = 30) + public static void WaitForDebuggerIfEnabled(string varName, TaskLoggingHelper logger, int timeoutSeconds = 30) { // this wait should be only available on debug build // to prevent unwanted wait on VS in machines where the variable is present @@ -21,20 +20,19 @@ public static void WaitForDebuggerIfEnabled(string varName, int timeoutSeconds = var isToEnablePauseForDebug = Environment.GetEnvironmentVariable(varName, EnvironmentVariableTarget.User); - if (!string.IsNullOrEmpty(isToEnablePauseForDebug) + if (!string.IsNullOrEmpty(isToEnablePauseForDebug) && isToEnablePauseForDebug.Equals("1", StringComparison.Ordinal)) { - // output helper messsage to console, hopefully to be read by a human - Console.WriteLine($".NET nanoFramework Metadata Processor msbuild task debugging is enabled. Waiting {timeoutSeconds} seconds for debugger to attach..."); - var currentProcessId = Process.GetCurrentProcess().Id; var currentProcessName = Process.GetProcessById(currentProcessId).ProcessName; - Console.WriteLine( - string.Format("Process Id: {0}, Name: {1}", currentProcessId, currentProcessName) - ); + + // output helper message to console, hopefully to be read by a human + Console.WriteLine($".NET nanoFramework Metadata Processor msbuild task debugging is enabled. Waiting {timeoutSeconds} seconds for debugger to attach on Process Id: {currentProcessId} Name: {currentProcessName}..."); + + logger.LogMessage(MessageImportance.Normal, $"Debugging of .NET nanoFramework Metadata Processor msbuild task is enabled. Waiting {timeoutSeconds} seconds for debugger attachment on Process Id: {currentProcessId} Name: {currentProcessName}..."); // wait N seconds for debugger to attach - while (!Debugger.IsAttached + while (!Debugger.IsAttached && timeoutToWaitForDebugToAttach.TotalSeconds > 0) { Thread.Sleep(1000); diff --git a/MetadataProcessor.Shared/DumpGenerator/AssemblyRef.cs b/MetadataProcessor.Shared/DumpGenerator/AssemblyRef.cs index a0f8da81..6a0c801d 100644 --- a/MetadataProcessor.Shared/DumpGenerator/AssemblyRef.cs +++ b/MetadataProcessor.Shared/DumpGenerator/AssemblyRef.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace nanoFramework.Tools.MetadataProcessor.Core { diff --git a/MetadataProcessor.Shared/DumpGenerator/AttFixedArgs.cs b/MetadataProcessor.Shared/DumpGenerator/AttFixedArgs.cs index d3e2fd65..d819fa6e 100644 --- a/MetadataProcessor.Shared/DumpGenerator/AttFixedArgs.cs +++ b/MetadataProcessor.Shared/DumpGenerator/AttFixedArgs.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace nanoFramework.Tools.MetadataProcessor.Core { diff --git a/MetadataProcessor.Shared/DumpGenerator/AttributeCustom.cs b/MetadataProcessor.Shared/DumpGenerator/AttributeCustom.cs index 8113a0ee..a70e7470 100644 --- a/MetadataProcessor.Shared/DumpGenerator/AttributeCustom.cs +++ b/MetadataProcessor.Shared/DumpGenerator/AttributeCustom.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; @@ -15,6 +13,6 @@ public class AttributeCustom public string TypeToken; - public List FixedArgs = new List(); + public List FixedArgs = new List(); } } diff --git a/MetadataProcessor.Shared/DumpGenerator/DumpAllTable.cs b/MetadataProcessor.Shared/DumpGenerator/DumpAllTable.cs index 2557ac52..0969a994 100644 --- a/MetadataProcessor.Shared/DumpGenerator/DumpAllTable.cs +++ b/MetadataProcessor.Shared/DumpGenerator/DumpAllTable.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; @@ -12,9 +10,12 @@ public class DumpAllTable public List AssemblyReferences = new List(); public List TypeReferences = new List(); public List TypeDefinitions = new List(); + public List TypeSpecifications = new List(); public List MethodDefinitions = new List(); public List InterfaceDefinitions = new List(); public List Attributes = new List(); + public List StringHeap = new List(); public List UserStrings = new List(); + public List GenericParams = new List(); } } diff --git a/MetadataProcessor.Shared/DumpGenerator/DumpTemplates.cs b/MetadataProcessor.Shared/DumpGenerator/DumpTemplates.cs index cbbc4401..b8c72e3f 100644 --- a/MetadataProcessor.Shared/DumpGenerator/DumpTemplates.cs +++ b/MetadataProcessor.Shared/DumpGenerator/DumpTemplates.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace nanoFramework.Tools.MetadataProcessor { @@ -9,30 +7,58 @@ internal partial class DumpTemplates { internal const string DumpAllTemplate = @"{{#each AssemblyReferences}} -AssemblyRefProps [{{ReferenceId}}]: Flags: {{Flags}} '{{Name}}'{{#newline}} +AssemblyRef {{ReferenceId}}{{#newline}} +-------------------------------------------------------{{#newline}} +'{{Name}}'{{#newline}} + Flags: {{Flags}}{{#newline}} +{{#newline}} {{/each}} -{{#if AssemblyReferences}}{{#newline}}{{/if}} {{#each TypeReferences}} -TypeRefProps [{{ReferenceId}}]: Scope: {{Scope}} '{{Name}}'{{#newline}} +TypeRef {{ReferenceId}}{{#newline}} +-------------------------------------------------------{{#newline}} +Scope: {{Scope}}{{#newline}} + '{{Name}}'{{#newline}} {{#each MemberReferences}} - MemberRefProps [{{ReferenceId}}]: '{{Name}}' [{{Signature}}]{{#newline}} + MemberRef {{ReferenceId}}{{#newline}} + -------------------------------------------------------{{#newline}} + '{{Name}}'{{#newline}} + [{{Signature}}]{{#newline}} {{/each}} +{{#newline}} {{/each}} -{{#if TypeReferences}}{{#newline}}{{/if}} {{#each TypeDefinitions}} -TypeDefProps [{{ReferenceId}}]: Flags: {{Flags}} Extends: {{ExtendsType}} Enclosed: {{EnclosedType}} '{{Name}}'{{#newline}} +TypeDef {{ReferenceId}}{{#newline}} +-------------------------------------------------------{{#newline}} + '{{Name}}'{{#newline}} + Flags: {{Flags}}{{#newline}} + Extends: {{ExtendsType}}{{#newline}} + Enclosed: {{EnclosedType}}{{#newline}} +{{#if GenericParameters}} + Generic Parameters{{#newline}} {{#each GenericParameters}} - GenericParam [{{GenericParamToken}}]: Position: ({{Position}}) '{{Name}}' Owner: {{Owner}} [{{Signature}}]{{#newline}} + ({{Position}}) GenericParamToken {{GenericParamToken}} '{{Name}}' Owner: {{Owner}} [{{Signature}}]{{#newline}} {{/each}} +{{/if}} {{#each FieldDefinitions}} - FieldDefProps [{{ReferenceId}}]: Attr: {{Attributes}} Flags: {{Flags}} '{{Name}}' [{{Signature}}]{{#newline}} + FieldDef {{ReferenceId}}{{#newline}} + -------------------------------------------------------{{#newline}} + Attr: {{Attributes}}{{#newline}} + Flags: {{Flags}}{{#newline}} + '{{Name}}'{{#newline}} + [{{Signature}}]{{#newline}} {{/each}} {{#each MethodDefinitions}} - MethodDefProps [{{ReferenceId}}]: Flags: {{Flags}} Impl: {{Implementation}} RVA: {{RVA}} '{{Name}}' [{{Signature}}]{{#newline}} + MethodDef {{ReferenceId}}{{#newline}} + -------------------------------------------------------{{#newline}} + '{{Name}}'{{#newline}} + Flags: {{Flags}}{{#newline}} + Impl: {{Implementation}}{{#newline}} + RVA: {{RVA}}{{#newline}} + [{{Signature}}]{{#newline}} {{#if Locals}} Locals {{Locals}}{{#newline}} {{/if}} @@ -43,28 +69,64 @@ internal partial class DumpTemplates IL count: {{ILCodeInstructionsCount}}{{#newline}} {{/if}} {{#each ILCode}} - {{IL}}{{#newline}} + {{IL}}{{#newline}} {{/each}} {{/each}} {{#each InterfaceDefinitions}} - InterfaceImplProps [{{ReferenceId}}]: Itf: {{Interface}}{{#newline}} + InterfaceImpl {{ReferenceId}} Itf: {{Interface}}{{#newline}} + -------------------------------------------------------{{#newline}} {{/each}} +{{#newline}} {{/each}} -{{#if TypeDefinitions}}{{#newline}}{{/if}} + +{{#each TypeSpecifications}} +TypeSpec {{ReferenceId}}{{#newline}} +-------------------------------------------------------{{#newline}} + '{{Name}}'{{#newline}} +{{#each MemberReferences}} + MemberRef {{ReferenceId}}{{#newline}} + -------------------------------------------------------{{#newline}} + '{{Name}}'{{#newline}} + {{Signature}}{{#newline}} + +{{#if Arguments}} + Argument: {{Arguments}}{{#newline}} +{{/else}} + No arguments +{{/if}} +{{/each}} +{{#newline}} +{{/each}} + +Generic Parameters{{#newline}} +-------------------------------------------------------{{#newline}} +{{#each GenericParams}} +{{Position}} {{Name}} {{Owner}}{{#newline}} +{{/each}} +{{#newline}} {{#each Attributes}} Attribute: {{Name}}::[{{ReferenceId}} {{TypeToken}}]{{#newline}} +-------------------------------------------------------{{#newline}} {{#if FixedArgs}}Fixed Arguments:{{#newline}}{{#else}}{{#newline}}{{/if}} {{#each FixedArgs}} {{Options}} {{Numeric}}{{Text}}{{#newline}} +{{/each}} {{#newline}} {{/each}} + +String Heap{{#newline}} +-------------------------------------------------------{{#newline}} +{{#each StringHeap}} +{{ReferenceId}}: {{Content}}{{#newline}} {{/each}} -{{#if Attributes}}{{#newline}}{{/if}} +{{#newline}} +User Strings{{#newline}} +-------------------------------------------------------{{#newline}} {{#each UserStrings}} -UserString [{{ReferenceId}}]: '{{Content}}'{{#newline}} +{{ReferenceId}} : ({{Length}}) ""{{Content}}""{{#newline}} {{/each}} "; } diff --git a/MetadataProcessor.Shared/DumpGenerator/ExceptionHandler.cs b/MetadataProcessor.Shared/DumpGenerator/ExceptionHandler.cs index 1b798ef8..979a98c2 100644 --- a/MetadataProcessor.Shared/DumpGenerator/ExceptionHandler.cs +++ b/MetadataProcessor.Shared/DumpGenerator/ExceptionHandler.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace nanoFramework.Tools.MetadataProcessor.Core { diff --git a/MetadataProcessor.Shared/DumpGenerator/FieldDef.cs b/MetadataProcessor.Shared/DumpGenerator/FieldDef.cs index dd14c1c9..0998e769 100644 --- a/MetadataProcessor.Shared/DumpGenerator/FieldDef.cs +++ b/MetadataProcessor.Shared/DumpGenerator/FieldDef.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace nanoFramework.Tools.MetadataProcessor.Core { diff --git a/MetadataProcessor.Shared/DumpGenerator/GenericParam.cs b/MetadataProcessor.Shared/DumpGenerator/GenericParam.cs index 010876ce..d8a5a3e4 100644 --- a/MetadataProcessor.Shared/DumpGenerator/GenericParam.cs +++ b/MetadataProcessor.Shared/DumpGenerator/GenericParam.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace nanoFramework.Tools.MetadataProcessor.Core { diff --git a/MetadataProcessor.Shared/DumpGenerator/HeapString.cs b/MetadataProcessor.Shared/DumpGenerator/HeapString.cs new file mode 100644 index 00000000..76c0a916 --- /dev/null +++ b/MetadataProcessor.Shared/DumpGenerator/HeapString.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class HeapString + { + public string ReferenceId; + + public string Content; + } +} diff --git a/MetadataProcessor.Shared/DumpGenerator/ILCode.cs b/MetadataProcessor.Shared/DumpGenerator/ILCode.cs index a2b958b8..200bea4e 100644 --- a/MetadataProcessor.Shared/DumpGenerator/ILCode.cs +++ b/MetadataProcessor.Shared/DumpGenerator/ILCode.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace nanoFramework.Tools.MetadataProcessor.Core { diff --git a/MetadataProcessor.Shared/DumpGenerator/InterfaceDef.cs b/MetadataProcessor.Shared/DumpGenerator/InterfaceDef.cs index e2594158..720352bf 100644 --- a/MetadataProcessor.Shared/DumpGenerator/InterfaceDef.cs +++ b/MetadataProcessor.Shared/DumpGenerator/InterfaceDef.cs @@ -1,9 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// - -using System.Collections.Generic; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace nanoFramework.Tools.MetadataProcessor.Core { diff --git a/MetadataProcessor.Shared/DumpGenerator/LocalDef.cs b/MetadataProcessor.Shared/DumpGenerator/LocalDef.cs index 23059d26..be9509ca 100644 --- a/MetadataProcessor.Shared/DumpGenerator/LocalDef.cs +++ b/MetadataProcessor.Shared/DumpGenerator/LocalDef.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace nanoFramework.Tools.MetadataProcessor.Core { diff --git a/MetadataProcessor.Shared/DumpGenerator/MemberRef.cs b/MetadataProcessor.Shared/DumpGenerator/MemberRef.cs index b3837a71..a03eaf92 100644 --- a/MetadataProcessor.Shared/DumpGenerator/MemberRef.cs +++ b/MetadataProcessor.Shared/DumpGenerator/MemberRef.cs @@ -1,7 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; namespace nanoFramework.Tools.MetadataProcessor.Core { @@ -12,5 +12,7 @@ public class MemberRef public string Name; public string Signature; + + public List Arguments; } } diff --git a/MetadataProcessor.Shared/DumpGenerator/MethodDef.cs b/MetadataProcessor.Shared/DumpGenerator/MethodDef.cs index 8426a9ff..9cc1c426 100644 --- a/MetadataProcessor.Shared/DumpGenerator/MethodDef.cs +++ b/MetadataProcessor.Shared/DumpGenerator/MethodDef.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; diff --git a/MetadataProcessor.Shared/DumpGenerator/TypeDef.cs b/MetadataProcessor.Shared/DumpGenerator/TypeDef.cs index 51b42990..f4e8a42e 100644 --- a/MetadataProcessor.Shared/DumpGenerator/TypeDef.cs +++ b/MetadataProcessor.Shared/DumpGenerator/TypeDef.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; diff --git a/MetadataProcessor.Shared/DumpGenerator/TypeRef.cs b/MetadataProcessor.Shared/DumpGenerator/TypeRef.cs index 1112fa4b..cede04b3 100644 --- a/MetadataProcessor.Shared/DumpGenerator/TypeRef.cs +++ b/MetadataProcessor.Shared/DumpGenerator/TypeRef.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; diff --git a/MetadataProcessor.Shared/DumpGenerator/TypeSpec.cs b/MetadataProcessor.Shared/DumpGenerator/TypeSpec.cs new file mode 100644 index 00000000..aee64d51 --- /dev/null +++ b/MetadataProcessor.Shared/DumpGenerator/TypeSpec.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class TypeSpec + { + public string ReferenceId; + + public string Name; + + public List MemberReferences = new List(); + } +} diff --git a/MetadataProcessor.Shared/DumpGenerator/UserString.cs b/MetadataProcessor.Shared/DumpGenerator/UserString.cs index 68f132d6..f2edc668 100644 --- a/MetadataProcessor.Shared/DumpGenerator/UserString.cs +++ b/MetadataProcessor.Shared/DumpGenerator/UserString.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace nanoFramework.Tools.MetadataProcessor.Core { @@ -9,6 +7,8 @@ public class UserString { public string ReferenceId; + public string Length; + public string Content; } } diff --git a/MetadataProcessor.Shared/Endianness/nanoBinaryWriter.cs b/MetadataProcessor.Shared/Endianness/nanoBinaryWriter.cs index 2fb2fe27..f22cfb74 100644 --- a/MetadataProcessor.Shared/Endianness/nanoBinaryWriter.cs +++ b/MetadataProcessor.Shared/Endianness/nanoBinaryWriter.cs @@ -1,8 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// using System; using System.IO; @@ -311,12 +310,12 @@ public void WriteInt64(long value) /// /// Write metadata token in packed format (variable length). /// - /// Metadata tocken in .NET Mico Framework format. + /// Metadata token in .NET nanoFramework format. public void WriteMetadataToken(uint value) { if (value <= 0x7F) { - WriteByte((byte) value); + WriteByte((byte)value); } else if (value <= 0x3FFF) { diff --git a/MetadataProcessor.Shared/Extensions/ByteArrayExtensions.cs b/MetadataProcessor.Shared/Extensions/ByteArrayExtensions.cs index 68788fae..e68f9457 100644 --- a/MetadataProcessor.Shared/Extensions/ByteArrayExtensions.cs +++ b/MetadataProcessor.Shared/Extensions/ByteArrayExtensions.cs @@ -1,11 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Mono.Cecil; using System.Text; -using System.Linq; namespace nanoFramework.Tools.MetadataProcessor.Core.Extensions { @@ -15,7 +11,7 @@ public static string BufferToHexString(this byte[] buffer) { StringBuilder output = new StringBuilder(); - foreach(byte b in buffer) + foreach (byte b in buffer) { output.Append(b.ToString("X2")); } diff --git a/MetadataProcessor.Shared/Extensions/ClrTableExtensions.cs b/MetadataProcessor.Shared/Extensions/ClrTableExtensions.cs new file mode 100644 index 00000000..99a54a38 --- /dev/null +++ b/MetadataProcessor.Shared/Extensions/ClrTableExtensions.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace nanoFramework.Tools.MetadataProcessor.Core.Extensions +{ + internal static class ClrTableExtensions + { + public static uint ToNanoTokenType(this NanoClrTable value) + { + return ((uint)value << 24); + } + } +} diff --git a/MetadataProcessor.Shared/Extensions/IGenericParameterProviderExtensions.cs b/MetadataProcessor.Shared/Extensions/IGenericParameterProviderExtensions.cs new file mode 100644 index 00000000..3f326ce7 --- /dev/null +++ b/MetadataProcessor.Shared/Extensions/IGenericParameterProviderExtensions.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Mono.Cecil; + +namespace nanoFramework.Tools.MetadataProcessor.Core.Extensions +{ + internal static class IGenericParameterProviderExtensions + { + public static ushort ToEncodedNanoTypeOrMethodDefToken(this IGenericParameterProvider value) + { + // implements .NET nanoFramework encoding for MethodToken + // encodes Method to be decoded with CLR_UncompressTypeOrMethodDefToken + // CLR tables are + // 0: TBL_TypeDef + // 1: TBL_MethodDef + + return nanoTokenHelpers.EncodeTableIndex(value.ToNanoCLRTable(), nanoTokenHelpers.NanoTypeOrMethodDefTokenTables); + } + + public static NanoClrTable ToNanoCLRTable(this IGenericParameterProvider value) + { + if (value is TypeDefinition) + { + return NanoClrTable.TBL_TypeDef; + } + else if (value is MethodDefinition) + { + return NanoClrTable.TBL_MethodDef; + } + else + { + throw new ArgumentException("Unknown conversion to CLR Table."); + } + } + } +} diff --git a/MetadataProcessor.Shared/Extensions/MemberReferenceExtensions.cs b/MetadataProcessor.Shared/Extensions/MemberReferenceExtensions.cs new file mode 100644 index 00000000..3754d86c --- /dev/null +++ b/MetadataProcessor.Shared/Extensions/MemberReferenceExtensions.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Mono.Cecil; + +namespace nanoFramework.Tools.MetadataProcessor.Core.Extensions +{ + internal static class MemberReferenceExtensions + { + public static ushort ToEncodedNanoMethodToken(this MemberReference value) + { + // implements .NET nanoFramework encoding for MethodToken + // encodes Method to be decoded with CLR_UncompressMethodToken + // CLR tables are + // 0: TBL_MethodDef + // 1: TBL_MethodRef + // 3: TBL_TypeSpec + // 4: TBL_MethodSpec + + return nanoTokenHelpers.EncodeTableIndex(value.ToNanoCLRTable(), nanoTokenHelpers.NanoMemberRefTokenTables); + } + + public static NanoClrTable ToNanoCLRTable(this MemberReference value) + { + // this one has to be before the others because generic parameters are also "other" types + if (value is MethodDefinition) + { + return NanoClrTable.TBL_MethodDef; + } + else if (value is MethodSpecification) + { + return NanoClrTable.TBL_MethodSpec; + } + else if (value.Resolve() is MethodReference) + { + if (value.DeclaringType.Scope.MetadataScopeType == MetadataScopeType.AssemblyNameReference) + { + // method ref is external + return NanoClrTable.TBL_MethodRef; + } + else + { + // method ref is internal + return NanoClrTable.TBL_MethodDef; + } + } + else if (value.DeclaringType is TypeSpecification) + { + return NanoClrTable.TBL_TypeSpec; + } + else + { + throw new ArgumentException("Unknown conversion to CLR Table."); + } + } + } +} diff --git a/MetadataProcessor.Shared/Extensions/MethodDefinitionExtensions.cs b/MetadataProcessor.Shared/Extensions/MethodDefinitionExtensions.cs index 4f6afbee..fff7fbc7 100644 --- a/MetadataProcessor.Shared/Extensions/MethodDefinitionExtensions.cs +++ b/MetadataProcessor.Shared/Extensions/MethodDefinitionExtensions.cs @@ -1,11 +1,9 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Mono.Cecil; using System.Linq; using System.Text; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor.Core.Extensions { @@ -13,7 +11,7 @@ internal static class MethodDefinitionExtensions { public static string FullName(this MethodDefinition value) { - if(value.GenericParameters.Count == 0) + if (value.GenericParameters.Count == 0) { return value.Name; } @@ -22,7 +20,7 @@ public static string FullName(this MethodDefinition value) StringBuilder name = new StringBuilder(value.Name); name.Append("<"); - foreach(var p in value.GenericParameters) + foreach (var p in value.GenericParameters) { name.Append(p.Name); if (!p.Equals(value.GenericParameters.Last())) @@ -36,5 +34,25 @@ public static string FullName(this MethodDefinition value) return name.ToString(); } } + + /// + /// Fixed full name with simplified type names. + /// + /// + /// + public static string FixedFullName(this MethodDefinition value) + { + return nanoHelpers.FixTypeNames(value.FullName); + } + + /// + /// Fixed name with simplified type names. + /// + /// + /// + public static string FixedName(this MethodDefinition value) + { + return nanoHelpers.FixTypeNames(value.Name); + } } } diff --git a/MetadataProcessor.Shared/Extensions/MethodReferenceExtensions.cs b/MetadataProcessor.Shared/Extensions/MethodReferenceExtensions.cs new file mode 100644 index 00000000..2edd0672 --- /dev/null +++ b/MetadataProcessor.Shared/Extensions/MethodReferenceExtensions.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Mono.Cecil; + +namespace nanoFramework.Tools.MetadataProcessor.Core.Extensions +{ + internal static class MethodReferenceExtensions + { + public static ushort ToEncodedNanoMethodToken(this MethodReference value) + { + // implements .NET nanoFramework encoding for MethodToken + // encodes Method to be decoded with CLR_UncompressMethodToken + // CLR tables are + // 0: TBL_MethodDef + // 1: TBL_MethodRef + + return nanoTokenHelpers.EncodeTableIndex(value.ToNanoCLRTable(), nanoTokenHelpers.NanoMemberRefTokenTables); + } + + private static NanoClrTable ToNanoCLRTable(this MethodReference value) + { + return nanoTokenHelpers.ConvertToNanoCLRTable(value); + } + } +} diff --git a/MetadataProcessor.Shared/Extensions/MethodSpecificationExtensions.cs b/MetadataProcessor.Shared/Extensions/MethodSpecificationExtensions.cs new file mode 100644 index 00000000..90b0a58b --- /dev/null +++ b/MetadataProcessor.Shared/Extensions/MethodSpecificationExtensions.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Mono.Cecil; + +namespace nanoFramework.Tools.MetadataProcessor.Core.Extensions +{ + internal static class MethodSpecificationExtensions + { + public static ushort ToEncodedNanoMethodToken(this MethodSpecification value) + { + // implements .NET nanoFramework encoding for MethodToken + // encodes Method to be decoded with CLR_UncompressMethodToken + // CLR tables are + // 0: TBL_MethodDef + // 1: TBL_MethodRef + + return nanoTokenHelpers.EncodeTableIndex(value.ToNanoCLRTable(), nanoTokenHelpers.NanoMethodDefOrRefTokenTables); + } + + public static NanoClrTable ToNanoCLRTable(this MethodSpecification value) + { + // this one has to be before the others because generic parameters are also "other" types + if (value.Resolve() is MethodDefinition) + { + return NanoClrTable.TBL_MethodDef; + } + else if (value.Resolve() is MethodReference || + value.Resolve() is MethodSpecification) + { + if (value.DeclaringType.Scope.MetadataScopeType == MetadataScopeType.AssemblyNameReference) + { + // method ref is external + return NanoClrTable.TBL_MethodRef; + } + else + { + // method ref is internal + return NanoClrTable.TBL_MethodDef; + } + } + else + { + throw new ArgumentException("Unknown conversion to CLR Table."); + } + } + } +} diff --git a/MetadataProcessor.Shared/Extensions/ParameterDefintionExtensions.cs b/MetadataProcessor.Shared/Extensions/ParameterDefintionExtensions.cs index 930ec1ca..6baf44bf 100644 --- a/MetadataProcessor.Shared/Extensions/ParameterDefintionExtensions.cs +++ b/MetadataProcessor.Shared/Extensions/ParameterDefintionExtensions.cs @@ -1,11 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using Mono.Cecil; -using System.Text; -using System.Linq; namespace nanoFramework.Tools.MetadataProcessor.Core.Extensions { @@ -13,7 +9,7 @@ internal static class ParameterDefintionExtensions { public static string TypeToString(this ParameterDefinition parameter) { - if(parameter.ParameterType is ByReferenceType byReference) + if (parameter.ParameterType is ByReferenceType byReference) { // pointer to native type return " *" + byReference.TypeSignatureAsString(); diff --git a/MetadataProcessor.Shared/Extensions/TypeDefinitionExtensions.cs b/MetadataProcessor.Shared/Extensions/TypeDefinitionExtensions.cs index 5d3294b7..cbbd1a83 100644 --- a/MetadataProcessor.Shared/Extensions/TypeDefinitionExtensions.cs +++ b/MetadataProcessor.Shared/Extensions/TypeDefinitionExtensions.cs @@ -1,10 +1,8 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Mono.Cecil; using System; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor.Core.Extensions { @@ -14,7 +12,7 @@ public static bool IncludeInStub(this TypeDefinition value) { var typeDefFlags = nanoTypeDefinitionTable.GetFlags(value); - if ( typeDefFlags.HasFlag(nanoTypeDefinitionFlags.TD_Delegate) || + if (typeDefFlags.HasFlag(nanoTypeDefinitionFlags.TD_Delegate) || typeDefFlags.HasFlag(nanoTypeDefinitionFlags.TD_MulticastDelegate)) { return false; @@ -23,9 +21,9 @@ public static bool IncludeInStub(this TypeDefinition value) typeDefFlags = typeDefFlags & nanoTypeDefinitionFlags.TD_Semantics; // Only generate a stub for classes and value types. - if (typeDefFlags == nanoTypeDefinitionFlags.TD_Semantics_Class || - typeDefFlags == nanoTypeDefinitionFlags.TD_Semantics_ValueType ) - { + if (typeDefFlags == nanoTypeDefinitionFlags.TD_Semantics_Class || + typeDefFlags == nanoTypeDefinitionFlags.TD_Semantics_ValueType) + { return true; } @@ -42,7 +40,7 @@ public static bool IsToExclude(this TypeDefinition value) public static EnumDeclaration ToEnumDeclaration(this TypeDefinition source) { // sanity check (to prevent missuse) - if(!source.IsEnum) + if (!source.IsEnum) { throw new ArgumentException("Can clone only TypeDefinition that are Enums."); } @@ -52,21 +50,21 @@ public static EnumDeclaration ToEnumDeclaration(this TypeDefinition source) // if there is a namespace remove it (as there can't be two enums with the same name) - if(!string.IsNullOrEmpty(source.Namespace)) + if (!string.IsNullOrEmpty(source.Namespace)) { enumName = source.FullName.Replace(source.Namespace, ""); - + // remove trailing dot enumName = enumName.Replace(".", ""); } else { - if( + if ( source.DeclaringType != null && !string.IsNullOrEmpty(source.DeclaringType.Namespace)) { enumName = source.FullName.Replace(source.DeclaringType.Namespace, ""); - + // remove trailing dot enumName = enumName.Replace(".", ""); @@ -130,9 +128,9 @@ public static EnumDeclaration ToEnumDeclaration(this TypeDefinition source) // enum items are named with the enum name followed by the enum item and respective value // pattern: nnnn_yyyyy var emunItem = new EnumItem() - { - Name = $"{enumName}_{f.Name}", - }; + { + Name = $"{enumName}_{f.Name}", + }; emunItem.Value = f.Constant.ToString(); @@ -142,5 +140,25 @@ public static EnumDeclaration ToEnumDeclaration(this TypeDefinition source) return myEnum; } + + /// + /// Fixed full name with simplified type names. + /// + /// + /// + public static string FixedFullName(this TypeDefinition value) + { + return nanoHelpers.FixTypeNames(value.FullName); + } + + /// + /// Fixed name with simplified type names. + /// + /// + /// + public static string FixedName(this TypeDefinition value) + { + return nanoHelpers.FixTypeNames(value.Name); + } } } diff --git a/MetadataProcessor.Shared/Extensions/TypeReferenceExtensions.cs b/MetadataProcessor.Shared/Extensions/TypeReferenceExtensions.cs index 4149880c..9120350f 100644 --- a/MetadataProcessor.Shared/Extensions/TypeReferenceExtensions.cs +++ b/MetadataProcessor.Shared/Extensions/TypeReferenceExtensions.cs @@ -38,38 +38,38 @@ public static string TypeSignatureAsString(this TypeReference type) return "U"; } - nanoCLR_DataType dataType; + NanoCLRDataType dataType; if (nanoSignaturesTable.PrimitiveTypes.TryGetValue(type.FullName, out dataType)) { switch (dataType) { - case nanoCLR_DataType.DATATYPE_VOID: - case nanoCLR_DataType.DATATYPE_BOOLEAN: - case nanoCLR_DataType.DATATYPE_CHAR: - case nanoCLR_DataType.DATATYPE_I1: - case nanoCLR_DataType.DATATYPE_U1: - case nanoCLR_DataType.DATATYPE_I2: - case nanoCLR_DataType.DATATYPE_U2: - case nanoCLR_DataType.DATATYPE_I4: - case nanoCLR_DataType.DATATYPE_U4: - case nanoCLR_DataType.DATATYPE_I8: - case nanoCLR_DataType.DATATYPE_U8: - case nanoCLR_DataType.DATATYPE_R4: - case nanoCLR_DataType.DATATYPE_BYREF: - case nanoCLR_DataType.DATATYPE_OBJECT: - case nanoCLR_DataType.DATATYPE_WEAKCLASS: + case NanoCLRDataType.DATATYPE_VOID: + case NanoCLRDataType.DATATYPE_BOOLEAN: + case NanoCLRDataType.DATATYPE_CHAR: + case NanoCLRDataType.DATATYPE_I1: + case NanoCLRDataType.DATATYPE_U1: + case NanoCLRDataType.DATATYPE_I2: + case NanoCLRDataType.DATATYPE_U2: + case NanoCLRDataType.DATATYPE_I4: + case NanoCLRDataType.DATATYPE_U4: + case NanoCLRDataType.DATATYPE_I8: + case NanoCLRDataType.DATATYPE_U8: + case NanoCLRDataType.DATATYPE_R4: + case NanoCLRDataType.DATATYPE_BYREF: + case NanoCLRDataType.DATATYPE_OBJECT: + case NanoCLRDataType.DATATYPE_WEAKCLASS: return dataType.ToString().Replace("DATATYPE_", ""); - case nanoCLR_DataType.DATATYPE_LAST_PRIMITIVE: + case NanoCLRDataType.DATATYPE_LAST_PRIMITIVE: return "STRING"; - case nanoCLR_DataType.DATATYPE_LAST_PRIMITIVE_TO_PRESERVE: + case NanoCLRDataType.DATATYPE_LAST_PRIMITIVE_TO_PRESERVE: return "R8"; - case nanoCLR_DataType.DATATYPE_LAST_PRIMITIVE_TO_MARSHAL: + case NanoCLRDataType.DATATYPE_LAST_PRIMITIVE_TO_MARSHAL: return "TIMESPAN"; - case nanoCLR_DataType.DATATYPE_REFLECTION: + case NanoCLRDataType.DATATYPE_REFLECTION: return type.FullName.Replace(".", ""); } } @@ -113,10 +113,23 @@ public static string TypeSignatureAsString(this TypeReference type) return byrefSig.ToString(); } - if (type.IsGenericParameter || - type.IsGenericInstance) + if (type.IsGenericParameter) { - return $"!!{type.Name}"; + StringBuilder genericParamTypeSig = new StringBuilder(); + + if ((type as GenericParameter).Owner is TypeDefinition) + { + genericParamTypeSig.Append("!"); + } + if ((type as GenericParameter).Owner is MethodDefinition) + { + genericParamTypeSig.Append("!!"); + } + + genericParamTypeSig.Append($"{type.Name}"); + + + return genericParamTypeSig.ToString(); } return ""; @@ -124,44 +137,44 @@ public static string TypeSignatureAsString(this TypeReference type) public static string ToNativeTypeAsString(this TypeReference type) { - nanoCLR_DataType dataType; + NanoCLRDataType dataType; if (nanoSignaturesTable.PrimitiveTypes.TryGetValue(type.FullName, out dataType)) { switch (dataType) { - case nanoCLR_DataType.DATATYPE_VOID: + case NanoCLRDataType.DATATYPE_VOID: return "void"; - case nanoCLR_DataType.DATATYPE_BOOLEAN: + case NanoCLRDataType.DATATYPE_BOOLEAN: return "bool"; - case nanoCLR_DataType.DATATYPE_CHAR: + case NanoCLRDataType.DATATYPE_CHAR: return "char"; - case nanoCLR_DataType.DATATYPE_I1: + case NanoCLRDataType.DATATYPE_I1: return "int8_t"; - case nanoCLR_DataType.DATATYPE_U1: + case NanoCLRDataType.DATATYPE_U1: return "uint8_t"; - case nanoCLR_DataType.DATATYPE_I2: + case NanoCLRDataType.DATATYPE_I2: return "int16_t"; - case nanoCLR_DataType.DATATYPE_U2: + case NanoCLRDataType.DATATYPE_U2: return "uint16_t"; - case nanoCLR_DataType.DATATYPE_I4: + case NanoCLRDataType.DATATYPE_I4: return "signed int"; - case nanoCLR_DataType.DATATYPE_U4: + case NanoCLRDataType.DATATYPE_U4: return "unsigned int"; - case nanoCLR_DataType.DATATYPE_I8: + case NanoCLRDataType.DATATYPE_I8: return "int64_t"; - case nanoCLR_DataType.DATATYPE_U8: + case NanoCLRDataType.DATATYPE_U8: return "uint64_t"; - case nanoCLR_DataType.DATATYPE_R4: + case NanoCLRDataType.DATATYPE_R4: return "float"; - case nanoCLR_DataType.DATATYPE_BYREF: + case NanoCLRDataType.DATATYPE_BYREF: return ""; // system.String - case nanoCLR_DataType.DATATYPE_LAST_PRIMITIVE: + case NanoCLRDataType.DATATYPE_LAST_PRIMITIVE: return "const char*"; // System.Double - case nanoCLR_DataType.DATATYPE_LAST_PRIMITIVE_TO_PRESERVE: + case NanoCLRDataType.DATATYPE_LAST_PRIMITIVE_TO_PRESERVE: return "double"; default: @@ -196,44 +209,44 @@ public static string ToNativeTypeAsString(this TypeReference type) public static string ToCLRTypeAsString(this TypeReference type) { - nanoCLR_DataType dataType; + NanoCLRDataType dataType; if (nanoSignaturesTable.PrimitiveTypes.TryGetValue(type.FullName, out dataType)) { switch (dataType) { - case nanoCLR_DataType.DATATYPE_VOID: + case NanoCLRDataType.DATATYPE_VOID: return "void"; - case nanoCLR_DataType.DATATYPE_BOOLEAN: + case NanoCLRDataType.DATATYPE_BOOLEAN: return "bool"; - case nanoCLR_DataType.DATATYPE_CHAR: + case NanoCLRDataType.DATATYPE_CHAR: return "CHAR"; - case nanoCLR_DataType.DATATYPE_I1: + case NanoCLRDataType.DATATYPE_I1: return "INT8"; - case nanoCLR_DataType.DATATYPE_U1: + case NanoCLRDataType.DATATYPE_U1: return "UINT8"; - case nanoCLR_DataType.DATATYPE_I2: + case NanoCLRDataType.DATATYPE_I2: return "INT16"; - case nanoCLR_DataType.DATATYPE_U2: + case NanoCLRDataType.DATATYPE_U2: return "UINT16"; - case nanoCLR_DataType.DATATYPE_I4: + case NanoCLRDataType.DATATYPE_I4: return "INT32"; - case nanoCLR_DataType.DATATYPE_U4: + case NanoCLRDataType.DATATYPE_U4: return "UINT32"; - case nanoCLR_DataType.DATATYPE_I8: + case NanoCLRDataType.DATATYPE_I8: return "INT64"; - case nanoCLR_DataType.DATATYPE_U8: + case NanoCLRDataType.DATATYPE_U8: return "UINT64"; - case nanoCLR_DataType.DATATYPE_R4: + case NanoCLRDataType.DATATYPE_R4: return "float"; - case nanoCLR_DataType.DATATYPE_BYREF: + case NanoCLRDataType.DATATYPE_BYREF: return "NONE"; // system.String - case nanoCLR_DataType.DATATYPE_LAST_PRIMITIVE: + case NanoCLRDataType.DATATYPE_LAST_PRIMITIVE: return "LPCSTR"; // System.Double - case nanoCLR_DataType.DATATYPE_LAST_PRIMITIVE_TO_PRESERVE: + case NanoCLRDataType.DATATYPE_LAST_PRIMITIVE_TO_PRESERVE: return "double"; default: @@ -270,36 +283,36 @@ public static string ToCLRTypeAsString(this TypeReference type) public static nanoSerializationType ToSerializationType(this TypeReference value) { - nanoCLR_DataType dataType; + NanoCLRDataType dataType; if (nanoSignaturesTable.PrimitiveTypes.TryGetValue(value.FullName, out dataType)) { switch (dataType) { - case nanoCLR_DataType.DATATYPE_BOOLEAN: + case NanoCLRDataType.DATATYPE_BOOLEAN: return nanoSerializationType.ELEMENT_TYPE_BOOLEAN; - case nanoCLR_DataType.DATATYPE_I1: + case NanoCLRDataType.DATATYPE_I1: return nanoSerializationType.ELEMENT_TYPE_I1; - case nanoCLR_DataType.DATATYPE_U1: + case NanoCLRDataType.DATATYPE_U1: return nanoSerializationType.ELEMENT_TYPE_U1; - case nanoCLR_DataType.DATATYPE_I2: + case NanoCLRDataType.DATATYPE_I2: return nanoSerializationType.ELEMENT_TYPE_I2; - case nanoCLR_DataType.DATATYPE_U2: + case NanoCLRDataType.DATATYPE_U2: return nanoSerializationType.ELEMENT_TYPE_U2; - case nanoCLR_DataType.DATATYPE_I4: + case NanoCLRDataType.DATATYPE_I4: return nanoSerializationType.ELEMENT_TYPE_I4; - case nanoCLR_DataType.DATATYPE_U4: + case NanoCLRDataType.DATATYPE_U4: return nanoSerializationType.ELEMENT_TYPE_U4; - case nanoCLR_DataType.DATATYPE_I8: + case NanoCLRDataType.DATATYPE_I8: return nanoSerializationType.ELEMENT_TYPE_I8; - case nanoCLR_DataType.DATATYPE_U8: + case NanoCLRDataType.DATATYPE_U8: return nanoSerializationType.ELEMENT_TYPE_U8; - case nanoCLR_DataType.DATATYPE_R4: + case NanoCLRDataType.DATATYPE_R4: return nanoSerializationType.ELEMENT_TYPE_R4; - case nanoCLR_DataType.DATATYPE_R8: + case NanoCLRDataType.DATATYPE_R8: return nanoSerializationType.ELEMENT_TYPE_R8; - case nanoCLR_DataType.DATATYPE_CHAR: + case NanoCLRDataType.DATATYPE_CHAR: return nanoSerializationType.ELEMENT_TYPE_CHAR; - case nanoCLR_DataType.DATATYPE_STRING: + case NanoCLRDataType.DATATYPE_STRING: return nanoSerializationType.ELEMENT_TYPE_STRING; default: return 0; @@ -309,5 +322,64 @@ public static nanoSerializationType ToSerializationType(this TypeReference value return 0; } + public static ushort ToEncodedNanoTypeToken(this TypeReference value) + { + // implements .NET nanoFramework encoding for TypeToken + // encodes TypeReference to be decoded with CLR_UncompressTypeToken + // CLR tables are + // 0: TBL_TypeDef + // 1: TBL_TypeRef + // 2: TBL_TypeSpec + // 3: TBL_GenericParam + + return nanoTokenHelpers.EncodeTableIndex(value.ToNanoCLRTable(), nanoTokenHelpers.NanoTypeTokenTables); + } + + public static ushort ToEncodedNanoTypeDefOrRefToken(this TypeReference value) + { + // implements .NET nanoFramework encoding for TypeToken + // CLR tables are + // 0: TBL_TypeDef + // 1: TBL_TypeRef + + return nanoTokenHelpers.EncodeTableIndex(value.ToNanoCLRTable(), nanoTokenHelpers.NanoTypeDefOrRefTokenTables); + } + + //////////////////////////////////////////// + + /// + /// Encodes a TypeReference or TypeSpecification to CLR_TypeRefOrSpec. + /// + /// + /// + public static ushort ToCLR_TypeRefOrSpec(this TypeReference value) + { + return nanoTokenHelpers.EncodeTableIndex(value.ToNanoCLRTable(), nanoTokenHelpers.CLR_TypeRefOrSpecTables); + } + + private static NanoClrTable ToNanoCLRTable(this TypeReference value) + { + return nanoTokenHelpers.ConvertToNanoCLRTable(value); + } + + /// + /// Fixed full name with simplified type names. + /// + /// + /// + public static string FixedFullName(this TypeReference value) + { + return nanoHelpers.FixTypeNames(value.FullName); + } + + /// + /// Fixed name with simplified type names. + /// + /// + /// + public static string FixedName(this TypeReference value) + { + return nanoHelpers.FixTypeNames(value.Name); + } } } diff --git a/MetadataProcessor.Shared/InanoTable.cs b/MetadataProcessor.Shared/InanoTable.cs index 1677b619..1c3e4933 100644 --- a/MetadataProcessor.Shared/InanoTable.cs +++ b/MetadataProcessor.Shared/InanoTable.cs @@ -1,8 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// namespace nanoFramework.Tools.MetadataProcessor { @@ -18,4 +17,4 @@ public interface InanoTable void Write( nanoBinaryWriter writer); } -} \ No newline at end of file +} diff --git a/MetadataProcessor.Shared/MetadataProcessor.Shared.projitems b/MetadataProcessor.Shared/MetadataProcessor.Shared.projitems index 24e869f3..95fe65aa 100644 --- a/MetadataProcessor.Shared/MetadataProcessor.Shared.projitems +++ b/MetadataProcessor.Shared/MetadataProcessor.Shared.projitems @@ -17,6 +17,7 @@ + @@ -24,10 +25,16 @@ + + + + + + @@ -38,6 +45,9 @@ + + + @@ -47,12 +57,15 @@ + + + @@ -63,16 +76,19 @@ + + - + + \ No newline at end of file diff --git a/MetadataProcessor.Shared/Mono.Cecil/CodeWriter.cs b/MetadataProcessor.Shared/Mono.Cecil/CodeWriter.cs index 5fb16d18..36a46bde 100644 --- a/MetadataProcessor.Shared/Mono.Cecil/CodeWriter.cs +++ b/MetadataProcessor.Shared/Mono.Cecil/CodeWriter.cs @@ -1,14 +1,13 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; -using Mono.Cecil.Cil; using System; using System.Collections.Generic; using System.Linq; +using Mono.Cecil; +using Mono.Cecil.Cil; namespace nanoFramework.Tools.MetadataProcessor { @@ -51,11 +50,11 @@ internal sealed class CodeWriter /// Assembly tables context - contains all tables used for building target assembly. /// public CodeWriter( - MethodDefinition method, + MethodDefinition method, nanoBinaryWriter writer, nanoStringTable stringTable, nanoTablesContext context) - { + { _stringTable = stringTable; _body = method.Body; @@ -109,13 +108,13 @@ public static IEnumerable> PreProcessMethod( switch (instruction.OpCode.OperandType) { case OperandType.InlineSwitch: - var targets = (Instruction[]) instruction.Operand; + var targets = (Instruction[])instruction.Operand; offset -= 3; // One bye used instead of Int32 - offset -= 2 * targets.Length; // each target use Int16 instead of Int32 + offset -= 2 * targets.Length; // each target use Int16 instead of Int32 offsetChanged = true; break; case OperandType.InlineString: - stringTable.GetOrCreateStringId((string) instruction.Operand, true); + stringTable.GetOrCreateStringId((string)instruction.Operand, true); offset -= 2; offsetChanged = true; break; @@ -138,8 +137,8 @@ public static IEnumerable> PreProcessMethod( /// Method body in Mono.Cecil format. /// Maximal evaluated stack size for passed method body. public static byte CalculateStackSize( - MethodBody methodBody) - { + MethodBody methodBody) + { if (methodBody == null) { return 0; @@ -149,16 +148,16 @@ public static byte CalculateStackSize( var size = 0; var maxSize = 0; - foreach (var instruction in methodBody.Instructions) - { + foreach (var instruction in methodBody.Instructions) + { int correctedStackSize; - if (offsets.TryGetValue(instruction.Offset, out correctedStackSize)) - { - size = correctedStackSize; - } + if (offsets.TryGetValue(instruction.Offset, out correctedStackSize)) + { + size = correctedStackSize; + } - switch (instruction.OpCode.Code) - { + switch (instruction.OpCode.Code) + { case Code.Throw: case Code.Endfinally: case Code.Endfilter: @@ -169,30 +168,30 @@ public static byte CalculateStackSize( continue; case Code.Newobj: - { - var method = (MethodReference)instruction.Operand; - size -= method.Parameters.Count; - } - break; + { + var method = (MethodReference)instruction.Operand; + size -= method.Parameters.Count; + } + break; case Code.Callvirt: case Code.Call: - { - var method = (MethodReference)instruction.Operand; - if (method.HasThis) - { - --size; - } - size -= method.Parameters.Count; - if (method.ReturnType.FullName != "System.Void") - { - ++size; - } + { + var method = (MethodReference)instruction.Operand; + if (method.HasThis) + { + --size; } - break; - } + size -= method.Parameters.Count; + if (method.ReturnType.FullName != "System.Void") + { + ++size; + } + } + break; + } - size = CorrectStackDepthByPushes(instruction, size); + size = CorrectStackDepthByPushes(instruction, size); size = CorrectStackDepthByPops(instruction, size); if (instruction.OpCode.OperandType == OperandType.ShortInlineBrTarget || @@ -204,11 +203,11 @@ public static byte CalculateStackSize( offsets[target.Offset] = Math.Max(stackSize, size); } - maxSize = Math.Max(maxSize, size); - } + maxSize = Math.Max(maxSize, size); + } - return (byte)maxSize; - } + return (byte)maxSize; + } private static int CorrectStackDepthByPushes( Instruction instruction, @@ -278,7 +277,7 @@ private void WriteExceptionsTable() { case ExceptionHandlerType.Catch: _writer.WriteUInt16(0x0000); - _writer.WriteUInt16(GetTypeReferenceId(handler.CatchType, 0x8000)); + _writer.WriteUInt16(_context.GetTypeReferenceId(handler.CatchType)); break; case ExceptionHandlerType.Fault: _writer.WriteUInt16(0x0001); @@ -310,216 +309,153 @@ private void WriteExceptionsTable() _writer.WriteByte((byte)_body.ExceptionHandlers.Count); } - private void WriteOpCode ( + private void WriteOpCode( OpCode opcode) - { - if (opcode.Size == 1) + { + if (opcode.Size == 1) { - _writer.WriteByte(opcode.Op2); - } + _writer.WriteByte(opcode.Op2); + } else { _writer.WriteByte(opcode.Op1); _writer.WriteByte(opcode.Op2); } - } + } - private void WriteOperand ( + private void WriteOperand( Instruction instruction) - { + { var opcode = instruction.OpCode; - var operandType = opcode.OperandType; + var operandType = opcode.OperandType; - if (operandType == OperandType.InlineNone) - { + if (operandType == OperandType.InlineNone) + { return; - } + } - var operand = instruction.Operand; - if (operand == null) - { + var operand = instruction.Operand; + if (operand == null) + { throw new ArgumentException(); - } + } - switch (operandType) - { - case OperandType.InlineSwitch: - { - var targets = (Instruction[]) operand; + switch (operandType) + { + case OperandType.InlineSwitch: + { + var targets = (Instruction[])operand; _writer.WriteByte((byte)targets.Length); - var diff = instruction.Offset + opcode.Size + 2 * targets.Length + 1; - foreach (var item in targets) - { - _writer.WriteInt16((short)(GetTargetOffset(item) - diff)); - } - break; - } - case OperandType.ShortInlineBrTarget: - { - var target = (Instruction) operand; - _writer.WriteSByte((sbyte) + var diff = instruction.Offset + opcode.Size + 2 * targets.Length + 1; + foreach (var item in targets) + { + _writer.WriteInt16((short)(GetTargetOffset(item) - diff)); + } + break; + } + case OperandType.ShortInlineBrTarget: + { + var target = (Instruction)operand; + _writer.WriteSByte((sbyte) (GetTargetOffset(target) - (instruction.Offset + opcode.Size + 1))); - break; - } - case OperandType.InlineBrTarget: - { - var target = (Instruction) operand; + break; + } + case OperandType.InlineBrTarget: + { + var target = (Instruction)operand; _writer.WriteInt16((short) (GetTargetOffset(target) - (instruction.Offset + opcode.Size + 2))); - break; - } - case OperandType.ShortInlineVar: + break; + } + case OperandType.ShortInlineVar: _writer.WriteByte((byte)GetVariableIndex((VariableDefinition)operand)); - break; - case OperandType.ShortInlineArg: + break; + case OperandType.ShortInlineArg: _writer.WriteByte((byte)GetParameterIndex((ParameterDefinition)operand)); - break; - case OperandType.InlineVar: + break; + case OperandType.InlineVar: _writer.WriteInt16((short)GetVariableIndex((VariableDefinition)operand)); - break; - case OperandType.InlineArg: + break; + case OperandType.InlineArg: _writer.WriteInt16((short)GetParameterIndex((ParameterDefinition)operand)); - break; - case OperandType.InlineSig: - // TODO: implement this properly after finding when such code is generated - //WriteMetadataToken (GetStandAloneSignature ((CallSite) operand)); - break; - case OperandType.ShortInlineI: - if (opcode == OpCodes.Ldc_I4_S) - { + break; + case OperandType.InlineSig: + // TODO: implement this properly after finding when such code is generated + //WriteMetadataToken (GetStandAloneSignature ((CallSite) operand)); + break; + case OperandType.ShortInlineI: + if (opcode == OpCodes.Ldc_I4_S) + { _writer.WriteSByte((sbyte)operand); - } - else - { + } + else + { _writer.WriteByte((byte)operand); } - break; - case OperandType.InlineI: + break; + case OperandType.InlineI: _writer.WriteInt32((int)operand); - break; - case OperandType.InlineI8: + break; + case OperandType.InlineI8: _writer.WriteInt64((long)operand); - break; - case OperandType.ShortInlineR: + break; + case OperandType.ShortInlineR: _writer.WriteSingle((float)operand); - break; - case OperandType.InlineR: + break; + case OperandType.InlineR: _writer.WriteDouble((double)operand); - break; - case OperandType.InlineString: - var stringReferenceId = _stringTable.GetOrCreateStringId((string) operand, true); + break; + case OperandType.InlineString: + var stringReferenceId = _stringTable.GetOrCreateStringId((string)operand, true); _writer.WriteUInt16(stringReferenceId); - break; + break; case OperandType.InlineMethod: - _writer.WriteUInt16(_context.GetMethodReferenceId((MethodReference)operand)); + _writer.WriteUInt16(_context.GetMethodReferenceId((MemberReference)operand)); break; case OperandType.InlineType: - _writer.WriteUInt16(GetTypeReferenceId((TypeReference)operand)); + _writer.WriteUInt16(_context.GetTypeReferenceId((TypeReference)operand)); break; - case OperandType.InlineField: - _writer.WriteUInt16(GetFieldReferenceId((FieldReference)operand)); + case OperandType.InlineField: + _writer.WriteUInt16(_context.GetFieldReferenceId((FieldReference)operand)); break; case OperandType.InlineTok: - _writer.WriteUInt32(GetMetadataToken((IMetadataTokenProvider)operand)); + _writer.WriteUInt32(_context.GetMetadataToken((IMetadataTokenProvider)operand)); break; default: - throw new ArgumentException(); - } - } - - private uint GetMetadataToken( - IMetadataTokenProvider token) - { - ushort referenceId; - switch (token.MetadataToken.TokenType) - { - case TokenType.TypeRef: - _context.TypeReferencesTable.TryGetTypeReferenceId((TypeReference)token, out referenceId); - return (uint)0x01000000 | referenceId; - case TokenType.TypeDef: - _context.TypeDefinitionTable.TryGetTypeReferenceId((TypeDefinition)token, out referenceId); - return (uint)0x04000000 | referenceId; - case TokenType.TypeSpec: - _context.TypeSpecificationsTable.TryGetTypeReferenceId((TypeReference) token, out referenceId); - return (uint)0x08000000 | referenceId; - case TokenType.Field: - _context.FieldsTable.TryGetFieldReferenceId((FieldDefinition) token, false, out referenceId); - return (uint)0x05000000 | referenceId; + throw new ArgumentException(); } - return 0U; } - private ushort GetFieldReferenceId( - FieldReference fieldReference) + private int GetTargetOffset( + Instruction instruction) { - ushort referenceId; - if (_context.FieldReferencesTable.TryGetFieldReferenceId(fieldReference, out referenceId)) + if (instruction == null) { - referenceId |= 0x8000; // External field reference + var last = _body.Instructions[_body.Instructions.Count - 1]; + return last.Offset + last.GetSize(); } - else - { - _context.FieldsTable.TryGetFieldReferenceId(fieldReference.Resolve(), false, out referenceId); - } - return referenceId; + + return instruction.Offset; } - private ushort GetTypeReferenceId( - TypeReference typeReference, - ushort typeReferenceMask = 0x4000) + private static int GetVariableIndex( + VariableDefinition variable) { - ushort referenceId; + return variable.Index; + } - if(typeReference is TypeSpecification) + private int GetParameterIndex( + ParameterDefinition parameter) + { + if (_body.Method.HasThis) { - referenceId = _context.TypeSpecificationsTable.GetOrCreateTypeSpecificationId(typeReference); + if (parameter == _body.ThisParameter) + return 0; - return (ushort)(0x8000 | referenceId); - } - else if (_context.TypeReferencesTable.TryGetTypeReferenceId(typeReference, out referenceId)) - { - referenceId |= typeReferenceMask; // External type reference + return parameter.Index + 1; } - else - { - if (!_context.TypeDefinitionTable.TryGetTypeReferenceId(typeReference.Resolve(), out referenceId)) - { - return 0x8000; - } - } - return referenceId; + return parameter.Index; } - - private int GetTargetOffset ( - Instruction instruction) - { - if (instruction == null) - { - var last = _body.Instructions[_body.Instructions.Count - 1]; - return last.Offset + last.GetSize (); - } - - return instruction.Offset; - } - - private static int GetVariableIndex ( - VariableDefinition variable) - { - return variable.Index; - } - - private int GetParameterIndex ( - ParameterDefinition parameter) - { - if (_body.Method.HasThis) { - if (parameter == _body.ThisParameter) - return 0; - - return parameter.Index + 1; - } - - return parameter.Index; - } } -} \ No newline at end of file +} diff --git a/MetadataProcessor.Shared/Pdbx/Pdbx.cs b/MetadataProcessor.Shared/Pdbx/Pdbx.cs new file mode 100644 index 00000000..d1264e12 --- /dev/null +++ b/MetadataProcessor.Shared/Pdbx/Pdbx.cs @@ -0,0 +1,121 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace nanoFramework.Tools.MetadataProcessor +{ + ////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Any changes in these classes need to be replicated on the same class at the Visual Studio extension // + ////////////////////////////////////////////////////////////////////////////////////////////////////////// + + public partial class Pdbx + { + public Assembly Assembly { get; set; } + } + + public partial class Assembly + { + public Token Token { get; set; } + + public string FileName { get; set; } + + [JsonConverter(typeof(VersionConverter))] + public Version Version { get; set; } + + public List Classes { get; set; } + + public List GenericParams { get; set; } + + public List TypeSpecs { get; set; } + } + + public partial class Class + { + public Token Token { get; set; } + + public string Name { get; set; } + public bool IsEnum { get; set; } = false; + public int NumGenericParams { get; set; } = 0; + public bool IsGenericInstance { get; set; } = false; + + public List Methods { get; set; } + public List Fields { get; set; } + } + + public partial class Field + { + public string Name { get; set; } + public Token Token { get; set; } + } + + public partial class Method + { + public Token Token { get; set; } + + public string Name { get; set; } + public int NumParams { get; set; } = 0; + public int NumLocals { get; set; } = 0; + public int NumGenericParams { get; set; } = 0; + public bool IsGenericInstance { get; set; } = false; + public bool HasByteCode { get; set; } = false; + public List ILMap { get; set; } + } + + public partial class IL + { + public Token Token { get; set; } + } + + public partial class GenericParam + { + public Token Token { get; set; } + + public string Name { get; set; } + } + + public partial class TypeSpec + { + public Token Token { get; set; } + + public string Name { get; set; } + public bool IsGenericInstance { get; set; } = false; + + public List Members { get; set; } + } + + public partial class Member + { + public Token Token { get; set; } + + public string Name { get; set; } + } + + public partial class Token + { + public string CLR { get; set; } + public string NanoCLR { get; set; } + } + + #region Converters + + public class VersionConverter : JsonConverter + { + public override Version Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) => + Version.Parse(reader.GetString()); + + public override void Write( + Utf8JsonWriter writer, + Version value, + JsonSerializerOptions options) => + writer.WriteStringValue(value.ToString(4)); + } + + #endregion +} diff --git a/MetadataProcessor.Shared/Pdbx/PdbxFileHelpers.cs b/MetadataProcessor.Shared/Pdbx/PdbxFileHelpers.cs new file mode 100644 index 00000000..8cba49ff --- /dev/null +++ b/MetadataProcessor.Shared/Pdbx/PdbxFileHelpers.cs @@ -0,0 +1,276 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Text; +using Mono.Cecil; +using nanoFramework.Tools.MetadataProcessor.Core.Extensions; + +namespace nanoFramework.Tools.MetadataProcessor +{ + public partial class Pdbx + { + public Pdbx(nanoTablesContext context) => Assembly = new Assembly(context); + } + + public partial class Assembly + { + private nanoTablesContext _context; + + public Assembly(nanoTablesContext context) + { + _context = context; + + Token = new Token(_context.AssemblyDefinition.MetadataToken); + + FileName = _context.AssemblyDefinition.MainModule.Name; + + Version = _context.AssemblyDefinition.Name.Version; + + Classes = WriteClasses(_context); + + GenericParams = WriteGenericParams(_context); + + TypeSpecs = WriteTypeSpecs(_context); + } + + private List WriteClasses(nanoTablesContext context) + { + var classes = new List(); + + context.TypeDefinitionTable.ForEachItems((nanoToken, item) => WriteClassInfo(classes, context, item, nanoToken)); + + return classes; + } + + private void WriteClassInfo(List classes, nanoTablesContext context, TypeDefinition item, uint nanoToken) + { + classes.Add(new Class(context, item, nanoToken)); + } + + private List WriteGenericParams(nanoTablesContext context) + { + var genericParams = new List(); + + context.GenericParamsTable.ForEachItems((nanoToken, item) => WriteGenericParamInfo(genericParams, context, item, nanoToken)); + + return genericParams; + } + + private void WriteGenericParamInfo(List genericParams, nanoTablesContext context, GenericParameter item, uint nanoToken) + { + genericParams.Add(new GenericParam(context, item, nanoToken)); + } + + private List WriteTypeSpecs(nanoTablesContext context) + { + var typeSpecs = new List(); + + context.TypeSpecificationsTable.ForEachItems((nanoToken, item) => WriteTypeSpecInfo(typeSpecs, context, item)); + + return typeSpecs; + } + + private void WriteTypeSpecInfo(List typeSpecs, nanoTablesContext context, TypeReference item) + { + typeSpecs.Add(new TypeSpec(context, item)); + } + } + + public partial class Class + { + public Class(nanoTablesContext context, TypeDefinition item, uint nanoToken) + { + Token = new Token(item.MetadataToken, NanoClrTable.TBL_TypeDef.ToNanoTokenType() | nanoToken); + + Name = item.FullName; + IsEnum = item.IsEnum; + NumGenericParams = item.GenericParameters.Count; + IsGenericInstance = item.IsGenericInstance; + + Methods = new List(); + + foreach (var method in item.Methods) + { + Methods.Add(new Method(context, method)); + } + + Fields = new List(); + + foreach (var field in item.Fields) + { + Fields.Add(new Field(context, field)); + } + } + } + + public partial class Method + { + public Method(nanoTablesContext context, MethodDefinition method) + { + context.MethodDefinitionTable.TryGetMethodReferenceId(method, out ushort methodToken); + + Token = new Token(method.MetadataToken, NanoClrTable.TBL_MethodDef.ToNanoTokenType() | methodToken); + + Name = method.Name; + NumParams = method.Parameters.Count; + NumLocals = method.HasBody ? method.Body.Variables.Count : 0; + NumGenericParams = method.GenericParameters.Count; + IsGenericInstance = method.IsGenericInstance; + HasByteCode = method.HasBody; + + ILMap = new List(); + + // sanity check vars + uint prevItem1 = 0; + uint prevItem2 = 0; + + foreach (var offset in context.TypeDefinitionTable.GetByteCodeOffsets(method.MetadataToken.ToUInt32())) + { + if (prevItem1 > 0) + { + // 1st pass, load prevs with current values + Debug.Assert(prevItem1 < offset.Item1); + Debug.Assert(prevItem2 < offset.Item2); + } + + ILMap.Add(new IL(offset.Item1, offset.Item2)); + + prevItem1 = offset.Item1; + prevItem2 = offset.Item2; + } + } + } + + public partial class Field + { + public Field(nanoTablesContext context, FieldDefinition field) + { + context.FieldsTable.TryGetFieldReferenceId(field, false, out ushort fieldToken); + + Token = new Token(field.MetadataToken, NanoClrTable.TBL_FieldDef.ToNanoTokenType() | fieldToken); + + Name = field.Name; + } + } + + public partial class IL + { + public IL(uint clrToken, uint nanoToken) + { + Token = new Token(clrToken, nanoToken); + } + } + + public partial class GenericParam + { + public GenericParam(nanoTablesContext context, GenericParameter item, uint nanoToken) + { + Token = new Token(item.MetadataToken, NanoClrTable.TBL_GenericParam.ToNanoTokenType() | nanoToken); + + Name = item.FullName; + } + } + + public partial class TypeSpec + { + public TypeSpec(nanoTablesContext context, TypeReference item) + { + context.TypeSpecificationsTable.TryGetTypeReferenceId(item, out ushort nanoToken); + + // assume that real token index is the same as ours + // need to add one because ours is 0 indexed + var clrToken = new MetadataToken(TokenType.TypeSpec, nanoToken + 1); + + Token = new Token(clrToken, NanoClrTable.TBL_TypeSpec.ToNanoTokenType() | nanoToken); + + if (item.IsGenericInstance) + { + Name = item.FixedFullName(); + } + else if (item.IsGenericParameter) + { + var genericParam = item as GenericParameter; + + StringBuilder typeSpecName = new StringBuilder(); + + if (genericParam.Owner is TypeDefinition) + { + typeSpecName.Append("!"); + } + if (genericParam.Owner is MethodDefinition) + { + typeSpecName.Append("!!"); + } + + typeSpecName.Append(genericParam.Owner.GenericParameters.IndexOf(genericParam)); + + Name = typeSpecName.ToString(); + } + + IsGenericInstance = item.IsGenericInstance; + + Members = new List(); + + if (item.IsGenericInstance) + { + foreach (var mr in context.MethodReferencesTable.Items) + { + if (context.TypeSpecificationsTable.TryGetTypeReferenceId(mr.DeclaringType, out ushort referenceId) && + referenceId == nanoToken) + { + if (context.MethodReferencesTable.TryGetMethodReferenceId(mr, out referenceId)) + { + Members.Add(new Member(mr, NanoClrTable.TBL_MethodRef.ToNanoTokenType() | nanoToken)); + } + } + } + + foreach (var ms in context.MethodSpecificationTable.Items) + { + if (context.TypeSpecificationsTable.TryGetTypeReferenceId(ms.DeclaringType, out ushort referenceId) && + referenceId == nanoToken) + { + if (context.MethodSpecificationTable.TryGetMethodSpecificationId(ms, out ushort methodSpecId)) + { + Members.Add(new Member(ms, NanoClrTable.TBL_MethodSpec.ToNanoTokenType() | nanoToken)); + } + } + } + } + } + } + + public partial class Member + { + public Member(MethodReference mr, uint nanoToken) + { + Token = new Token(mr.MetadataToken, NanoClrTable.TBL_MethodRef.ToNanoTokenType() | nanoToken); + + Name = mr.Name; + } + } + + public partial class Token + { + public Token(MetadataToken metadataToken) + { + CLR = metadataToken.ToUInt32().ToString("X8", CultureInfo.InvariantCulture); + NanoCLR = "00000000"; + } + + public Token(MetadataToken metadataToken, uint nanoToken) + { + CLR = metadataToken.ToUInt32().ToString("X8", CultureInfo.InvariantCulture); + NanoCLR = nanoToken.ToString("X8", CultureInfo.InvariantCulture); + } + + public Token(uint clrToken, uint nanoToken) + { + CLR = clrToken.ToString("X8", CultureInfo.InvariantCulture); + NanoCLR = nanoToken.ToString("X8", CultureInfo.InvariantCulture); + } + } +} diff --git a/MetadataProcessor.Shared/Pdbx/nanoPdbxFileWriter.cs b/MetadataProcessor.Shared/Pdbx/nanoPdbxFileWriter.cs new file mode 100644 index 00000000..80d71ad2 --- /dev/null +++ b/MetadataProcessor.Shared/Pdbx/nanoPdbxFileWriter.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using System.Text.Encodings.Web; +using System.Text.Json; + +namespace nanoFramework.Tools.MetadataProcessor +{ + internal sealed class nanoPdbxFileWriter + { + private readonly nanoTablesContext _context; + + public nanoPdbxFileWriter( + nanoTablesContext context) + { + _context = context; + } + + internal void Write(string fileName) + { + Pdbx pdbxFile = new Pdbx(_context); + + var options = new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + + var pdbxContent = JsonSerializer.SerializeToUtf8Bytes(pdbxFile, options); + File.WriteAllBytes(fileName, pdbxContent); + } + } +} diff --git a/MetadataProcessor.Shared/SkeletonGenerator/AssemblyClass.cs b/MetadataProcessor.Shared/SkeletonGenerator/AssemblyClass.cs index 697d33f5..9d1941ac 100644 --- a/MetadataProcessor.Shared/SkeletonGenerator/AssemblyClass.cs +++ b/MetadataProcessor.Shared/SkeletonGenerator/AssemblyClass.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; diff --git a/MetadataProcessor.Shared/SkeletonGenerator/AssemblyClassStubs.cs b/MetadataProcessor.Shared/SkeletonGenerator/AssemblyClassStubs.cs index 360a942b..aa310287 100644 --- a/MetadataProcessor.Shared/SkeletonGenerator/AssemblyClassStubs.cs +++ b/MetadataProcessor.Shared/SkeletonGenerator/AssemblyClassStubs.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; diff --git a/MetadataProcessor.Shared/SkeletonGenerator/AssemblyClassTable.cs b/MetadataProcessor.Shared/SkeletonGenerator/AssemblyClassTable.cs index 4dfce167..41844ce2 100644 --- a/MetadataProcessor.Shared/SkeletonGenerator/AssemblyClassTable.cs +++ b/MetadataProcessor.Shared/SkeletonGenerator/AssemblyClassTable.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; diff --git a/MetadataProcessor.Shared/SkeletonGenerator/AssemblyLookupTable.cs b/MetadataProcessor.Shared/SkeletonGenerator/AssemblyLookupTable.cs index 1943a05a..9b7b7eae 100644 --- a/MetadataProcessor.Shared/SkeletonGenerator/AssemblyLookupTable.cs +++ b/MetadataProcessor.Shared/SkeletonGenerator/AssemblyLookupTable.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; diff --git a/MetadataProcessor.Shared/SkeletonGenerator/SkeletonTemplates.cs b/MetadataProcessor.Shared/SkeletonGenerator/SkeletonTemplates.cs index 9d696257..357b2a49 100644 --- a/MetadataProcessor.Shared/SkeletonGenerator/SkeletonTemplates.cs +++ b/MetadataProcessor.Shared/SkeletonGenerator/SkeletonTemplates.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace nanoFramework.Tools.MetadataProcessor { diff --git a/MetadataProcessor.Shared/Tables/ICustomStringSorter.cs b/MetadataProcessor.Shared/Tables/ICustomStringSorter.cs index 7d31d351..77c532f1 100644 --- a/MetadataProcessor.Shared/Tables/ICustomStringSorter.cs +++ b/MetadataProcessor.Shared/Tables/ICustomStringSorter.cs @@ -1,8 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// using System.Collections.Generic; @@ -21,4 +20,4 @@ public interface ICustomStringSorter IEnumerable Sort( ICollection strings); } -} \ No newline at end of file +} diff --git a/MetadataProcessor.Shared/Tables/nanoAssemblyReferenceTable.cs b/MetadataProcessor.Shared/Tables/nanoAssemblyReferenceTable.cs index 60ff1bfd..a9c8e9d5 100644 --- a/MetadataProcessor.Shared/Tables/nanoAssemblyReferenceTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoAssemblyReferenceTable.cs @@ -1,12 +1,12 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections.Generic; +using System.Diagnostics; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor { @@ -17,6 +17,14 @@ namespace nanoFramework.Tools.MetadataProcessor public sealed class nanoAssemblyReferenceTable : nanoReferenceTableBase { + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + // // + // when updating this size here need to update matching define in nanoCLR_Types.h in native // + private const int sizeOf_CLR_RECORD_ASSEMBLYREF = 10; + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + /// /// Helper class for comparing two instances of objects /// using property as unique key for comparison. @@ -60,10 +68,14 @@ protected override void WriteSingleItem( return; } - WriteStringReference(writer, item.Name); - writer.WriteUInt16(0); // padding + var writerStartPosition = writer.BaseStream.Position; + WriteStringReference(writer, item.Name); writer.WriteVersion(item.Version); + + var writerEndPosition = writer.BaseStream.Position; + + Debug.Assert((writerEndPosition - writerStartPosition) == sizeOf_CLR_RECORD_ASSEMBLYREF); } /// @@ -77,7 +89,7 @@ protected override void AllocateSingleItemStrings( /// Gets assembly reference ID by assembly name reference in Mono.Cecil format. /// /// Assembly name reference in Mono.Cecil format. - /// Refernce ID for passed item. + /// Reference ID for passed item. public ushort GetReferenceId( AssemblyNameReference assemblyNameReference) { diff --git a/MetadataProcessor.Shared/Tables/nanoAttributesTable.cs b/MetadataProcessor.Shared/Tables/nanoAttributesTable.cs index cf3441ef..3d52e493 100644 --- a/MetadataProcessor.Shared/Tables/nanoAttributesTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoAttributesTable.cs @@ -1,13 +1,12 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections.Generic; using System.Linq; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor { @@ -38,6 +37,8 @@ public sealed class nanoAttributesTable : InanoTable /// private readonly nanoTablesContext _context; + public NanoClrTable TableIndex => NanoClrTable.TBL_Attributes; + /// /// Creates new instance of object. /// @@ -139,4 +140,4 @@ public void RemoveUnusedItems(HashSet set) .Select(a => new Tuple(a.Item1, a.Item2)); } } -} \ No newline at end of file +} diff --git a/MetadataProcessor.Shared/Tables/nanoByteCodeTable.cs b/MetadataProcessor.Shared/Tables/nanoByteCodeTable.cs index ce49a0c1..bf152851 100644 --- a/MetadataProcessor.Shared/Tables/nanoByteCodeTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoByteCodeTable.cs @@ -1,13 +1,12 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections.Generic; using System.IO; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor { @@ -43,6 +42,8 @@ public sealed class nanoByteCodeTable : InanoTable /// private ushort _lastAvailableRva; + public NanoClrTable TableIndex => NanoClrTable.TBL_ByteCode; + /// /// Creates new instance of object. /// diff --git a/MetadataProcessor.Shared/Tables/nanoClrTable.cs b/MetadataProcessor.Shared/Tables/nanoClrTable.cs new file mode 100644 index 00000000..11006475 --- /dev/null +++ b/MetadataProcessor.Shared/Tables/nanoClrTable.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace nanoFramework.Tools.MetadataProcessor +{ + /// + /// .NET nanoFramework PE tables index. + /// + public enum NanoClrTable + { + ////////////////////////////////////////////////////////////////////////////////////// + // // + // !!! KEEP IN SYNC WITH enum NanoCLRTable (in NanoCLR_TypeSystem VS extension) !!! // + // // + // !!! KEEP IN SYNC WITH enum NanoCLRTable (in NanoCLR_Types.h in CLR) !!! // + ////////////////////////////////////////////////////////////////////////////////////// + + TBL_AssemblyRef = 0x00000000, + TBL_TypeRef = 0x00000001, + TBL_FieldRef = 0x00000002, + TBL_MethodRef = 0x00000003, + TBL_TypeDef = 0x00000004, + TBL_FieldDef = 0x00000005, + TBL_MethodDef = 0x00000006, + TBL_GenericParam = 0x00000007, + TBL_MethodSpec = 0x00000008, + TBL_TypeSpec = 0x00000009, + TBL_Attributes = 0x0000000A, + TBL_Resources = 0x0000000B, + TBL_ResourcesData = 0x0000000C, + TBL_Strings = 0x0000000D, + TBL_Signatures = 0x0000000E, + TBL_ByteCode = 0x000000F, + TBL_ResourcesFiles = 0x00000010, + TBL_EndOfAssembly = 0x000000011 + } +} diff --git a/MetadataProcessor.Shared/Tables/nanoEmptyTable.cs b/MetadataProcessor.Shared/Tables/nanoEmptyTable.cs index 44b9662c..ba5371a3 100644 --- a/MetadataProcessor.Shared/Tables/nanoEmptyTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoEmptyTable.cs @@ -1,8 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// namespace nanoFramework.Tools.MetadataProcessor { diff --git a/MetadataProcessor.Shared/Tables/nanoFieldDefinitionTable.cs b/MetadataProcessor.Shared/Tables/nanoFieldDefinitionTable.cs index ea64ce23..6d7e0f7f 100644 --- a/MetadataProcessor.Shared/Tables/nanoFieldDefinitionTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoFieldDefinitionTable.cs @@ -1,13 +1,13 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor { @@ -18,6 +18,14 @@ namespace nanoFramework.Tools.MetadataProcessor public sealed class nanoFieldDefinitionTable : nanoReferenceTableBase { + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + // // + // when updating this size here need to update matching define in nanoCLR_Types.h in native // + private const int sizeOf_CLR_RECORD_FIELDDEF = 8; + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + /// /// Helper class for comparing two instances of objects /// using property as unique key for comparison. @@ -71,11 +79,17 @@ protected override void WriteSingleItem( return; } + var writerStartPosition = writer.BaseStream.Position; + WriteStringReference(writer, item.Name); writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item)); writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item.InitialValue)); writer.WriteUInt16(GetFlags(item)); + + var writerEndPosition = writer.BaseStream.Position; + + Debug.Assert((writerEndPosition - writerStartPosition) == sizeOf_CLR_RECORD_FIELDDEF); } /// diff --git a/MetadataProcessor.Shared/Tables/nanoFieldReferenceTable.cs b/MetadataProcessor.Shared/Tables/nanoFieldReferenceTable.cs index 36305ffa..b8a7db08 100644 --- a/MetadataProcessor.Shared/Tables/nanoFieldReferenceTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoFieldReferenceTable.cs @@ -1,12 +1,13 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections.Generic; +using System.Diagnostics; +using Mono.Cecil; +using nanoFramework.Tools.MetadataProcessor.Core.Extensions; namespace nanoFramework.Tools.MetadataProcessor { @@ -17,6 +18,14 @@ namespace nanoFramework.Tools.MetadataProcessor public sealed class nanoFieldReferenceTable : nanoReferenceTableBase { + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + // // + // when updating this size here need to update matching define in nanoCLR_Types.h in native // + private const int sizeOf_CLR_RECORD_FIELDREF = 6; + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + /// /// Helper class for comparing two instances of objects /// using property as unique key for comparison. @@ -73,57 +82,35 @@ protected override void WriteSingleItem( return; } - bool experimentalCode = true; + var writerStartPosition = writer.BaseStream.Position; - ushort referenceId; - - - if (experimentalCode) + if ((item.DeclaringType is TypeSpecification || + item.DeclaringType is GenericParameter) && + _context.TypeSpecificationsTable.TryGetTypeReferenceId(item.DeclaringType, out ushort referenceId)) { - //////////////////////////////////// - // EXPERIMENTAL CODE FOR GENERICS // - //////////////////////////////////// - - if (_context.TypeReferencesTable.TryGetTypeReferenceId(item.DeclaringType, out referenceId)) - { - WriteStringReference(writer, item.Name); - writer.WriteUInt16(referenceId); - - writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item)); - writer.WriteUInt16(0); // padding - } - else if (_context.TypeReferencesTable.TryGetTypeReferenceId(item.DeclaringType.Resolve(), out referenceId)) - { - WriteStringReference(writer, item.Name); - writer.WriteUInt16(referenceId); - - writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item)); - writer.WriteUInt16(0); // padding - } - else if (_context.TypeDefinitionTable.TryGetTypeReferenceId(item.DeclaringType.Resolve(), out referenceId)) - { - WriteStringReference(writer, item.Name); - writer.WriteUInt16((ushort)(referenceId | 0x8000)); - - writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item)); - writer.WriteUInt16(0); // padding - } - else - { - throw new ArgumentException($"Can't find entry in type reference table for {item.DeclaringType.FullName} for Field {item.FullName}."); - } + // is TypeSpecification + } + else if (_context.TypeReferencesTable.TryGetTypeReferenceId(item.DeclaringType, out referenceId)) + { + // is TypeReference } else { + throw new ArgumentException($"Can't find a type reference for {item.DeclaringType}."); + } - _context.TypeReferencesTable.TryGetTypeReferenceId(item.DeclaringType, out referenceId); + // Name + WriteStringReference(writer, item.Name); - WriteStringReference(writer, item.Name); - writer.WriteUInt16(referenceId); + // Owner + writer.WriteUInt16((ushort)(item.DeclaringType.ToCLR_TypeRefOrSpec() | referenceId)); - writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item)); - writer.WriteUInt16(0); // padding - } + // signature + writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item)); + + var writerEndPosition = writer.BaseStream.Position; + + Debug.Assert((writerEndPosition - writerStartPosition) == sizeOf_CLR_RECORD_FIELDREF); } } } diff --git a/MetadataProcessor.Shared/Tables/nanoGenericParamTable.cs b/MetadataProcessor.Shared/Tables/nanoGenericParamTable.cs index d5a16fc6..2eb26470 100644 --- a/MetadataProcessor.Shared/Tables/nanoGenericParamTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoGenericParamTable.cs @@ -1,11 +1,12 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Mono.Cecil; using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Mono.Cecil; +using nanoFramework.Tools.MetadataProcessor.Core.Extensions; namespace nanoFramework.Tools.MetadataProcessor { @@ -16,11 +17,19 @@ namespace nanoFramework.Tools.MetadataProcessor public sealed class nanoGenericParamTable : nanoReferenceTableBase { + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + // // + // when updating this size here need to update matching define in nanoCLR_Types.h in native // + private const int sizeOf_CLR_RECORD_GENERICPARAM = 10; + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + /// /// Helper class for comparing two instances of objects /// using property as unique key for comparison. /// - private sealed class MemberReferenceComparer : IEqualityComparer + private sealed class GenericParameterComparer : IEqualityComparer { /// public bool Equals(GenericParameter x, GenericParameter y) @@ -45,6 +54,14 @@ public int GetHashCode(GenericParameter obj) } } + /// + /// Maps each unique generic parameter and its type. + /// + private Dictionary _typeForGenericParam = + new Dictionary(); + + public NanoClrTable TableIndex => NanoClrTable.TBL_GenericParam; + /// /// Creates new instance of object. /// @@ -55,21 +72,62 @@ public int GetHashCode(GenericParameter obj) public nanoGenericParamTable( IEnumerable items, nanoTablesContext context) - : base(items, new MemberReferenceComparer(), context) + : base(items, new GenericParameterComparer(), context) { + foreach (var gp in items) + { + var methodWithGenericParam = _context.MethodDefinitionTable.Items.SingleOrDefault(m => m.GenericParameters.Contains(gp)); + + if (methodWithGenericParam != null) + { + // get the first method specification that matches this type AND name + var instanceMethod = _context.MethodSpecificationTable.Items.FirstOrDefault( + mr => mr.DeclaringType.GetElementType() == methodWithGenericParam.DeclaringType && + mr.Name == methodWithGenericParam.Name) as GenericInstanceMethod; + + Debug.Assert(instanceMethod != null, $"Couldn't find a method specification for type {methodWithGenericParam.DeclaringType} when processing generic parameter {gp}."); + + _typeForGenericParam.Add(gp, instanceMethod.GenericArguments.ElementAt(gp.Position)); + } + else + { + var typeWithGenericParam = _context.TypeDefinitionTable.Items.SingleOrDefault(t => t.GenericParameters.Contains(gp)); + + if (typeWithGenericParam != null) + { + if (_context.MethodReferencesTable.Items.Any()) + { + var genericInstance = _context.MethodReferencesTable.Items.FirstOrDefault( + mr => mr.DeclaringType.GetElementType() == typeWithGenericParam) + .DeclaringType as GenericInstanceType; + Debug.Assert(genericInstance != null, $"Couldn't find a method reference for type {typeWithGenericParam} when processing generic parameter {gp}."); + + _typeForGenericParam.Add(gp, genericInstance.GenericArguments.ElementAt(gp.Position)); + } + else + { + _typeForGenericParam.Add(gp, null); + } + } + else + { + _typeForGenericParam.Add(gp, null); + } + } + } } /// - /// Gets method reference ID if possible (if method is external and stored in this table). + /// Gets generic parameter ID if possible (if generic parameter is stored in this table). /// - /// Method reference metadata in Mono.Cecil format. - /// Method reference ID in .NET nanoFramework format. - /// Returns true if reference found, otherwise returns false. + /// Generic parameter TypeReference in Mono.Cecil format. + /// Generic parameter identifier for filling. + /// Returns true the parameter was found, otherwise returns false. public bool TryGetParameterId( - GenericParameter genericParameter, + TypeReference genericParameter, out ushort referenceId) { - return TryGetIdByValue(genericParameter, out referenceId); + return TryGetIdByValue(genericParameter as GenericParameter, out referenceId); } /// @@ -82,7 +140,49 @@ protected override void WriteSingleItem( return; } - // TODO + var writerStartPosition = writer.BaseStream.Position; + + // number + writer.WriteUInt16((ushort)item.Position); + + // flags + writer.WriteUInt16((ushort)item.Attributes); + + // find owner + if (item.Owner is TypeDefinition && + _context.TypeDefinitionTable.TryGetTypeReferenceId(item.Owner as TypeDefinition, out ushort referenceId)) + { + // is TypeDef + } + else if (_context.MethodDefinitionTable.TryGetMethodReferenceId(item.Owner as MethodDefinition, out referenceId)) + { + // is MethodDef + } + else + { + throw new ArgumentException($"Can't find entry in type or method definition tables for generic parameter '{item.FullName}' [0x{item.Owner.MetadataToken.ToInt32():x8}]."); + } + + // owner + writer.WriteUInt16((ushort)(item.Owner.ToEncodedNanoTypeOrMethodDefToken() | referenceId)); + + // Signature + if (_typeForGenericParam[item] != null) + { + writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(_typeForGenericParam[item])); + } + else + { + // no type for this generic parameter + writer.WriteUInt16(0xFFFF); + } + + // name + WriteStringReference(writer, item.Name); + + var writerEndPosition = writer.BaseStream.Position; + + Debug.Assert((writerEndPosition - writerStartPosition) == sizeOf_CLR_RECORD_GENERICPARAM); } } } diff --git a/MetadataProcessor.Shared/Tables/nanoMemberReferenceTable.cs b/MetadataProcessor.Shared/Tables/nanoMemberReferenceTable.cs new file mode 100644 index 00000000..9c15a7c6 --- /dev/null +++ b/MetadataProcessor.Shared/Tables/nanoMemberReferenceTable.cs @@ -0,0 +1,156 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Original work from Oleg Rakhmatulin. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Mono.Cecil; + +namespace nanoFramework.Tools.MetadataProcessor +{ + /// + /// Encapsulates logic for storing methods references list and writing + /// this collected list into target assembly in .NET nanoFramework format. + /// + public sealed class nanoMemberReferencesTable : + nanoReferenceTableBase + { + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + // // + // when updating this size here need to update matching define in nanoCLR_Types.h in native // + private const int sizeOf_CLR_RECORD_MEMBERREF = 6; + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + + /// + /// Helper class for comparing two instances of objects + /// using property as unique key for comparison. + /// + private sealed class MemberReferenceComparer : IEqualityComparer + { + /// + public bool Equals(MemberReference x, MemberReference y) + { + if (x is null) + { + throw new ArgumentNullException(nameof(x)); + } + + if (y is null) + { + throw new ArgumentNullException(nameof(y)); + } + + return x.MetadataToken.ToInt32() == y.MetadataToken.ToInt32(); + } + + /// + public int GetHashCode(MemberReference obj) + { + return obj.MetadataToken.ToInt32().GetHashCode(); + } + } + + /// + /// Creates new instance of object. + /// + /// List of member references in Mono.Cecil format. + /// + /// Assembly tables context - contains all tables used for building target assembly. + /// + public nanoMemberReferencesTable( + IEnumerable items, + nanoTablesContext context) + : base(items, new MemberReferenceComparer(), context) + { + } + + /// + /// Gets member reference ID if possible (if method is external and stored in this table). + /// + /// Member reference metadata in Mono.Cecil format. + /// Member reference ID in .NET nanoFramework format. + /// Returns true if reference found, otherwise returns false. + public bool TryGetMemberReferenceId( + MemberReference memberReference, + out ushort referenceId) + { + return TryGetIdByValue(memberReference, out referenceId); + } + + /// + protected override void WriteSingleItem( + nanoBinaryWriter writer, + MemberReference item) + { + if (!_context.MinimizeComplete) + { + return; + } + + var writerStartPosition = writer.BaseStream.Position; + + ushort tag; + ushort signature = 0; + ushort referenceId = 0; + + if (item is MethodDefinition && + _context.MethodDefinitionTable.TryGetMethodReferenceId(item as MethodDefinition, out referenceId)) + { + // MemberRefParent tag is 3 (MethodDef) + tag = 3; + + signature = 0; + } + else if (_context.TypeReferencesTable.TryGetTypeReferenceId(item.DeclaringType, out referenceId)) + { + // MemberRefParent tag is 1 (TypeRef) + tag = 1; + + // get signature index + signature = _context.SignaturesTable.GetOrCreateSignatureId(item.DeclaringType); + } + else if (_context.TypeSpecificationsTable.TryGetTypeReferenceId(item.DeclaringType, out referenceId)) + { + // MemberRefParent tag is 4 (TypeSpec) + tag = 4; + + // get signature index + signature = _context.SignaturesTable.GetOrCreateSignatureId(item.DeclaringType); + } + else if (_context.TypeDefinitionTable.TryGetTypeReferenceId(item.DeclaringType.Resolve(), out referenceId)) + { + // MemberRefParent tag is 0 (TypeDef) + tag = 0; + + // get signature index + signature = _context.SignaturesTable.GetOrCreateSignatureId(item.DeclaringType.Resolve()); + } + else + { + // developer note: + // The current implementation is lacking support for: ModuleRef and MethodDef + + throw new ArgumentException($"Can't find entry in type reference table for {item.DeclaringType.FullName} for MethodReference {item.FullName}."); + } + + // MethodDefOrRef tag is 3 bits + referenceId = (ushort)(referenceId << 3); + + // OR with tag to form coded index + referenceId |= tag; + + WriteStringReference(writer, item.Name); + writer.WriteUInt16(referenceId); + + writer.WriteUInt16(signature); + + var writerEndPosition = writer.BaseStream.Position; + + Debug.Assert((writerEndPosition - writerStartPosition) == sizeOf_CLR_RECORD_MEMBERREF); + } + } +} diff --git a/MetadataProcessor.Shared/Tables/nanoMethodDefinitionTable.cs b/MetadataProcessor.Shared/Tables/nanoMethodDefinitionTable.cs index 2ee60fb0..7972d674 100644 --- a/MetadataProcessor.Shared/Tables/nanoMethodDefinitionTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoMethodDefinitionTable.cs @@ -1,7 +1,11 @@ -using Mono.Cecil; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor { @@ -12,7 +16,13 @@ namespace nanoFramework.Tools.MetadataProcessor public sealed class nanoMethodDefinitionTable : nanoReferenceTableBase { - private const int sizeOf_CLR_RECORD_METHODDEF = 16; + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + // // + // when updating this size here need to update matching define in nanoCLR_Types.h in native // + private const int sizeOf_CLR_RECORD_METHODDEF = 19; + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// /// /// Helper class for comparing two instances of objects @@ -33,6 +43,8 @@ public int GetHashCode(MethodDefinition that) } } + public NanoClrTable TableIndex => NanoClrTable.TBL_MethodDef; + /// /// Creates new instance of object. /// @@ -65,16 +77,21 @@ protected override void WriteSingleItem( nanoBinaryWriter writer, MethodDefinition item) { - var writerStartPosition = writer.BaseStream.Position; if (!_context.MinimizeComplete) { return; } + var writerStartPosition = writer.BaseStream.Position; + + // Name WriteStringReference(writer, item.Name); + + // RVA writer.WriteUInt16(_context.ByteCodeTable.GetMethodRva(item)); + // Flags writer.WriteUInt32(GetFlags(item)); var parametersCount = (byte)item.Parameters.Count; @@ -83,7 +100,9 @@ protected override void WriteSingleItem( ++parametersCount; // add implicit 'this' pointer into non-static methods } + // RetVal _context.SignaturesTable.WriteDataType(item.ReturnType, writer, false, false, false); + if (item.ReturnType is TypeSpecification) { // developer note @@ -97,13 +116,18 @@ protected override void WriteSingleItem( //} } + // ArgumentsCount writer.WriteByte(parametersCount); + + // LocalsCount writer.WriteByte((byte)(item.HasBody ? item.Body.Variables.Count : 0)); + + // LengthEvalStack writer.WriteByte(CodeWriter.CalculateStackSize(item.Body)); var methodSignature = _context.SignaturesTable.GetOrCreateSignatureId(item); - // locals signature + // Locals signature if (item.HasBody) { writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item.Body.Variables)); @@ -122,6 +146,21 @@ protected override void WriteSingleItem( } } + ushort genericParamRefId = 0xFFFF; + + if (item.HasGenericParameters) + { + // no need to check if it's found + _context.GenericParamsTable.TryGetParameterId(item.GenericParameters.FirstOrDefault(), out genericParamRefId); + } + + // FirstGenericParam + writer.WriteUInt16(genericParamRefId); + + // GenericParamCount + writer.WriteByte((byte)item.GenericParameters.Count); + + // Signature writer.WriteUInt16(methodSignature); var writerEndPosition = writer.BaseStream.Position; @@ -158,8 +197,8 @@ public static uint GetFlags(MethodDefinition method) const uint MD_DelegateBeginInvoke = 0x00040000; const uint MD_DelegateEndInvoke = 0x00080000; - const uint MD_ContainsGenericParameter = 0x00100000; - const uint MD_HasGenericParameter = 0x00200000; + const uint MD_IsGenericInstance = 0x00100000; + const uint MD_ContainsGenericParameter = 0x00200000; const uint MD_Synchronized = 0x01000000; const uint MD_GloballySynchronized = 0x02000000; @@ -242,7 +281,7 @@ public static uint GetFlags(MethodDefinition method) flag |= (method.IsStatic ? MD_StaticConstructor : MD_Constructor); } - if(method.Name == "Finalize" + if (method.Name == "Finalize" && method.ReturnType.FullName == "System.Void" && method.Parameters.Count == 0) { @@ -300,9 +339,9 @@ public static uint GetFlags(MethodDefinition method) flag |= MD_ContainsGenericParameter; } - if (method.HasGenericParameters) + if (method.IsGenericInstance) { - flag |= MD_HasGenericParameter; + flag |= MD_IsGenericInstance; } return flag; diff --git a/MetadataProcessor.Shared/Tables/nanoMethodReferenceTable.cs b/MetadataProcessor.Shared/Tables/nanoMethodReferenceTable.cs index ff04252e..4a09ddc2 100644 --- a/MetadataProcessor.Shared/Tables/nanoMethodReferenceTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoMethodReferenceTable.cs @@ -1,12 +1,13 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections.Generic; +using System.Diagnostics; +using Mono.Cecil; +using nanoFramework.Tools.MetadataProcessor.Core.Extensions; namespace nanoFramework.Tools.MetadataProcessor { @@ -17,6 +18,14 @@ namespace nanoFramework.Tools.MetadataProcessor public sealed class nanoMethodReferenceTable : nanoReferenceTableBase { + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + // // + // when updating this size here need to update matching define in nanoCLR_Types.h in native // + private const int sizeOf_CLR_RECORD_METHODREF = 6; + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + /// /// Helper class for comparing two instances of objects /// using property as unique key for comparison. @@ -36,6 +45,8 @@ public int GetHashCode(MethodReference that) } } + public NanoClrTable TableIndex => NanoClrTable.TBL_MethodRef; + /// /// Creates new instance of object. /// @@ -73,56 +84,35 @@ protected override void WriteSingleItem( return; } - bool experimentalCode = true; - - ushort referenceId; - + var writerStartPosition = writer.BaseStream.Position; - if (experimentalCode) + if ((item.DeclaringType is TypeSpecification || + item.DeclaringType is GenericParameter) && + _context.TypeSpecificationsTable.TryGetTypeReferenceId(item.DeclaringType, out ushort referenceId)) { - //////////////////////////////////// - // EXPERIMENTAL CODE FOR GENERICS // - //////////////////////////////////// - - if (_context.TypeReferencesTable.TryGetTypeReferenceId(item.DeclaringType, out referenceId)) - { - WriteStringReference(writer, item.Name); - writer.WriteUInt16(referenceId); - - writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item)); - writer.WriteUInt16(0); // padding - } - else if (_context.TypeReferencesTable.TryGetTypeReferenceId(item.DeclaringType.Resolve(), out referenceId)) - { - WriteStringReference(writer, item.Name); - writer.WriteUInt16((ushort)(referenceId | 0x8000)); - - writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item)); - writer.WriteUInt16(0); // padding - } - else if (_context.TypeDefinitionTable.TryGetTypeReferenceId(item.DeclaringType.Resolve(), out referenceId)) - { - WriteStringReference(writer, item.Name); - writer.WriteUInt16((ushort)(referenceId | 0x8000)); - - writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item)); - writer.WriteUInt16(0); // padding - } - else - { - throw new ArgumentException($"Can't find entry in type reference table for {item.DeclaringType.FullName} for Method {item.FullName}."); - } + // is TypeSpecification + } + else if (_context.TypeReferencesTable.TryGetTypeReferenceId(item.DeclaringType, out referenceId)) + { + // is TypeReference } else { - _context.TypeReferencesTable.TryGetTypeReferenceId(item.DeclaringType, out referenceId); + throw new ArgumentException($"Can't find a type reference for {item.DeclaringType}."); + } - WriteStringReference(writer, item.Name); - writer.WriteUInt16(referenceId); + // Name + WriteStringReference(writer, item.Name); - writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item)); - writer.WriteUInt16(0); // padding - } + // Owner + writer.WriteUInt16((ushort)(item.DeclaringType.ToCLR_TypeRefOrSpec() | referenceId)); + + // Signature + writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item)); + + var writerEndPosition = writer.BaseStream.Position; + + Debug.Assert((writerEndPosition - writerStartPosition) == sizeOf_CLR_RECORD_METHODREF); } } } diff --git a/MetadataProcessor.Shared/Tables/nanoMethodSpecificationTable.cs b/MetadataProcessor.Shared/Tables/nanoMethodSpecificationTable.cs new file mode 100644 index 00000000..81846591 --- /dev/null +++ b/MetadataProcessor.Shared/Tables/nanoMethodSpecificationTable.cs @@ -0,0 +1,125 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Mono.Cecil; +using nanoFramework.Tools.MetadataProcessor.Core.Extensions; + +namespace nanoFramework.Tools.MetadataProcessor +{ + /// + /// Encapsulates logic for storing method specifications list and writing + /// this collected list into target assembly in .NET nanoFramework format. + /// + public sealed class nanoMethodSpecificationTable : + nanoReferenceTableBase + { + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + // // + // when updating this size here need to update matching define in nanoCLR_Types.h in native // + private const int sizeOf_CLR_RECORD_METHODSPEC = 6; + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + + /// + /// Helper class for comparing two instances of objects + /// using property as unique key for comparison. + /// + private sealed class MemberReferenceComparer : IEqualityComparer + { + /// + public bool Equals(MethodSpecification x, MethodSpecification y) + { + if (x is null) + { + throw new ArgumentNullException(nameof(x)); + } + + if (y is null) + { + throw new ArgumentNullException(nameof(y)); + } + + return x.MetadataToken.ToInt32() == y.MetadataToken.ToInt32(); + } + + /// + public int GetHashCode(MethodSpecification obj) + { + return obj.MetadataToken.ToInt32().GetHashCode(); + } + } + + public NanoClrTable TableIndex => NanoClrTable.TBL_MethodSpec; + + /// + /// Creates new instance of object. + /// + /// List of member references in Mono.Cecil format. + /// + /// Assembly tables context - contains all tables used for building target assembly. + /// + public nanoMethodSpecificationTable( + IEnumerable items, + nanoTablesContext context) + : base(items, new MemberReferenceComparer(), context) + { + } + + /// + /// Gets method specification ID if possible. + /// + /// Method reference metadata in Mono.Cecil format. + /// Method reference ID in .NET nanoFramework format. + /// Returns true if reference found, otherwise returns false. + public bool TryGetMethodSpecificationId( + MethodSpecification genericParameter, + out ushort referenceId) + { + return TryGetIdByValue(genericParameter, out referenceId); + } + + /// + protected override void WriteSingleItem( + nanoBinaryWriter writer, + MethodSpecification item) + { + if (!_context.MinimizeComplete) + { + return; + } + + var writerStartPosition = writer.BaseStream.Position; + + // Method + if (_context.MethodDefinitionTable.TryGetMethodReferenceId(item.Resolve(), out ushort referenceId)) + { + // method is method definition + } + else + { + Debug.Fail($"Can't find a reference for {item.Resolve()}"); + } + + writer.WriteUInt16((ushort)(item.ToEncodedNanoMethodToken() | referenceId)); + + // Instantiation + writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item)); + + // Container + if (_context.TypeSpecificationsTable.TryGetTypeReferenceId(item.DeclaringType, out referenceId)) + { + // method is method definition + } + + writer.WriteUInt16(referenceId); + + var writerEndPosition = writer.BaseStream.Position; + + Debug.Assert((writerEndPosition - writerStartPosition) == sizeOf_CLR_RECORD_METHODSPEC); + } + } +} diff --git a/MetadataProcessor.Shared/Tables/nanoReferenceTableBase.cs b/MetadataProcessor.Shared/Tables/nanoReferenceTableBase.cs index 205ff278..7607f562 100644 --- a/MetadataProcessor.Shared/Tables/nanoReferenceTableBase.cs +++ b/MetadataProcessor.Shared/Tables/nanoReferenceTableBase.cs @@ -1,13 +1,12 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections.Generic; using System.Linq; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor { @@ -172,5 +171,47 @@ public virtual void RemoveUnusedItems(HashSet set) _items = usedItems; } + + public virtual void AddItem(T value, int index = -1) + { + // sanity check + if (_idsByItemsDictionary.ContainsKey(value)) + { + // already there + return; + } + + // need to recreate the items dictionary after adding this new one + + List copyOfItems = new List(); + + foreach (var i in _idsByItemsDictionary) + { + copyOfItems.Add(i.Key); + } + + // add new item... + if (index > -1) + { + // index was specified, so make it happen + copyOfItems.Insert(index, value); + } + else + { + // no index specified, so just add it + copyOfItems.Add(value); + } + + // rebuild dictionary + _idsByItemsDictionary = copyOfItems + .Select((reference, + position) => new { reference, position }) + .ToDictionary(item => item.reference, + item => (ushort)item.position, + _comparer); + + // repopulate items + _items = copyOfItems; + } } } diff --git a/MetadataProcessor.Shared/Tables/nanoResourceDataTable.cs b/MetadataProcessor.Shared/Tables/nanoResourceDataTable.cs index d80f147e..23a8de5d 100644 --- a/MetadataProcessor.Shared/Tables/nanoResourceDataTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoResourceDataTable.cs @@ -1,8 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// using System.Collections.Generic; @@ -18,6 +17,7 @@ public sealed class nanoResourceDataTable : InanoTable /// List of registered resouce data for writing into output stream "as is". /// private readonly IList _dataByteArrays = new List(); + public NanoClrTable TableIndex => NanoClrTable.TBL_ResourcesData; /// /// Gets current offset in resrouces data table (total size of all data blocks). diff --git a/MetadataProcessor.Shared/Tables/nanoResourceFileTable.cs b/MetadataProcessor.Shared/Tables/nanoResourceFileTable.cs index 9729e184..1d33504e 100644 --- a/MetadataProcessor.Shared/Tables/nanoResourceFileTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoResourceFileTable.cs @@ -1,13 +1,12 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections.Generic; using System.IO; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor { @@ -27,6 +26,8 @@ public sealed class nanoResourceFileTable : InanoTable /// private readonly IList> _resouces = new List>(); + public NanoClrTable TableIndex => NanoClrTable.TBL_ResourcesFiles; + /// /// Creates new instance of object. /// @@ -76,4 +77,4 @@ public void Write( } } -} \ No newline at end of file +} diff --git a/MetadataProcessor.Shared/Tables/nanoResourcesTable.cs b/MetadataProcessor.Shared/Tables/nanoResourcesTable.cs index bca808ce..ee9d9d41 100644 --- a/MetadataProcessor.Shared/Tables/nanoResourcesTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoResourcesTable.cs @@ -1,10 +1,8 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections; using System.Collections.Generic; @@ -13,6 +11,7 @@ using System.IO; using System.Linq; using System.Resources; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor { @@ -43,6 +42,8 @@ private enum ResourceKind : byte /// private readonly nanoTablesContext _context; + public NanoClrTable TableIndex => NanoClrTable.TBL_Resources; + /// /// Creates new instance of object. /// diff --git a/MetadataProcessor.Shared/Tables/nanoSignaturesTable.cs b/MetadataProcessor.Shared/Tables/nanoSignaturesTable.cs index b72f4f10..8a4acbb7 100644 --- a/MetadataProcessor.Shared/Tables/nanoSignaturesTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoSignaturesTable.cs @@ -40,67 +40,67 @@ public int GetHashCode(byte[] that) } } - private static readonly IDictionary s_primitiveTypes = - new Dictionary(StringComparer.Ordinal); + private static readonly IDictionary s_primitiveTypes = + new Dictionary(StringComparer.Ordinal); /// /// Built-in types (see flags in c_CLR_RT_DataTypeLookup at CLR Core code) /// - private static readonly IDictionary s_builtInTypes = - new Dictionary(StringComparer.Ordinal); + private static readonly IDictionary s_builtInTypes = + new Dictionary(StringComparer.Ordinal); - public static IDictionary PrimitiveTypes => s_primitiveTypes; + public static IDictionary PrimitiveTypes => s_primitiveTypes; static nanoSignaturesTable() { - s_primitiveTypes.Add(typeof(void).FullName, nanoCLR_DataType.DATATYPE_VOID); + s_primitiveTypes.Add(typeof(void).FullName, NanoCLRDataType.DATATYPE_VOID); - s_primitiveTypes.Add(typeof(sbyte).FullName, nanoCLR_DataType.DATATYPE_I1); - s_primitiveTypes.Add(typeof(short).FullName, nanoCLR_DataType.DATATYPE_I2); - s_primitiveTypes.Add(typeof(int).FullName, nanoCLR_DataType.DATATYPE_I4); - s_primitiveTypes.Add(typeof(long).FullName, nanoCLR_DataType.DATATYPE_I8); + s_primitiveTypes.Add(typeof(sbyte).FullName, NanoCLRDataType.DATATYPE_I1); + s_primitiveTypes.Add(typeof(short).FullName, NanoCLRDataType.DATATYPE_I2); + s_primitiveTypes.Add(typeof(int).FullName, NanoCLRDataType.DATATYPE_I4); + s_primitiveTypes.Add(typeof(long).FullName, NanoCLRDataType.DATATYPE_I8); - s_primitiveTypes.Add(typeof(byte).FullName, nanoCLR_DataType.DATATYPE_U1); - s_primitiveTypes.Add(typeof(ushort).FullName, nanoCLR_DataType.DATATYPE_U2); - s_primitiveTypes.Add(typeof(uint).FullName, nanoCLR_DataType.DATATYPE_U4); - s_primitiveTypes.Add(typeof(ulong).FullName, nanoCLR_DataType.DATATYPE_U8); + s_primitiveTypes.Add(typeof(byte).FullName, NanoCLRDataType.DATATYPE_U1); + s_primitiveTypes.Add(typeof(ushort).FullName, NanoCLRDataType.DATATYPE_U2); + s_primitiveTypes.Add(typeof(uint).FullName, NanoCLRDataType.DATATYPE_U4); + s_primitiveTypes.Add(typeof(ulong).FullName, NanoCLRDataType.DATATYPE_U8); - s_primitiveTypes.Add(typeof(float).FullName, nanoCLR_DataType.DATATYPE_R4); - s_primitiveTypes.Add(typeof(double).FullName, nanoCLR_DataType.DATATYPE_R8); + s_primitiveTypes.Add(typeof(float).FullName, NanoCLRDataType.DATATYPE_R4); + s_primitiveTypes.Add(typeof(double).FullName, NanoCLRDataType.DATATYPE_R8); - s_primitiveTypes.Add(typeof(char).FullName, nanoCLR_DataType.DATATYPE_CHAR); - s_primitiveTypes.Add(typeof(string).FullName, nanoCLR_DataType.DATATYPE_STRING); - s_primitiveTypes.Add(typeof(bool).FullName, nanoCLR_DataType.DATATYPE_BOOLEAN); + s_primitiveTypes.Add(typeof(char).FullName, NanoCLRDataType.DATATYPE_CHAR); + s_primitiveTypes.Add(typeof(string).FullName, NanoCLRDataType.DATATYPE_STRING); + s_primitiveTypes.Add(typeof(bool).FullName, NanoCLRDataType.DATATYPE_BOOLEAN); - s_primitiveTypes.Add(typeof(object).FullName, nanoCLR_DataType.DATATYPE_OBJECT); - s_primitiveTypes.Add(typeof(IntPtr).FullName, nanoCLR_DataType.DATATYPE_I4); - s_primitiveTypes.Add(typeof(UIntPtr).FullName, nanoCLR_DataType.DATATYPE_U4); + s_primitiveTypes.Add(typeof(object).FullName, NanoCLRDataType.DATATYPE_OBJECT); + s_primitiveTypes.Add(typeof(IntPtr).FullName, NanoCLRDataType.DATATYPE_I4); + s_primitiveTypes.Add(typeof(UIntPtr).FullName, NanoCLRDataType.DATATYPE_U4); - s_primitiveTypes.Add(typeof(WeakReference).FullName, nanoCLR_DataType.DATATYPE_WEAKCLASS); + s_primitiveTypes.Add(typeof(WeakReference).FullName, NanoCLRDataType.DATATYPE_WEAKCLASS); // from c_CLR_RT_DataTypeLookup at CLR Core code - s_builtInTypes.Add(typeof(bool).FullName, nanoCLR_DataType.DATATYPE_BOOLEAN); - s_builtInTypes.Add(typeof(char).FullName, nanoCLR_DataType.DATATYPE_CHAR); - s_builtInTypes.Add(typeof(sbyte).FullName, nanoCLR_DataType.DATATYPE_I1); - s_builtInTypes.Add(typeof(byte).FullName, nanoCLR_DataType.DATATYPE_U1); - s_builtInTypes.Add(typeof(short).FullName, nanoCLR_DataType.DATATYPE_I2); - s_builtInTypes.Add(typeof(ushort).FullName, nanoCLR_DataType.DATATYPE_U2); - s_builtInTypes.Add(typeof(int).FullName, nanoCLR_DataType.DATATYPE_I4); - s_builtInTypes.Add(typeof(uint).FullName, nanoCLR_DataType.DATATYPE_U4); - s_builtInTypes.Add(typeof(long).FullName, nanoCLR_DataType.DATATYPE_I8); - s_builtInTypes.Add(typeof(ulong).FullName, nanoCLR_DataType.DATATYPE_U8); - s_builtInTypes.Add(typeof(float).FullName, nanoCLR_DataType.DATATYPE_R4); - s_builtInTypes.Add(typeof(double).FullName, nanoCLR_DataType.DATATYPE_R8); - - s_builtInTypes.Add(typeof(DateTime).FullName, nanoCLR_DataType.DATATYPE_DATETIME); - s_builtInTypes.Add(typeof(TimeSpan).FullName, nanoCLR_DataType.DATATYPE_TIMESPAN); - s_builtInTypes.Add(typeof(string).FullName, nanoCLR_DataType.DATATYPE_STRING); - - s_builtInTypes.Add("System.RuntimeTypeHandle", nanoCLR_DataType.DATATYPE_REFLECTION); - s_builtInTypes.Add("System.RuntimeFieldHandle", nanoCLR_DataType.DATATYPE_REFLECTION); - s_builtInTypes.Add("System.RuntimeMethodHandle", nanoCLR_DataType.DATATYPE_REFLECTION); - - s_builtInTypes.Add(typeof(WeakReference).FullName, nanoCLR_DataType.DATATYPE_WEAKCLASS); + s_builtInTypes.Add(typeof(bool).FullName, NanoCLRDataType.DATATYPE_BOOLEAN); + s_builtInTypes.Add(typeof(char).FullName, NanoCLRDataType.DATATYPE_CHAR); + s_builtInTypes.Add(typeof(sbyte).FullName, NanoCLRDataType.DATATYPE_I1); + s_builtInTypes.Add(typeof(byte).FullName, NanoCLRDataType.DATATYPE_U1); + s_builtInTypes.Add(typeof(short).FullName, NanoCLRDataType.DATATYPE_I2); + s_builtInTypes.Add(typeof(ushort).FullName, NanoCLRDataType.DATATYPE_U2); + s_builtInTypes.Add(typeof(int).FullName, NanoCLRDataType.DATATYPE_I4); + s_builtInTypes.Add(typeof(uint).FullName, NanoCLRDataType.DATATYPE_U4); + s_builtInTypes.Add(typeof(long).FullName, NanoCLRDataType.DATATYPE_I8); + s_builtInTypes.Add(typeof(ulong).FullName, NanoCLRDataType.DATATYPE_U8); + s_builtInTypes.Add(typeof(float).FullName, NanoCLRDataType.DATATYPE_R4); + s_builtInTypes.Add(typeof(double).FullName, NanoCLRDataType.DATATYPE_R8); + + s_builtInTypes.Add(typeof(DateTime).FullName, NanoCLRDataType.DATATYPE_DATETIME); + s_builtInTypes.Add(typeof(TimeSpan).FullName, NanoCLRDataType.DATATYPE_TIMESPAN); + s_builtInTypes.Add(typeof(string).FullName, NanoCLRDataType.DATATYPE_STRING); + + s_builtInTypes.Add("System.RuntimeTypeHandle", NanoCLRDataType.DATATYPE_REFLECTION); + s_builtInTypes.Add("System.RuntimeFieldHandle", NanoCLRDataType.DATATYPE_REFLECTION); + s_builtInTypes.Add("System.RuntimeMethodHandle", NanoCLRDataType.DATATYPE_REFLECTION); + + s_builtInTypes.Add(typeof(WeakReference).FullName, NanoCLRDataType.DATATYPE_WEAKCLASS); } /// @@ -121,6 +121,8 @@ static nanoSignaturesTable() /// private ushort _lastAvailableId; + public NanoClrTable TableIndex => NanoClrTable.TBL_Signatures; + /// /// Creates new instance of object. /// @@ -135,52 +137,75 @@ public nanoSignaturesTable(nanoTablesContext context) } /// - /// Gets existing or creates new singature identifier for method definition. + /// Gets existing or creates new signature identifier for field definition. /// - /// Method definition in Mono.Cecil format. + /// Field definition in Mono.Cecil format. public ushort GetOrCreateSignatureId( - MethodDefinition methodDefinition) + FieldDefinition fieldDefinition) { - var sig = GetSignature(methodDefinition); + var sig = GetSignature(fieldDefinition.FieldType, true); var sigId = GetOrCreateSignatureIdImpl(sig); - if (_verbose) Console.WriteLine($"{methodDefinition.MetadataToken.ToInt32()} -> {sig.BufferToHexString()} -> {sigId.ToString("X4")}"); + if (_verbose) + { + Console.WriteLine($"{fieldDefinition.MetadataToken} ({fieldDefinition.FullName}) {fieldDefinition.MetadataToken.ToInt32():X8} -> {sig.BufferToHexString()} -> {sigId:X4}"); + } return sigId; } /// - /// Gets existing or creates new singature identifier for field definition. + /// Gets existing or creates new signature identifier for the list of generic parameters. /// - /// Field definition in Mono.Cecil format. + /// List of parameters information in Mono.Cecil format. + public ushort GetOrCreateSignatureId(Collection genericParameters) + { + if (genericParameters == null || genericParameters.Count == 0) + { + return 0xFFFF; // No generic parameters + } + + return GetOrCreateSignatureIdImpl(GetSignature(genericParameters)); + } + + /// + /// Gets existing or creates new signature identifier for field reference. + /// + /// Field reference in Mono.Cecil format. public ushort GetOrCreateSignatureId( - FieldDefinition fieldDefinition) + FieldReference fieldReference) { - var sig = GetSignature(fieldDefinition.FieldType, true); + var sig = GetSignature(fieldReference); var sigId = GetOrCreateSignatureIdImpl(sig); - if (_verbose) Console.WriteLine($"{fieldDefinition.MetadataToken.ToInt32()} -> {sig.BufferToHexString()} -> {sigId.ToString("X4")}"); + if (_verbose) + { + Console.WriteLine($"{fieldReference.MetadataToken} ({fieldReference.FullName}) {fieldReference.MetadataToken.ToInt32():X8} -> {sig.BufferToHexString()} -> {sigId:X4}"); + } return sigId; } /// - /// Gets existing or creates new singature identifier for field reference. + /// Gets existing or creates new signature identifier for method definition. /// - /// Field reference in Mono.Cecil format. + /// Method definition in Mono.Cecil format. public ushort GetOrCreateSignatureId( - FieldReference fieldReference) + MethodDefinition methodDefinition) { - var sig = GetSignature(fieldReference); + var sig = GetSignature(methodDefinition); var sigId = GetOrCreateSignatureIdImpl(sig); - if (_verbose) Console.WriteLine($"{fieldReference.MetadataToken.ToInt32()} -> {sig.BufferToHexString()} -> {sigId.ToString("X4")}"); + if (_verbose) + { + Console.WriteLine($"{methodDefinition.MetadataToken} ({methodDefinition.FullName}) {methodDefinition.MetadataToken.ToInt32():X8} -> {sig.BufferToHexString()} -> {sigId:X4}"); + } return sigId; } /// - /// Gets existing or creates new singature identifier for member reference. + /// Gets existing or creates new signature identifier for method reference. /// /// Method reference in Mono.Cecil format. public ushort GetOrCreateSignatureId( @@ -189,13 +214,34 @@ public ushort GetOrCreateSignatureId( var sig = GetSignature(methodReference); var sigId = GetOrCreateSignatureIdImpl(sig); - if (_verbose) Console.WriteLine($"{methodReference.MetadataToken.ToInt32()} -> {sig.BufferToHexString()} -> {sigId.ToString("X4")}"); + if (_verbose) + { + Console.WriteLine($"{methodReference.MetadataToken} ({methodReference.FullName}) {methodReference.MetadataToken.ToInt32():X8} -> {sig.BufferToHexString()} -> {sigId:X4}"); + } + + return sigId; + } + + /// + /// Gets existing or creates new signature identifier for method specification. + /// + /// Method reference in Mono.Cecil format. + public ushort GetOrCreateSignatureId( + MethodSpecification methodSpecification) + { + var sig = GetSignature(methodSpecification); + var sigId = GetOrCreateSignatureIdImpl(sig); + + if (_verbose) + { + Console.WriteLine($"{methodSpecification.MetadataToken} ({methodSpecification.FullName}) {methodSpecification.MetadataToken.ToInt32():X8} -> {sig.BufferToHexString()} -> {sigId:X4}"); + } return sigId; } /// - /// Gets existing or creates new singature identifier for list of local variables. + /// Gets existing or creates new signature identifier for list of local variables. /// /// List of variables information in Mono.Cecil format. public ushort GetOrCreateSignatureId( @@ -210,7 +256,7 @@ public ushort GetOrCreateSignatureId( } /// - /// Gets existing or creates new singature identifier for list of class interfaces. + /// Gets existing or creates new signature identifier for list of class interfaces. /// /// List of interfaes information in Mono.Cecil format. public ushort GetOrCreateSignatureId( @@ -249,7 +295,10 @@ public ushort GetOrCreateSignatureId( var sig = GetSignature(interfaceImplementation, false); var sigId = GetOrCreateSignatureIdImpl(sig); - if (_verbose) Console.WriteLine($"{interfaceImplementation.MetadataToken.ToInt32()} -> {sig.BufferToHexString()} -> {sigId.ToString("X4")}"); + if (_verbose) + { + Console.WriteLine($"{interfaceImplementation.MetadataToken} ({interfaceImplementation.InterfaceType.FullName}) {interfaceImplementation.MetadataToken.ToInt32():X8} -> {sig.BufferToHexString()} -> {sigId:X4}"); + } return sigId; } @@ -264,7 +313,10 @@ public ushort GetOrCreateSignatureId( var sig = GetSignature(typeReference, false); var sigId = GetOrCreateSignatureIdImpl(sig); - if (_verbose) Console.WriteLine($"{typeReference.MetadataToken.ToInt32()} -> {sig.BufferToHexString()} -> {sigId.ToString("X4")}"); + if (_verbose) + { + Console.WriteLine($"{typeReference.MetadataToken} ({typeReference.FullName}) {typeReference.MetadataToken.ToInt32():X8} -> {sig.BufferToHexString()} -> {sigId:X4}"); + } return sigId; } @@ -278,7 +330,10 @@ public ushort GetOrCreateSignatureId(CustomAttribute customAttribute) var sig = GetSignature(customAttribute); var sigId = GetOrCreateSignatureIdImpl(sig); - if (_verbose) Console.WriteLine($"{customAttribute.ToString()} -> {sig.BufferToHexString()} -> {sigId.ToString("X4")}"); + if (_verbose) + { + Console.WriteLine($"{customAttribute} -> {sig.BufferToHexString()} -> {sigId:X4}"); + } return sigId; } @@ -300,13 +355,13 @@ public void WriteDataType( if (isTypeDefinition && typeDefinition.MetadataType == MetadataType.Object) { - writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_CLASS); + writer.WriteByte((byte)NanoCLRDataType.DATATYPE_CLASS); return; } if (s_primitiveTypes.TryGetValue( typeDefinition.FullName, - out nanoCLR_DataType dataType)) + out NanoCLRDataType dataType)) { writer.WriteByte((byte)dataType); return; @@ -319,7 +374,7 @@ public void WriteDataType( if (typeDefinition.MetadataType == MetadataType.Class) { - writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_CLASS); + writer.WriteByte((byte)NanoCLRDataType.DATATYPE_CLASS); if (alsoWriteSubType) { WriteSubTypeInfo(typeDefinition, writer); @@ -340,7 +395,7 @@ public void WriteDataType( } } - writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_VALUETYPE); + writer.WriteByte((byte)NanoCLRDataType.DATATYPE_VALUETYPE); if (alsoWriteSubType) { WriteSubTypeInfo(typeDefinition, writer); @@ -350,7 +405,20 @@ public void WriteDataType( if (typeDefinition.MetadataType == MetadataType.Var) { - writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_MVAR); + writer.WriteByte((byte)NanoCLRDataType.DATATYPE_VAR); + + if (alsoWriteSubType) + { + // following ECMA-335 VI.B.4.3 Metadata + writer.WriteByte((byte)(typeDefinition as GenericParameter).Position); + } + + return; + } + + if (typeDefinition.MetadataType == MetadataType.MVar) + { + writer.WriteByte((byte)NanoCLRDataType.DATATYPE_MVAR); if (alsoWriteSubType) { @@ -363,15 +431,16 @@ public void WriteDataType( if (typeDefinition.IsArray) { - writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_SZARRAY); + writer.WriteByte((byte)NanoCLRDataType.DATATYPE_SZARRAY); var array = (ArrayType)typeDefinition; if (array.ElementType.IsGenericParameter) { // ECMA 335 VI.B.4.3 Metadata - writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_VAR); + writer.WriteByte((byte)NanoCLRDataType.DATATYPE_VAR); + // OK to use byte here as we won't support more than 0x7F generic parameters writer.WriteByte((byte)(array.ElementType as GenericParameter).Position); } else if (alsoWriteSubType) @@ -385,7 +454,7 @@ public void WriteDataType( if (typeDefinition.IsByReference) { - writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_BYREF); + writer.WriteByte((byte)NanoCLRDataType.DATATYPE_BYREF); if (alsoWriteSubType) { @@ -400,12 +469,13 @@ public void WriteDataType( if (typeDefinition.IsGenericInstance) { // following ECMA-335 VI.B.4.3 Metadata - writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_GENERICINST); + // II.23.2.12 Type + writer.WriteByte((byte)NanoCLRDataType.DATATYPE_GENERICINST); var genericType = (GenericInstanceType)typeDefinition; + WriteDataType(genericType.Resolve(), writer, true, expandEnumType, isTypeDefinition); - WriteDataType(genericType.ElementType, writer, false, expandEnumType, isTypeDefinition); - + // OK to use byte here as we won't support more than 0x7F arguments writer.WriteByte((byte)genericType.GenericArguments.Count); foreach (var a in genericType.GenericArguments) @@ -429,7 +499,7 @@ public void WriteDataTypeForTypeDef(TypeDefinition typeDefinition, nanoBinaryWri // start checking with the built-in types if (s_builtInTypes.TryGetValue( typeDefinition.FullName, - out nanoCLR_DataType dataType)) + out NanoCLRDataType dataType)) { writer.WriteByte((byte)dataType); } @@ -446,16 +516,16 @@ public void WriteDataTypeForTypeDef(TypeDefinition typeDefinition, nanoBinaryWri } else { - writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_I4); + writer.WriteByte((byte)NanoCLRDataType.DATATYPE_I4); } } else if (typeDefinition.IsValueType) { - writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_VALUETYPE); + writer.WriteByte((byte)NanoCLRDataType.DATATYPE_VALUETYPE); } else if (typeDefinition.IsClass || typeDefinition.IsInterface) { - writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_CLASS); + writer.WriteByte((byte)NanoCLRDataType.DATATYPE_CLASS); } else { @@ -530,6 +600,35 @@ internal byte[] GetSignature( } } + internal byte[] GetSignature( + MethodSpecification methodSpecification) + { + using (var buffer = new MemoryStream()) + using (var writer = new BinaryWriter(buffer)) // Only Write(Byte) will be used + { + var binaryWriter = nanoBinaryWriter.CreateLittleEndianBinaryWriter(writer); + + var genericInstance = methodSpecification as GenericInstanceMethod; + + // implementation from ECMA-335 II.23.2.15 + + // method calling convention + // IMAGE_CEE_CS_CALLCONV_GENERICINST: 0x0A + + writer.Write((byte)0x0A); + + // generic arguments count + writer.Write((byte)(genericInstance.GenericArguments.Count)); + + foreach (var argument in genericInstance.GenericArguments) + { + WriteTypeInfo(argument.GetElementType(), binaryWriter); + } + + return buffer.ToArray(); + } + } + private byte[] GetSignature( IEnumerable variables) { @@ -587,6 +686,21 @@ private byte[] GetSignature( } } + private byte[] GetSignature(Collection genericParameters) + { + using (var buffer = new MemoryStream()) + // Only Write(Byte) will be used + using (var writer = new BinaryWriter(buffer)) + { + foreach (GenericParameter parameter in genericParameters) + { + WriteGenericParameterValue(writer, parameter); + } + + return buffer.ToArray(); + } + } + private byte[] GetSignature( InterfaceImplementation typeReference, bool isFieldSignature) @@ -643,60 +757,60 @@ private void WriteAttributeArgumentValue( BinaryWriter writer, CustomAttributeArgument argument) { - nanoCLR_DataType dataType; + NanoCLRDataType dataType; if (s_primitiveTypes.TryGetValue(argument.Type.FullName, out dataType)) { switch (dataType) { - case nanoCLR_DataType.DATATYPE_BOOLEAN: + case NanoCLRDataType.DATATYPE_BOOLEAN: writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_BOOLEAN); writer.Write((byte)((bool)argument.Value ? 1 : 0)); break; - case nanoCLR_DataType.DATATYPE_I1: + case NanoCLRDataType.DATATYPE_I1: writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_I1); writer.Write((sbyte)argument.Value); break; - case nanoCLR_DataType.DATATYPE_U1: + case NanoCLRDataType.DATATYPE_U1: writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_U1); writer.Write((byte)argument.Value); break; - case nanoCLR_DataType.DATATYPE_I2: + case NanoCLRDataType.DATATYPE_I2: writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_I2); writer.Write((short)argument.Value); break; - case nanoCLR_DataType.DATATYPE_U2: + case NanoCLRDataType.DATATYPE_U2: writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_U2); writer.Write((ushort)argument.Value); break; - case nanoCLR_DataType.DATATYPE_I4: + case NanoCLRDataType.DATATYPE_I4: writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_I4); writer.Write((int)argument.Value); break; - case nanoCLR_DataType.DATATYPE_U4: + case NanoCLRDataType.DATATYPE_U4: writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_U4); writer.Write((uint)argument.Value); break; - case nanoCLR_DataType.DATATYPE_I8: + case NanoCLRDataType.DATATYPE_I8: writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_I8); writer.Write((long)argument.Value); break; - case nanoCLR_DataType.DATATYPE_U8: + case NanoCLRDataType.DATATYPE_U8: writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_U8); writer.Write((ulong)argument.Value); break; - case nanoCLR_DataType.DATATYPE_R4: + case NanoCLRDataType.DATATYPE_R4: writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_R4); writer.Write((float)argument.Value); break; - case nanoCLR_DataType.DATATYPE_R8: + case NanoCLRDataType.DATATYPE_R8: writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_R8); writer.Write((double)argument.Value); break; - case nanoCLR_DataType.DATATYPE_CHAR: + case NanoCLRDataType.DATATYPE_CHAR: writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_CHAR); writer.Write((char)argument.Value); break; - case nanoCLR_DataType.DATATYPE_STRING: + case NanoCLRDataType.DATATYPE_STRING: writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_STRING); writer.Write(_context.StringTable.GetOrCreateStringId((string)argument.Value)); break; @@ -727,6 +841,22 @@ private void WriteAttributeArgumentValue( } } + private void WriteGenericParameterValue(BinaryWriter writer, GenericParameter parameter) + { + if (_context.GenericParamsTable.TryGetParameterId(parameter, out ushort referenceId)) + { + writer.Write((byte)nanoSerializationType.ELEMENT_TYPE_GENERICINST); + + // OK to use byte because we are not supporting more than 0x7F generic parameters + writer.Write((byte)referenceId); + } + else + { + // TODO + Debug.Fail("NEED TO IMPLEMENT THIS"); + } + } + private ushort GetOrCreateSignatureIdImpl( byte[] signature) { @@ -766,7 +896,7 @@ private void WriteTypeInfo( var byReference = typeReference as ByReferenceType; if (byReference != null) { - writer.WriteByte((byte)nanoCLR_DataType.DATATYPE_BYREF); + writer.WriteByte((byte)NanoCLRDataType.DATATYPE_BYREF); WriteDataType(byReference.ElementType, writer, true, false, false); } else @@ -791,26 +921,47 @@ private byte[] GetFullSignaturesArray() private void WriteSubTypeInfo(TypeReference typeDefinition, nanoBinaryWriter writer) { - ushort referenceId; - if (typeDefinition is TypeSpecification && - _context.TypeSpecificationsTable.TryGetTypeReferenceId(typeDefinition, out referenceId)) + // decoded at target with CLR_TkFromStream + + ushort tag; + + if ((typeDefinition is TypeSpecification || + typeDefinition is GenericParameter) && + _context.TypeSpecificationsTable.TryGetTypeReferenceId(typeDefinition, out ushort referenceId)) { - writer.WriteMetadataToken(((uint)referenceId << 2) | 0x02); + // TypeDefOrRef tag is 2 (TypeSpec) + tag = 2; + + // TypeDefOrRef tag is 2 bits + referenceId = (ushort)(referenceId << 2); } else if (_context.TypeReferencesTable.TryGetTypeReferenceId(typeDefinition, out referenceId)) { - writer.WriteMetadataToken(((uint)referenceId << 2) | 0x01); + // TypeDefOrRef tag is 1 (TypeRef) + tag = 1; + + // TypeDefOrRef tag is 2 bits + referenceId = (ushort)(referenceId << 2); } else if (_context.TypeDefinitionTable.TryGetTypeReferenceId( typeDefinition.Resolve(), out referenceId)) { - writer.WriteMetadataToken((uint)referenceId << 2); + // TypeDefOrRef tag is 0 (TypeDef) + tag = 0; + + // TypeDefOrRef tag is 2 bits + referenceId = (ushort)(referenceId << 2); } else { throw new ArgumentException($"Can't find entry in type reference table for {typeDefinition.FullName}."); } + + // OR with tag to form coded index + referenceId |= tag; + + writer.WriteMetadataToken(referenceId); } } } diff --git a/MetadataProcessor.Shared/Tables/nanoStringTable.cs b/MetadataProcessor.Shared/Tables/nanoStringTable.cs index 295a504c..fce091ba 100644 --- a/MetadataProcessor.Shared/Tables/nanoStringTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoStringTable.cs @@ -1,14 +1,13 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections.Generic; using System.Linq; using System.Text; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor { @@ -55,6 +54,8 @@ public IEnumerable Sort( /// private readonly nanoTablesContext _context; + public NanoClrTable TableIndex => NanoClrTable.TBL_Strings; + /// /// Last pre-allocated string identifier. /// diff --git a/MetadataProcessor.Shared/Tables/nanoTablesContext.cs b/MetadataProcessor.Shared/Tables/nanoTablesContext.cs index abf1fb20..fdc927b0 100644 --- a/MetadataProcessor.Shared/Tables/nanoTablesContext.cs +++ b/MetadataProcessor.Shared/Tables/nanoTablesContext.cs @@ -1,11 +1,11 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using Mono.Cecil; @@ -14,7 +14,6 @@ namespace nanoFramework.Tools.MetadataProcessor public sealed class nanoTablesContext { internal readonly bool _verbose; - internal readonly bool _isCoreLibrary; internal static HashSet IgnoringAttributes { get; } = new HashSet(StringComparer.Ordinal) { @@ -80,7 +79,9 @@ public nanoTablesContext( ClassNamesToExclude = classNamesToExclude; _verbose = verbose; - _isCoreLibrary = isCoreLibrary; + + // add default types to exclude + SetDefaultTypesToExclude(); // add default types to exclude SetDefaultTypesToExclude(); @@ -129,9 +130,10 @@ public nanoTablesContext( item.DeclaringType.GetElementType().IsPrimitive || item.ContainsGenericParameter || item.DeclaringType.IsGenericInstance)) - .ToList(); + MemberReferencesTable = new nanoMemberReferencesTable(memberReferences, this); + FieldReferencesTable = new nanoFieldReferenceTable( memberReferences.OfType(), this); MethodReferencesTable = new nanoMethodReferenceTable( @@ -166,8 +168,6 @@ public nanoTablesContext( GetAttributes(methods, applyAttributesCompression), this); - TypeSpecificationsTable = new nanoTypeSpecificationsTable(this); - // Resources information ResourcesTable = new nanoResourcesTable( @@ -188,16 +188,14 @@ public nanoTablesContext( ResourceFileTable = new nanoResourceFileTable(this); + List methodSpecifications = GetMethodSpecifications(methods); + + MethodSpecificationTable = new nanoMethodSpecificationTable(methodSpecifications, this); + // build list of generic parameters belonging to method defs List methodDefsGenericParameters = new List(); - foreach (var m in methods) - { - if (m.HasGenericParameters) - { - methodDefsGenericParameters.AddRange(m.GenericParameters); - } - } + methodDefsGenericParameters.AddRange(methods.Where(m => m.HasGenericParameters).SelectMany(mm => mm.GenericParameters)); var generics = types .SelectMany(t => t.GenericParameters) @@ -206,6 +204,8 @@ public nanoTablesContext( GenericParamsTable = new nanoGenericParamTable(generics, this); + TypeSpecificationsTable = new nanoTypeSpecificationsTable(this); + // Pre-allocate strings from some tables AssemblyReferenceTable.AllocateStrings(); TypeReferencesTable.AllocateStrings(); @@ -228,23 +228,240 @@ public nanoTablesContext( } /// - /// Gets method reference identifier (external or internal) encoded with appropriate prefix. + /// Gets (.NET nanoFramework encoded) method reference identifier (external or internal). /// - /// Method reference in Mono.Cecil format. - /// Reference identifier for passed value. + /// Method reference in Mono.Cecil format. + /// Reference identifier for passed value. public ushort GetMethodReferenceId( - MethodReference methodReference) + MemberReference memberReference) { - ushort referenceId; - if (MethodReferencesTable.TryGetMethodReferenceId(methodReference, out referenceId)) + // encodes MethodReference to be decoded with CLR_UncompressMethodToken + // CLR tables are: + // 0: TBL_MethodDef + // 1: TBL_MethodRef + // 2: TBL_MemberRef (TODO find if needed) + + ushort referenceId = 0xFFFF; + NanoClrTable ownerTable = NanoClrTable.TBL_EndOfAssembly; + + if (memberReference is MethodDefinition) + { + // check if method is external + if (memberReference.DeclaringType.Scope.MetadataScopeType == MetadataScopeType.AssemblyNameReference) + { + // method reference is external + ownerTable = NanoClrTable.TBL_MethodRef; + } + else + { + // method reference is internal + if (MethodDefinitionTable.TryGetMethodReferenceId(memberReference as MethodDefinition, out referenceId)) + { + // method reference is internal => method definition + ownerTable = NanoClrTable.TBL_MethodDef; + } + else + { + Debug.Fail($"Can't find method definition for {memberReference}"); + } + } + } + else if (memberReference is MethodReference && + MethodReferencesTable.TryGetMethodReferenceId(memberReference as MethodReference, out referenceId)) { - referenceId |= 0x8000; // External method reference + // check if method is external + if (memberReference.DeclaringType.Scope.MetadataScopeType == MetadataScopeType.AssemblyNameReference) + { + // method reference is external + } + else + { + // method reference belongs to a TypeSpec + + // find MethodDef for this + var methodRef = MethodReferencesTable.Items.FirstOrDefault(m => m.DeclaringType.MetadataToken == memberReference.DeclaringType.MetadataToken && m.Name == memberReference.Name); + + if (!MethodReferencesTable.TryGetMethodReferenceId(methodRef, out referenceId)) + { + Debug.Fail($"Can't find MethodRef for {memberReference}"); + } + } + + ownerTable = NanoClrTable.TBL_MethodRef; + } + else if (memberReference is MethodSpecification && + MethodSpecificationTable.TryGetMethodSpecificationId(memberReference as MethodSpecification, out referenceId)) + { + // member reference is MethodSpecification + ownerTable = NanoClrTable.TBL_MethodSpec; } else { - MethodDefinitionTable.TryGetMethodReferenceId(methodReference.Resolve(), out referenceId); + Debug.Fail($"Can't find any reference for {memberReference}"); } - return referenceId; + + return (ushort)(nanoTokenHelpers.EncodeTableIndex(ownerTable, nanoTokenHelpers.NanoMemberRefTokenTables) | referenceId); + } + + /// + /// Gets (.NET nanoFramework encoded) field reference identifier (external or internal). + /// + /// Field reference in Mono.Cecil format. + /// Reference identifier for passed value. + public ushort GetFieldReferenceId( + FieldReference fieldReference) + { + // encodes FieldReference to be decoded with CLR_UncompressFieldToken + // CLR tables are: + // 0: TBL_FieldDef + // 1: TBL_FieldRef + + ushort referenceId = 0xFFFF; + NanoClrTable ownerTable = NanoClrTable.TBL_EndOfAssembly; + + if (fieldReference is FieldDefinition) + { + // field reference is internal + if (FieldsTable.TryGetFieldReferenceId(fieldReference as FieldDefinition, false, out referenceId)) + { + // field reference is internal => field definition + ownerTable = NanoClrTable.TBL_FieldDef; + } + else + { + Debug.Fail($"Can't find field definition for {fieldReference}"); + } + } + else if (FieldReferencesTable.TryGetFieldReferenceId(fieldReference, out referenceId)) + { + // field reference is external + ownerTable = NanoClrTable.TBL_FieldRef; + } + else + { + Debug.Fail($"Can't find any reference for {fieldReference}"); + } + + return (ushort)(nanoTokenHelpers.EncodeTableIndex(ownerTable, nanoTokenHelpers.NanoFieldMemberRefTokenTables) | referenceId); + } + + /// + /// Gets metadata token encoded with appropriate prefix. + /// + /// Metadata token in Mono.Cecil format. + /// The .NET nanoFramework encoded token for passed value. + public uint GetMetadataToken( + IMetadataTokenProvider token) + { + switch (token.MetadataToken.TokenType) + { + case TokenType.TypeRef: + TypeReferencesTable.TryGetTypeReferenceId((TypeReference)token, out ushort referenceId); + return (uint)0x01000000 | referenceId; + case TokenType.TypeDef: + TypeDefinitionTable.TryGetTypeReferenceId((TypeDefinition)token, out referenceId); + return (uint)0x04000000 | referenceId; + case TokenType.TypeSpec: + TypeSpecificationsTable.TryGetTypeReferenceId((TypeReference)token, out referenceId); + return (uint)0x09000000 | referenceId; + case TokenType.Field: + FieldsTable.TryGetFieldReferenceId((FieldDefinition)token, false, out referenceId); + return (uint)0x05000000 | referenceId; + case TokenType.GenericParam: + GenericParamsTable.TryGetParameterId((GenericParameter)token, out referenceId); + return (uint)0x07000000 | referenceId; + + default: + System.Diagnostics.Debug.Fail("Unsupported TokenType"); + break; + } + return 0U; + } + + /// + /// Gets an (.NET nanoFramework encoded) type reference identifier (all kinds). + /// + /// Type reference in Mono.Cecil format. + /// The mask type to add to the encoded type reference Id. TypeRef mask will be added if none is specified. + /// Encoded type reference identifier for passed value. + public ushort GetTypeReferenceId( + TypeReference typeReference) + { + // encodes TypeReference to be decoded with CLR_UncompressTypeToken + + NanoClrTable ownerTable = NanoClrTable.TBL_EndOfAssembly; + + if (typeReference is TypeSpecification && + TypeSpecificationsTable.TryGetTypeReferenceId(typeReference, out ushort referenceId)) + { + // is TypeSpec + ownerTable = NanoClrTable.TBL_TypeSpec; + } + else if (typeReference is GenericParameter) + { + // is GenericParameter + if (TypeSpecificationsTable.TryGetTypeReferenceId(typeReference, out referenceId)) + { + // found it! + ownerTable = NanoClrTable.TBL_TypeSpec; + } + else + { + Debug.Fail("Can't find type reference."); + throw new ArgumentException($"Can't find type reference for {typeReference}."); + } + } + else if (typeReference is TypeDefinition && + TypeDefinitionTable.TryGetTypeReferenceId(typeReference.Resolve(), out referenceId)) + { + // is TypeDefinition + ownerTable = NanoClrTable.TBL_TypeDef; + } + else if (TypeReferencesTable.TryGetTypeReferenceId(typeReference, out referenceId)) + { + // is External type reference + ownerTable = NanoClrTable.TBL_TypeRef; + } + else + { + Debug.Fail("Can't find type reference."); + throw new ArgumentException($"Can't find type reference for {typeReference}."); + } + + return (ushort)(nanoTokenHelpers.EncodeTableIndex(ownerTable, nanoTokenHelpers.NanoTypeTokenTables) | referenceId); + } + + private List GetMethodSpecifications(List methods) + { + List methodSpecs = new List(); + + // need to find MethodSpecs in method body + foreach (var m in methods.Where(i => i.HasBody)) + { + foreach (var i in m.Body.Instructions) + { + if (i.Operand is MethodSpecification) + { + methodSpecs.Add(i.Operand as MethodSpecification); + } + } + } + + return methodSpecs; + } + + private List GetGenericParamsConstraints(List generics) + { + var genericsWithConstraints = generics.Where(g => g.HasConstraints); + + List constraints = new List(); + + foreach (var g in genericsWithConstraints) + { + constraints.AddRange(g.Constraints); + } + + return constraints; } public AssemblyDefinition AssemblyDefinition { get; private set; } @@ -259,6 +476,8 @@ public ushort GetMethodReferenceId( public nanoGenericParamTable GenericParamsTable { get; private set; } + public nanoMethodSpecificationTable MethodSpecificationTable { get; private set; } + public nanoMethodReferenceTable MethodReferencesTable { get; private set; } public nanoFieldDefinitionTable FieldsTable { get; private set; } @@ -267,6 +486,8 @@ public ushort GetMethodReferenceId( public nanoTypeDefinitionTable TypeDefinitionTable { get; private set; } + public nanoMemberReferencesTable MemberReferencesTable { get; private set; } + public nanoAttributesTable AttributesTable { get; private set; } public nanoTypeSpecificationsTable TypeSpecificationsTable { get; private set; } @@ -461,6 +682,11 @@ internal void ResetSignaturesTable() SignaturesTable = new nanoSignaturesTable(this); } + internal void ResetTypeSpecificationsTable() + { + TypeSpecificationsTable = new nanoTypeSpecificationsTable(this); + } + internal void ResetResourcesTables() { ResourcesTable = new nanoResourcesTable( diff --git a/MetadataProcessor.Shared/Tables/nanoTypeDefinitionTable.cs b/MetadataProcessor.Shared/Tables/nanoTypeDefinitionTable.cs index f0b7fd8c..bb45a3c6 100644 --- a/MetadataProcessor.Shared/Tables/nanoTypeDefinitionTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoTypeDefinitionTable.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using Mono.Cecil; @@ -21,6 +22,14 @@ namespace nanoFramework.Tools.MetadataProcessor public sealed class nanoTypeDefinitionTable : nanoReferenceTableBase { + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + // // + // when updating this size here need to update matching define in nanoCLR_Types.h in native // + private const int sizeOf_CLR_RECORD_TYPEDEF = 27; + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + /// /// Helper class for comparing two instances of objects /// using property as unique key for comparison. @@ -43,14 +52,16 @@ public int GetHashCode(TypeDefinition item) private IDictionary>> _byteCodeOffsets = new Dictionary>>(); - public List TypeDefinitions { get; private set; } + private List TypeDefinitions; public List EnumDeclarations { get; } + public NanoClrTable TableIndex => NanoClrTable.TBL_TypeDef; + /// /// Creates new instance of object. /// - /// List of types definitins in Mono.Cecil format. + /// List of types definitions in Mono.Cecil format. /// /// Assembly tables context - contains all tables used for building target assembly. /// @@ -99,13 +110,21 @@ protected override void WriteSingleItem( nanoBinaryWriter writer, TypeDefinition item) { + var writerStartPosition = writer.BaseStream.Position; + _context.StringTable.GetOrCreateStringId(item.Namespace); + // Name WriteStringReference(writer, item.Name); + + // NameSpace WriteStringReference(writer, item.Namespace); - writer.WriteUInt16(GetTypeReferenceOrDefinitionId(item.BaseType)); - writer.WriteUInt16(GetTypeReferenceOrDefinitionId(item.DeclaringType)); + // Extends + writer.WriteUInt16(GetEncodedTypeReferenceOrDefinitionId(item.BaseType)); + + // EnclosingType + writer.WriteUInt16(GetEncodedTypeReferenceOrDefinitionId(item.DeclaringType)); var fieldsList = item.Fields .Where(field => !field.HasConstant) @@ -155,11 +174,50 @@ protected override void WriteSingleItem( } } - // write flags + ushort genericParamRefId = 0xFFFF; + + if (item.HasGenericParameters) + { + // no need to check if it's found + _context.GenericParamsTable.TryGetParameterId(item.GenericParameters.FirstOrDefault(), out genericParamRefId); + } + + // FirstGenericParam + writer.WriteUInt16(genericParamRefId); + + // GenericParamCount + writer.WriteByte((byte)item.GenericParameters.Count); + + // Flags writer.WriteUInt16( (ushort)GetFlags( item, _context.MethodDefinitionTable)); + + var writerEndPosition = writer.BaseStream.Position; + + // ignore assert when not minimize + if (_context.MinimizeComplete) + { + Debug.Assert((writerEndPosition - writerStartPosition) == sizeOf_CLR_RECORD_TYPEDEF); + } + } + + /// + /// Add a "fake" TypeDef as placeholder for an instanced generic type. + /// + /// + public void AddGenericInstanceType(TypeReference typeReference) + { + // drop namespace as it's already on the full name + // OK to use full name as type name to help comparison ahead + var genericType = new TypeDefinition( + string.Empty, + typeReference.FullName, + typeReference.Resolve().Attributes); + + // add to items list + AddItem(genericType); } private void WriteClassFields( @@ -223,10 +281,16 @@ private void WriteClassFields( } } + // FirstStaticField writer.WriteUInt16(firstStaticFieldId); + + // FirstInstanceField writer.WriteUInt16(firstInstanceFieldId); + // StaticFieldsCount writer.WriteByte((byte)staticFieldsCount); + + // InstanceFieldsCount writer.WriteByte((byte)instanceFieldsCount); } @@ -266,8 +330,10 @@ private void WriteMethodBodies( firstMethodId = _context.ByteCodeTable.NextMethodId; } + // Interfaces writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(iInterfaces)); + // FirstMethod writer.WriteUInt16(firstMethodId); // sanity checks @@ -286,8 +352,11 @@ private void WriteMethodBodies( throw new InvalidOperationException($"Fatal error processing '{typeName}', static methods count ({staticMethodsCount}) exceeds maximum supported (255)."); } + // VirtualMethodCount writer.WriteByte((byte)virtualMethodsCount); + // InstanceMethodCount writer.WriteByte((byte)instanceMethodsCount); + // StaticMethodCount writer.WriteByte((byte)staticMethodsCount); } @@ -302,19 +371,31 @@ private void CreateMethodSignatures( _context.StringTable.GetOrCreateStringId(method.Name); } - private ushort GetTypeReferenceOrDefinitionId( + private ushort GetEncodedTypeReferenceOrDefinitionId( TypeReference typeReference) { - ushort referenceId; - if (_context.TypeReferencesTable.TryGetTypeReferenceId(typeReference, out referenceId)) + ushort tag; + + if (_context.TypeReferencesTable.TryGetTypeReferenceId(typeReference, out ushort referenceId)) { - return (ushort)(0x8000 | referenceId); + // check "nested inside" case + if (referenceId != 0xFFFF) + { + // is TypeRef + + return (ushort)(typeReference.ToEncodedNanoTypeDefOrRefToken() | referenceId); + } } - ushort typeId; - if (TryGetTypeReferenceId(typeReference.Resolve(), out typeId)) + if (TryGetTypeReferenceId(typeReference?.Resolve(), out ushort typeId)) { - return typeId; + // check "nested inside" case + if (referenceId != 0xFFFF) + { + // is TypeDef + + return (ushort)(typeReference.Resolve().ToEncodedNanoTypeDefOrRefToken() | typeId); + } } return 0xFFFF; diff --git a/MetadataProcessor.Shared/Tables/nanoTypeReferenceTable.cs b/MetadataProcessor.Shared/Tables/nanoTypeReferenceTable.cs index 77e43041..695cd5b8 100644 --- a/MetadataProcessor.Shared/Tables/nanoTypeReferenceTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoTypeReferenceTable.cs @@ -1,12 +1,12 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections.Generic; +using System.Diagnostics; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor { @@ -17,24 +17,15 @@ namespace nanoFramework.Tools.MetadataProcessor public sealed class nanoTypeReferenceTable : nanoReferenceTableBase { - /// - /// Helper class for comparing two instances of objects - /// using property as unique key for comparison. - /// - private sealed class TypeReferenceEqualityComparer : IEqualityComparer - { - /// - public bool Equals(TypeReference lhs, TypeReference rhs) - { - return string.Equals(lhs.FullName, rhs.FullName, StringComparison.Ordinal); - } + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + // // + // when updating this size here need to update matching define in nanoCLR_Types.h in native // + private const int sizeOf_CLR_RECORD_TYPEREF = 6; + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// - /// - public int GetHashCode(TypeReference item) - { - return item.FullName.GetHashCode(); - } - } + public NanoClrTable TableIndex => NanoClrTable.TBL_TypeRef; /// /// Creates new instance of object. @@ -46,7 +37,7 @@ public int GetHashCode(TypeReference item) public nanoTypeReferenceTable( IEnumerable items, nanoTablesContext context) - : base(items, new TypeReferenceEqualityComparer(), context) + : base(items, new TypeReferenceEqualityComparer(context), context) { } @@ -77,11 +68,20 @@ protected override void WriteSingleItem( nanoBinaryWriter writer, TypeReference item) { - WriteStringReference(writer, item.Name); + var writerStartPosition = writer.BaseStream.Position; + + + // Get the full name for nested types + string fullName = nanoTypeReferenceTable.GetFullName(item); + + WriteStringReference(writer, fullName); WriteStringReference(writer, item.Namespace); writer.WriteUInt16(GetScope(item)); // scope - TBL_AssemblyRef | TBL_TypeRef // 0x8000 - writer.WriteUInt16(0); // padding + + var writerEndPosition = writer.BaseStream.Position; + + Debug.Assert((writerEndPosition - writerStartPosition) == sizeOf_CLR_RECORD_TYPEREF); } /// @@ -95,16 +95,45 @@ protected override void AllocateSingleItemStrings( internal ushort GetScope( TypeReference typeReference) { - if (typeReference.DeclaringType == null) + // Check if the type is defined in the same assembly + if (typeReference.Scope is ModuleDefinition moduleDefinition + && moduleDefinition.Assembly == _context.AssemblyDefinition) { - return _context.AssemblyReferenceTable.GetReferenceId(typeReference.Scope as AssemblyNameReference); + // The type is defined in the same assembly + if (_context.TypeReferencesTable.TryGetTypeReferenceId( + typeReference.DeclaringType, + out ushort referenceId)) + { + return (ushort)(0x8000 | referenceId); + } + else + { + // unknown scope + throw new InvalidOperationException($"Unknown scope for type reference '{typeReference.FullName}'"); + } + } + else if (typeReference.Scope is AssemblyNameReference assemblyNameReference) + { + // The type is defined in a referenced assembly + return _context.AssemblyReferenceTable.GetReferenceId(assemblyNameReference); } else { - ushort referenceId; - _context.TypeReferencesTable.TryGetTypeReferenceId(typeReference.DeclaringType, out referenceId); - return (ushort)(0x8000 | referenceId); + // unknown scope + throw new InvalidOperationException($"Unknown scope for type reference '{typeReference.FullName}'"); } + + } + + private static string GetFullName(TypeReference typeReference) + { + if (typeReference.DeclaringType == null) + { + return typeReference.Name; + } + + // return the full name of the declaring type + return typeReference.FullName; } } } diff --git a/MetadataProcessor.Shared/Tables/nanoTypeSpecificationsTable.cs b/MetadataProcessor.Shared/Tables/nanoTypeSpecificationsTable.cs index 9cc8357b..ea27c951 100644 --- a/MetadataProcessor.Shared/Tables/nanoTypeSpecificationsTable.cs +++ b/MetadataProcessor.Shared/Tables/nanoTypeSpecificationsTable.cs @@ -1,13 +1,14 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using Mono.Cecil; +using Mono.Cecil.Cil; namespace nanoFramework.Tools.MetadataProcessor { @@ -17,40 +18,74 @@ namespace nanoFramework.Tools.MetadataProcessor /// public sealed class nanoTypeSpecificationsTable : InanoTable { + + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + // // + // when updating this size here need to update matching define in nanoCLR_Types.h in native // + private const int sizeOf_CLR_RECORD_TYPESPEC = 2; + ////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////// + /// - /// Helper class for comparing two instances of objects - /// using property as unique key for comparison. + /// Helper class for comparing two instances of objects + /// using property as unique key for comparison. /// - private sealed class TypeReferenceComparer : IEqualityComparer + private sealed class TypeSpecificationEqualityComparer : IEqualityComparer { /// - public bool Equals(TypeReference lhs, TypeReference rhs) + public bool Equals(TypeSpecification x, TypeSpecification y) + { + if (x is null) + { + throw new ArgumentNullException(nameof(x)); + } + + if (y is null) + { + throw new ArgumentNullException(nameof(y)); + } + + return string.Equals(x.MetadataToken, y.MetadataToken); + } + + /// + public int GetHashCode(TypeSpecification obj) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + return obj.MetadataToken.GetHashCode(); + } + } + + private sealed class TypeSpecBySignatureComparer : IEqualityComparer> + { + public bool Equals(KeyValuePair x, KeyValuePair y) { - return string.Equals(lhs.FullName, rhs.FullName, StringComparison.Ordinal); + return x.Key == y.Key; } /// - public int GetHashCode(TypeReference that) + public int GetHashCode(KeyValuePair that) { - return that.FullName.GetHashCode(); + return that.Key; } } /// /// Maps for each unique type specification and related identifier. /// - private readonly IDictionary _idByTypeSpecifications = - new Dictionary(new TypeReferenceComparer()); + private Dictionary _idByTypeSpecifications; /// /// Assembly tables context - contains all tables used for building target assembly. /// private readonly nanoTablesContext _context; - /// - /// Last available type specifier identificator. - /// - private ushort _lastAvailableId; + public NanoClrTable TableIndex => NanoClrTable.TBL_TypeSpec; /// /// Creates new instance of object. @@ -62,79 +97,128 @@ public nanoTypeSpecificationsTable( nanoTablesContext context) { _context = context; - } - /// - /// Gets existing or creates new type specification reference identifier. - /// - /// Type reference value for obtaining identifier. - /// Existing identifier if specification already in table or new one. - public ushort GetOrCreateTypeSpecificationId( - TypeReference typeReference) - { - ushort referenceId; - if (!_idByTypeSpecifications.TryGetValue(typeReference, out referenceId)) - { - // check for array in TypeSpec because we don't support for multidimensional arrays - if (typeReference.IsArray && - (typeReference as ArrayType).Rank > 1) - { - throw new ArgumentException($".NET nanoFramework doesn't have support for multidimensional arrays. Unable to parse {typeReference.FullName}."); - } + _idByTypeSpecifications = new Dictionary(new TypeReferenceEqualityComparer(context)); - _idByTypeSpecifications.Add(typeReference, _lastAvailableId); + FillTypeSpecsFromTypes(); - referenceId = _lastAvailableId; - ++_lastAvailableId; - } - - return referenceId; + FillTypeSpecsFromMemberReferences(); } /// - /// Gets type specification identifier (if it already added into type specifications list). + /// Gets type specification identifier. /// /// Type reference in Mono.Cecil format. - /// Type reference identifier for filling. + /// Type Specification identifier for filling. /// Returns true if item found, otherwise returns false. public bool TryGetTypeReferenceId( TypeReference typeReference, out ushort referenceId) { - if (typeReference == null) // This case is possible for encoding 'nested inside' case + if (_idByTypeSpecifications.TryGetValue(typeReference, out referenceId)) { - referenceId = 0xFFFF; + referenceId = (ushort)Array.IndexOf(_idByTypeSpecifications.Values.ToArray(), referenceId); + return true; } - referenceId = GetOrCreateTypeSpecificationId(typeReference); - - return true; + return false; } public TypeReference TryGetTypeSpecification(MetadataToken token) { - foreach (var t in _idByTypeSpecifications) + return _idByTypeSpecifications.FirstOrDefault(typeEntry => typeEntry.Key.MetadataToken == token).Key; + } + + /// + public void Write( + nanoBinaryWriter writer) + { + + foreach (var item in _idByTypeSpecifications) { - if (t.Key.MetadataToken == token) + var writerStartPosition = writer.BaseStream.Position; + + writer.WriteUInt16(item.Value); + + var writerEndPosition = writer.BaseStream.Position; + + Debug.Assert((writerEndPosition - writerStartPosition) == sizeOf_CLR_RECORD_TYPESPEC); + } + } + + public void ForEachItems(Action action) + { + foreach (var item in _idByTypeSpecifications) + { + action(item.Value, item.Key); + } + } + + private void FillTypeSpecsFromMemberReferences() + { + List typeSpecs = new List(); + + foreach (var m in _context.MemberReferencesTable.Items.Where(mr => mr.DeclaringType is TypeSpecification)) + { + if (!typeSpecs.Contains(m.DeclaringType as TypeSpecification, new TypeSpecificationEqualityComparer())) { - return t.Key; + // check for array in TypeSpec because we don't support for multidimensional arrays + if (m.DeclaringType.IsArray && + (m.DeclaringType as ArrayType).Rank > 1) + { + throw new ArgumentException($".NET nanoFramework doesn't have support for multidimensional arrays. Unable to parse {m.DeclaringType.FullName}."); + } + + typeSpecs.Add(m.DeclaringType as TypeSpecification); + + // get index of signature for the TypeSpecification + ushort signatureId = _context.SignaturesTable.GetOrCreateSignatureId(m.DeclaringType); + + if (!_idByTypeSpecifications.TryGetValue(m.DeclaringType, out ushort referenceId)) + { + // is not on the list yet, add it + _idByTypeSpecifications.Add(m.DeclaringType, signatureId); + } } } - - return null; } - /// - public void Write( - nanoBinaryWriter writer) + private void FillTypeSpecsFromTypes() { - foreach (var item in _idByTypeSpecifications - .OrderBy(item => item.Value) - .Select(item => item.Key)) + foreach (TypeDefinition t in _context.TypeDefinitionTable.Items) { - writer.WriteUInt16(_context.SignaturesTable.GetOrCreateSignatureId(item)); - writer.WriteUInt16(0x0000); // padding + foreach (MethodDefinition m in t.Methods.Where(method => method.HasBody)) + { + foreach (Instruction instruction in m.Body.Instructions) + { + if (instruction.Operand is GenericParameter genericParameter) + { + ushort signatureId = _context.SignaturesTable.GetOrCreateSignatureId(genericParameter); + + if (!_idByTypeSpecifications.ContainsKey(genericParameter)) + { + _idByTypeSpecifications.Add(genericParameter, signatureId); + } + } + else if (instruction.Operand is TypeReference typeReference) + { + // Optional: Check additional conditions if needed, + // for example, if the operand type should be an array. + if (instruction.OpCode.OperandType == OperandType.InlineType && !typeReference.IsArray) + { + continue; + } + + ushort signatureId = _context.SignaturesTable.GetOrCreateSignatureId(typeReference); + + if (!_idByTypeSpecifications.ContainsKey(typeReference)) + { + _idByTypeSpecifications.Add(typeReference, signatureId); + } + } + } + } } } } diff --git a/MetadataProcessor.Shared/Utility/CompressTokenHelper.cs b/MetadataProcessor.Shared/Utility/CompressTokenHelper.cs new file mode 100644 index 00000000..f38e7d73 --- /dev/null +++ b/MetadataProcessor.Shared/Utility/CompressTokenHelper.cs @@ -0,0 +1,187 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Mono.Cecil; + +namespace nanoFramework.Tools.MetadataProcessor +{ + /// + /// Helpers to handle nanoTokens. + /// + public class nanoTokenHelpers + { + /// + /// Tables to encode NanoTypeToken. + /// + public readonly static List NanoTypeTokenTables = new List() { + // + // order matters and has to match CLR_UncompressTypeToken in native nanoCLR_Types.h + NanoClrTable.TBL_TypeDef, + NanoClrTable.TBL_TypeRef, + NanoClrTable.TBL_TypeSpec, + NanoClrTable.TBL_GenericParam + }; + + /// + /// Tables to encode NanoTypeDefOrRefToken. + /// + public readonly static List NanoTypeDefOrRefTokenTables = new List() { + NanoClrTable.TBL_TypeDef, + NanoClrTable.TBL_TypeRef, + }; + + /// + /// Tables to encode NanoMemberRefToken. + /// + public readonly static List NanoMemberRefTokenTables = new List() { + // + // order matters and has to match CLR_UncompressMethodToken in native nanoCLR_Types.h + NanoClrTable.TBL_MethodDef, + NanoClrTable.TBL_MethodRef, + NanoClrTable.TBL_TypeSpec, + NanoClrTable.TBL_MethodSpec, + }; + + /// + /// Tables to encode NanoFieldMemberRefToken. + /// + public readonly static List NanoFieldMemberRefTokenTables = new List() { + NanoClrTable.TBL_FieldDef, + NanoClrTable.TBL_FieldRef + }; + + /// + /// Tables to encode NanoMethodDefOrRefToken. + /// + public readonly static List NanoMethodDefOrRefTokenTables = new List() { + NanoClrTable.TBL_MethodDef, + NanoClrTable.TBL_MethodRef + }; + + /// + /// Tables to encode NanoTypeOrMethodToken. + /// + public readonly static List NanoTypeOrMethodDefTokenTables = new List() { + NanoClrTable.TBL_TypeDef, + NanoClrTable.TBL_MethodDef + }; + + /// + /// Tables to encode CLR_TypeRefOrSpec. + /// + public readonly static List CLR_TypeRefOrSpecTables = new List() { + // + // order matters and has to match decoder Owner() in native nanoCLR_Types.h + NanoClrTable.TBL_TypeRef, + NanoClrTable.TBL_TypeSpec + }; + + /// + /// Encode table to be used in a nanoToken. + /// The table index in moved to the MSbits. + /// + /// Table to compress. + /// List of tables to be used in encoding. + /// The encoded tag to be used in a nanoToken. + public static ushort EncodeTableIndex(NanoClrTable table, List tableList) + { + // sanity checks + if (tableList.Count < 1) + { + Debug.Fail($"List contains only one element. No need to encode."); + } + + if (!tableList.Contains(table)) + { + Debug.Fail($"{table} is not listed in the options."); + } + + // find out how many bits are required to compress the list + var requiredBits = (int)Math.Round(Math.Log(tableList.Count, 2)); + + return (ushort)(tableList.IndexOf(table) << (16 - requiredBits)); + } + + /// + /// Decode from nanoToken. + /// + /// Encoded value containing the table index. + /// List of tables to be used in encoding. + /// The encoded in the . + public static NanoClrTable DecodeTableIndex(ushort value, List tableList) + { + if (tableList.Count < 1) + { + Debug.Fail($"List contains only one element. No need to encode."); + } + + // find out how many bits are required to compress the list + var requiredBits = (int)Math.Round(Math.Log(tableList.Count, 2)); + + var index = (value >> 16 - requiredBits); + + return tableList[index]; + } + + /// + /// Decode the reference from nanoToken taking into account the encoded table. + /// + /// Encoded value. + /// List of tables used in encoding. + /// The reference encoded in the . + public static ushort DecodeReferenceIndex(ushort value, List tableList) + { + if (tableList.Count < 1) + { + Debug.Fail($"List contains only one element. No need to encode."); + } + + // find out how many bits are required to compress the list + var requiredBits = (int)Math.Log(tableList.Count, 2); + + var mask = 0xFFFF; + + while (requiredBits-- > 0) + { + mask = mask >> 1; + } + + return (ushort)(value & mask); + } + + /// + /// Convert (and derived) in . + /// + /// + /// + public static NanoClrTable ConvertToNanoCLRTable(MemberReference value) + { + switch (value) + { + case GenericParameter _: + return NanoClrTable.TBL_GenericParam; + + case TypeDefinition _: + return NanoClrTable.TBL_TypeDef; + + case TypeSpecification _: + return NanoClrTable.TBL_TypeSpec; + + case TypeReference _: + return NanoClrTable.TBL_TypeRef; + + case FieldReference _: + return NanoClrTable.TBL_FieldRef; + + case MethodReference _: + return NanoClrTable.TBL_MethodRef; + + default: + throw new ArgumentException("Unknown conversion to CLR Table."); + } + } + } +} diff --git a/MetadataProcessor.Shared/Utility/Crc32.cs b/MetadataProcessor.Shared/Utility/Crc32.cs index 4f30feb0..d5a5f15a 100644 --- a/MetadataProcessor.Shared/Utility/Crc32.cs +++ b/MetadataProcessor.Shared/Utility/Crc32.cs @@ -1,8 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// using System.Linq; @@ -63,4 +62,4 @@ public static uint Compute(byte[] buffer, uint crc = 0) (index, item) => _crcTable[((index >> 24) ^ item) & 0xFF] ^ (index << 8)); } } -} \ No newline at end of file +} diff --git a/MetadataProcessor.Shared/Utility/FixTypeNames.cs b/MetadataProcessor.Shared/Utility/FixTypeNames.cs new file mode 100644 index 00000000..ecfdef58 --- /dev/null +++ b/MetadataProcessor.Shared/Utility/FixTypeNames.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace nanoFramework.Tools.MetadataProcessor +{ + public class nanoHelpers + { + internal static string FixTypeNames(string name) + { + // This is used to remedy the wrong output from Cecil.Mono + // Reported jbevain/cecil#715 + // OK to remove if implemented + + // following II.23.2.16 Short form signatures + string fixedName; + + fixedName = name.Replace("System.String", "string"); + fixedName = fixedName.Replace("System.Object", "object"); + fixedName = fixedName.Replace("System.Void", "void"); + fixedName = fixedName.Replace("System.Boolean", "bool"); + fixedName = fixedName.Replace("System.Char", "char"); + fixedName = fixedName.Replace("System.Byte", "int8"); + fixedName = fixedName.Replace("System.Sbyte", "uint8"); + fixedName = fixedName.Replace("System.Int16", "int16"); + fixedName = fixedName.Replace("System.UInt16", "uint16"); + fixedName = fixedName.Replace("System.Int32", "int32"); + fixedName = fixedName.Replace("System.UInt32", "uint32"); + fixedName = fixedName.Replace("System.Int64", "int64"); + fixedName = fixedName.Replace("System.UInt64", "uint64"); + fixedName = fixedName.Replace("System.Single", "float32"); + fixedName = fixedName.Replace("System.Double", "float64"); + + return fixedName; + } + } +} diff --git a/MetadataProcessor.Shared/Utility/LoadHintsAssemblyResolver.cs b/MetadataProcessor.Shared/Utility/LoadHintsAssemblyResolver.cs index 04b2d021..0426da49 100644 --- a/MetadataProcessor.Shared/Utility/LoadHintsAssemblyResolver.cs +++ b/MetadataProcessor.Shared/Utility/LoadHintsAssemblyResolver.cs @@ -1,13 +1,12 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections.Generic; using System.Reflection; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor { diff --git a/MetadataProcessor.Shared/Utility/NativeMethodsCrc.cs b/MetadataProcessor.Shared/Utility/NativeMethodsCrc.cs index e85df637..c3bec6e9 100644 --- a/MetadataProcessor.Shared/Utility/NativeMethodsCrc.cs +++ b/MetadataProcessor.Shared/Utility/NativeMethodsCrc.cs @@ -1,14 +1,13 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; -using nanoFramework.Tools.MetadataProcessor.Core.Extensions; using System; using System.Collections.Generic; using System.Text; +using Mono.Cecil; +using nanoFramework.Tools.MetadataProcessor.Core.Extensions; namespace nanoFramework.Tools.MetadataProcessor { @@ -19,7 +18,7 @@ namespace nanoFramework.Tools.MetadataProcessor /// public sealed class NativeMethodsCrc { - private readonly byte[] _null = Encoding.ASCII.GetBytes("NULL"); + private readonly byte[] _null = Encoding.ASCII.GetBytes("nullptr"); private readonly byte[] _name; @@ -118,22 +117,22 @@ private static string GetParameterType( // special processing for arrays if (parameterType.IsArray) { - typeName += nanoCLR_DataType.DATATYPE_SZARRAY + "_" + GetParameterType(parameterType.GetElementType()); + typeName += NanoCLRDataType.DATATYPE_SZARRAY + "_" + GetParameterType(parameterType.GetElementType()); continueProcessing = false; } else if (parameterType.IsByReference) { var elementType = ((TypeSpecification)parameterType).ElementType; - typeName += nanoCLR_DataType.DATATYPE_BYREF + "_"; + typeName += NanoCLRDataType.DATATYPE_BYREF + "_"; if (elementType.IsArray) { - typeName += nanoCLR_DataType.DATATYPE_SZARRAY + "_" + GetParameterType(((TypeSpecification)elementType).ElementType); + typeName += NanoCLRDataType.DATATYPE_SZARRAY + "_" + GetParameterType(((TypeSpecification)elementType).ElementType); } else { - typeName += GetnanoClrTypeName(elementType); + typeName += GetNanoCLRTypeName(elementType); } continueProcessing = false; } @@ -145,7 +144,7 @@ private static string GetParameterType( if (continueProcessing) { - typeName = GetnanoClrTypeName(parameterType); + typeName = GetNanoCLRTypeName(parameterType); } // clear 'DATATYPE_' prefixes @@ -153,26 +152,26 @@ private static string GetParameterType( return typeName.Replace("DATATYPE_", ""); } - internal static string GetnanoClrTypeName(TypeReference parameterType) + internal static string GetNanoCLRTypeName(TypeReference parameterType) { // try getting primitive type - nanoCLR_DataType myType; + NanoCLRDataType myType; if (nanoSignaturesTable.PrimitiveTypes.TryGetValue(parameterType.FullName, out myType)) { - if (myType == nanoCLR_DataType.DATATYPE_LAST_PRIMITIVE) + if (myType == NanoCLRDataType.DATATYPE_LAST_PRIMITIVE) { return "DATATYPE_STRING"; } - else if (myType == nanoCLR_DataType.DATATYPE_LAST_NONPOINTER) + else if (myType == NanoCLRDataType.DATATYPE_LAST_NONPOINTER) { return "DATATYPE_TIMESPAN"; } - else if (myType == nanoCLR_DataType.DATATYPE_LAST_PRIMITIVE_TO_MARSHAL) + else if (myType == NanoCLRDataType.DATATYPE_LAST_PRIMITIVE_TO_MARSHAL) { return "DATATYPE_TIMESPAN"; } - else if (myType == nanoCLR_DataType.DATATYPE_LAST_PRIMITIVE_TO_PRESERVE) + else if (myType == NanoCLRDataType.DATATYPE_LAST_PRIMITIVE_TO_PRESERVE) { return "DATATYPE_R8"; } diff --git a/MetadataProcessor.Shared/Utility/TypeReferenceEqualityComparer.cs b/MetadataProcessor.Shared/Utility/TypeReferenceEqualityComparer.cs new file mode 100644 index 00000000..f85a6c21 --- /dev/null +++ b/MetadataProcessor.Shared/Utility/TypeReferenceEqualityComparer.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using Mono.Cecil; + +namespace nanoFramework.Tools.MetadataProcessor +{ + /// + /// Helper class for comparing two instances of objects + /// using property as unique key for comparison. + /// + public sealed class TypeReferenceEqualityComparer : IEqualityComparer + { + private readonly nanoTablesContext _context; + + public TypeReferenceEqualityComparer(nanoTablesContext context) => _context = context; + + /// + public bool Equals(TypeReference x, TypeReference y) + { + if (x is null) + { + throw new ArgumentNullException(nameof(x)); + } + + if (y is null) + { + throw new ArgumentNullException(nameof(y)); + } + + if (x is TypeSpecification && + !(y is TypeSpecification)) + { + return false; + } + else if (y is TypeSpecification && + !(x is TypeSpecification)) + { + return false; + } + else if (x is TypeSpecification && + y is TypeSpecification) + { + // get signatures to perform comparison + ushort xSignatureId = _context.SignaturesTable.GetOrCreateSignatureId(x); + ushort ySignatureId = _context.SignaturesTable.GetOrCreateSignatureId(y); + + return xSignatureId == ySignatureId; + } + else if (x is GenericParameter && y is GenericParameter) + { + // comparison is made with type and position + var xGenericParam = x as GenericParameter; + var yGenericParam = y as GenericParameter; + + return (xGenericParam.Type == yGenericParam.Type) && + (xGenericParam.Position == yGenericParam.Position); + } + else + { + return x.MetadataToken == y.MetadataToken; + } + } + + /// + public int GetHashCode(TypeReference obj) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (obj is TypeSpecification) + { + ushort xSignatureId = _context.SignaturesTable.GetOrCreateSignatureId(obj); + + // provide an hash code based on the TypeSpec signature + return xSignatureId; + } + else if (obj is GenericParameter) + { + // provide an hash code based on the generic parameter position and type, + // which is what makes it unique when comparing GenericParameter as a TypeReference + var genericParam = obj as GenericParameter; + + return genericParam.Position * 10 + (int)genericParam.Type; + } + else + { + // provide an hash code from the metadatatoken + return obj.MetadataToken.GetHashCode(); + } + } + } +} diff --git a/MetadataProcessor.Shared/Utility/nanoBitmapProcessor.cs b/MetadataProcessor.Shared/Utility/nanoBitmapProcessor.cs index a483504b..8c9ec57d 100644 --- a/MetadataProcessor.Shared/Utility/nanoBitmapProcessor.cs +++ b/MetadataProcessor.Shared/Utility/nanoBitmapProcessor.cs @@ -1,8 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// using System; using System.Drawing; diff --git a/MetadataProcessor.Shared/Utility/nanoCLR_DataType.cs b/MetadataProcessor.Shared/Utility/nanoCLR_DataType.cs index 1fca7bc2..5b7fea98 100644 --- a/MetadataProcessor.Shared/Utility/nanoCLR_DataType.cs +++ b/MetadataProcessor.Shared/Utility/nanoCLR_DataType.cs @@ -1,12 +1,18 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// namespace nanoFramework.Tools.MetadataProcessor { - public enum nanoCLR_DataType : byte + ////////////////////////////////////////////////////////////////////////////////// + // // + // !!! KEEP IN SYNC WITH enum CLRDataType (in nanoCLR_TypeSystem Debugger) !!! // + // // + // !!! KEEP IN SYNC WITH enum CLRDataType (in nanoCLRT_Types.h in CLR) !!! // + ////////////////////////////////////////////////////////////////////////////////// + + public enum NanoCLRDataType : byte { // these where defined @ enum CLR_DataType diff --git a/MetadataProcessor.Shared/Utility/nanoDependencyGeneratorWriter.cs b/MetadataProcessor.Shared/Utility/nanoDependencyGeneratorWriter.cs index e462c716..23da2086 100644 --- a/MetadataProcessor.Shared/Utility/nanoDependencyGeneratorWriter.cs +++ b/MetadataProcessor.Shared/Utility/nanoDependencyGeneratorWriter.cs @@ -1,15 +1,14 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Xml; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor { @@ -129,12 +128,12 @@ private void WriteVersionInfo( private void WriteClassInfo( XmlWriter writer, - uint nanoClrItemToken, + uint nanoCLRItemToken, TypeDefinition item) { writer.WriteStartElement("Class"); - WriteTokensPair(writer, item.MetadataToken.ToUInt32(), 0x04000000 | nanoClrItemToken); + WriteTokensPair(writer, item.MetadataToken.ToUInt32(), 0x04000000 | nanoCLRItemToken); writer.WriteStartElement("Methods"); foreach (var tuple in GetMethodsTokens(item.Methods)) @@ -204,12 +203,12 @@ private IEnumerable> GetFieldsTokens( private void WriteTokensPair( XmlWriter writer, uint clrToken, - uint nanoClrToken) + uint nanoCLRToken) { writer.WriteStartElement("Token"); writer.WriteElementString("CLR", "0x" + clrToken.ToString("X8", CultureInfo.InvariantCulture)); - writer.WriteElementString("nanoCLR", "0x" + nanoClrToken.ToString("X8", CultureInfo.InvariantCulture)); + writer.WriteElementString("nanoCLR", "0x" + nanoCLRToken.ToString("X8", CultureInfo.InvariantCulture)); writer.WriteEndElement(); } diff --git a/MetadataProcessor.Shared/Utility/nanoFontProcessor.cs b/MetadataProcessor.Shared/Utility/nanoFontProcessor.cs index a6666dbe..1a5f4bcc 100644 --- a/MetadataProcessor.Shared/Utility/nanoFontProcessor.cs +++ b/MetadataProcessor.Shared/Utility/nanoFontProcessor.cs @@ -1,8 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// using System.IO; diff --git a/MetadataProcessor.Shared/Utility/nanoMetadataToken.cs b/MetadataProcessor.Shared/Utility/nanoMetadataToken.cs new file mode 100644 index 00000000..0711f23c --- /dev/null +++ b/MetadataProcessor.Shared/Utility/nanoMetadataToken.cs @@ -0,0 +1,84 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using Mono.Cecil; + +namespace nanoFramework.Tools.MetadataProcessor +{ + /// + /// Encoded type for inline type calls. + /// + public class nanoMetadataToken + { + private NanoClrTable _clrTable; + private ushort _id; + + public nanoMetadataToken() + { + } + + public nanoMetadataToken(NanoClrTable clrTable, ushort id) + { + _clrTable = clrTable; + _id = id; + } + + public nanoMetadataToken(MetadataToken token, ushort id) + { + _id = id; + + // get token type + switch (token.TokenType) + { + case TokenType.AssemblyRef: + _clrTable = NanoClrTable.TBL_AssemblyRef; + break; + + case TokenType.TypeRef: + _clrTable = NanoClrTable.TBL_TypeRef; + break; + + case TokenType.Field: + _clrTable = NanoClrTable.TBL_FieldDef; + break; + + case TokenType.Method: + _clrTable = NanoClrTable.TBL_MethodDef; + break; + + case TokenType.TypeDef: + _clrTable = NanoClrTable.TBL_TypeDef; + break; + + case TokenType.GenericParam: + _clrTable = NanoClrTable.TBL_GenericParam; + break; + + case TokenType.MethodSpec: + _clrTable = NanoClrTable.TBL_MethodDef; + break; + + case TokenType.MemberRef: + _clrTable = NanoClrTable.TBL_MethodRef; + break; + + case TokenType.TypeSpec: + _clrTable = NanoClrTable.TBL_TypeSpec; + break; + + default: + Debug.Fail("Unsupported token conversion"); + break; + } + } + + public override string ToString() + { + // table token + var tokenType = (uint)_clrTable << 24; + + return $"{tokenType | _id:X8}"; + } + } +} diff --git a/MetadataProcessor.Shared/Utility/nanoPdbxFileWriter.cs b/MetadataProcessor.Shared/Utility/nanoPdbxFileWriter.cs deleted file mode 100644 index d27f46c9..00000000 --- a/MetadataProcessor.Shared/Utility/nanoPdbxFileWriter.cs +++ /dev/null @@ -1,159 +0,0 @@ -// -// Copyright (c) .NET Foundation and Contributors -// Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// - -using Mono.Cecil; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.Linq; -using System.Xml; - -namespace nanoFramework.Tools.MetadataProcessor -{ - internal sealed class nanoPdbxFileWriter - { - private readonly nanoTablesContext _context; - - public nanoPdbxFileWriter( - nanoTablesContext context) - { - _context = context; - } - - public void Write( - XmlWriter writer) - { - writer.WriteStartElement("PdbxFile"); - writer.WriteStartElement("Assembly"); - - WriteTokensPair(writer, _context.AssemblyDefinition.MetadataToken.ToUInt32(), 0x00000000); - writer.WriteElementString("FileName", _context.AssemblyDefinition.MainModule.Name); - WriteVersionInfo(writer, _context.AssemblyDefinition.Name.Version); - - writer.WriteStartElement("Classes"); - - _context.TypeDefinitionTable.ForEachItems((token, item) => WriteClassInfo(writer, token, item)); - - writer.WriteEndDocument(); - } - - private void WriteVersionInfo( - XmlWriter writer, - Version version) - { - writer.WriteStartElement("Version"); - - writer.WriteElementString("Major", version.Major.ToString("D", CultureInfo.InvariantCulture)); - writer.WriteElementString("Minor", version.Minor.ToString("D", CultureInfo.InvariantCulture)); - writer.WriteElementString("Build", version.Build.ToString("D", CultureInfo.InvariantCulture)); - writer.WriteElementString("Revision", version.Revision.ToString("D", CultureInfo.InvariantCulture)); - - writer.WriteEndElement(); - } - - private void WriteClassInfo( - XmlWriter writer, - uint nanoClrItemToken, - TypeDefinition item) - { - writer.WriteStartElement("Class"); - - WriteTokensPair(writer, item.MetadataToken.ToUInt32(), 0x04000000 | nanoClrItemToken); - - writer.WriteStartElement("Methods"); - foreach (var tuple in GetMethodsTokens(item.Methods)) - { - writer.WriteStartElement("Method"); - - WriteTokensPair(writer, tuple.Item1, tuple.Item2); - - if (!tuple.Item3.HasBody) - { - writer.WriteElementString("HasByteCode", "false"); - } - writer.WriteStartElement("ILMap"); - - // sanity check vars - uint prevItem1 = 0; - uint prevItem2 = 0; - - foreach (var offset in _context.TypeDefinitionTable.GetByteCodeOffsets(tuple.Item1)) - { - if (prevItem1 > 0) - { - // 1st pass, load prevs with current values - Debug.Assert(prevItem1 < offset.Item1); - Debug.Assert(prevItem2 < offset.Item2); - } - writer.WriteStartElement("IL"); - - writer.WriteElementString("CLR", "0x" + offset.Item1.ToString("X8", CultureInfo.InvariantCulture)); - writer.WriteElementString("nanoCLR", "0x" + offset.Item2.ToString("X8", CultureInfo.InvariantCulture)); - - prevItem1 = offset.Item1; - prevItem2 = offset.Item2; - - writer.WriteEndElement(); - } - writer.WriteEndElement(); - - writer.WriteEndElement(); - } - writer.WriteEndElement(); - - writer.WriteStartElement("Fields"); - foreach (var pair in GetFieldsTokens(item.Fields)) - { - writer.WriteStartElement("Field"); - - WriteTokensPair(writer, pair.Item1, pair.Item2); - - writer.WriteEndElement(); - } - writer.WriteEndElement(); - - writer.WriteEndElement(); - } - - private IEnumerable> GetMethodsTokens( - IEnumerable methods) - { - foreach (var method in methods) - { - ushort fieldToken; - _context.MethodDefinitionTable.TryGetMethodReferenceId(method, out fieldToken); - yield return new Tuple( - method.MetadataToken.ToUInt32(), 0x06000000 | (uint)fieldToken, method); - } - } - - private IEnumerable> GetFieldsTokens( - IEnumerable fields) - { - foreach (var field in fields.Where(item => !item.HasConstant)) - { - ushort fieldToken; - _context.FieldsTable.TryGetFieldReferenceId(field, false, out fieldToken); - yield return new Tuple( - field.MetadataToken.ToUInt32(), 0x05000000 | (uint)fieldToken); - } - } - - private void WriteTokensPair( - XmlWriter writer, - uint clrToken, - uint nanoClrToken) - { - writer.WriteStartElement("Token"); - - writer.WriteElementString("CLR", "0x" + clrToken.ToString("X8", CultureInfo.InvariantCulture)); - writer.WriteElementString("nanoCLR", "0x" + nanoClrToken.ToString("X8", CultureInfo.InvariantCulture)); - - writer.WriteEndElement(); - } - } -} diff --git a/MetadataProcessor.Shared/Utility/nanoSerializationType.cs b/MetadataProcessor.Shared/Utility/nanoSerializationType.cs index d9227220..4990d1a0 100644 --- a/MetadataProcessor.Shared/Utility/nanoSerializationType.cs +++ b/MetadataProcessor.Shared/Utility/nanoSerializationType.cs @@ -1,8 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// namespace nanoFramework.Tools.MetadataProcessor { diff --git a/MetadataProcessor.Shared/Utility/nanoStringsConstants.cs b/MetadataProcessor.Shared/Utility/nanoStringsConstants.cs index 5290b1b5..fce86339 100644 --- a/MetadataProcessor.Shared/Utility/nanoStringsConstants.cs +++ b/MetadataProcessor.Shared/Utility/nanoStringsConstants.cs @@ -1,8 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// using System; using System.Collections.Generic; diff --git a/MetadataProcessor.Shared/Utility/nanoTypeDefinitionFlags.cs b/MetadataProcessor.Shared/Utility/nanoTypeDefinitionFlags.cs index f17206b3..5af14251 100644 --- a/MetadataProcessor.Shared/Utility/nanoTypeDefinitionFlags.cs +++ b/MetadataProcessor.Shared/Utility/nanoTypeDefinitionFlags.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; diff --git a/MetadataProcessor.Shared/nanoAssemblyBuilder.cs b/MetadataProcessor.Shared/nanoAssemblyBuilder.cs index 1396f5fc..ce3e0320 100644 --- a/MetadataProcessor.Shared/nanoAssemblyBuilder.cs +++ b/MetadataProcessor.Shared/nanoAssemblyBuilder.cs @@ -1,19 +1,18 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// -using Mono.Cecil; -using Mono.Collections.Generic; -using nanoFramework.Tools.MetadataProcessor.Core.Extensions; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; -using System.Xml; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Collections.Generic; +using nanoFramework.Tools.MetadataProcessor.Core.Extensions; namespace nanoFramework.Tools.MetadataProcessor { @@ -102,7 +101,7 @@ public void Minimize() var setNew = new HashSet(); var set = new HashSet(); - foreach (var t in _tablesContext.TypeDefinitionTable.TypeDefinitions) + foreach (var t in _tablesContext.TypeDefinitionTable.Items) { if (!t.IsToExclude()) { @@ -166,19 +165,22 @@ public void Minimize() } // need to reset several tables so they are recreated only with the used items + // order matters on several cases because the list recreation populates others + _tablesContext.ResetByteCodeTable(); + _tablesContext.ResetSignaturesTable(); + _tablesContext.ResetResourcesTables(); _tablesContext.AssemblyReferenceTable.RemoveUnusedItems(set); _tablesContext.TypeReferencesTable.RemoveUnusedItems(set); _tablesContext.FieldsTable.RemoveUnusedItems(set); _tablesContext.GenericParamsTable.RemoveUnusedItems(set); + _tablesContext.MethodSpecificationTable.RemoveUnusedItems(set); _tablesContext.FieldReferencesTable.RemoveUnusedItems(set); _tablesContext.MethodDefinitionTable.RemoveUnusedItems(set); _tablesContext.MethodReferencesTable.RemoveUnusedItems(set); _tablesContext.TypeDefinitionTable.RemoveUnusedItems(set); _tablesContext.TypeDefinitionTable.ResetByteCodeOffsets(); + _tablesContext.ResetTypeSpecificationsTable(); _tablesContext.AttributesTable.RemoveUnusedItems(set); - _tablesContext.ResetByteCodeTable(); - _tablesContext.ResetSignaturesTable(); - _tablesContext.ResetResourcesTables(); _tablesContext.StringTable.RemoveUnusedItems(set); // renormalise type definitions look-up tables @@ -340,6 +342,8 @@ private HashSet BuildDependencyList(MetadataToken token) Collection parameters = null; + FieldReference fr = null; + // try to find a method reference var mr = _tablesContext.MethodReferencesTable.Items.FirstOrDefault(i => i.MetadataToken == token); @@ -350,7 +354,24 @@ private HashSet BuildDependencyList(MetadataToken token) if (mr.DeclaringType != null) { - set.Add(mr.DeclaringType.MetadataToken); + if (mr.DeclaringType is TypeSpecification) + { + // Cecil.Mono has a bug providing TypeSpecs Metadata tokens generic parameters variables, so we need to check against our internal table and build one from it + if (_tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(mr.DeclaringType, out ushort referenceId)) + { + set.Add(new MetadataToken( + TokenType.TypeSpec, + referenceId)); + } + else + { + Debug.Fail($"Couldn't find a TypeSpec entry for {mr.DeclaringType}"); + } + } + else + { + set.Add(mr.DeclaringType.MetadataToken); + } } if (mr.MethodReturnType.ReturnType.IsValueType && @@ -428,16 +449,32 @@ private HashSet BuildDependencyList(MetadataToken token) if (mr == null) { // try now with field references - var fr = _tablesContext.FieldReferencesTable.Items.FirstOrDefault(i => i.MetadataToken == token); + fr = _tablesContext.FieldReferencesTable.Items.FirstOrDefault(i => i.MetadataToken == token); if (fr != null) { if (fr.DeclaringType != null) { - set.Add(fr.DeclaringType.MetadataToken); + if (fr.DeclaringType is TypeSpecification) + { + // Cecil.Mono has a bug providing TypeSpecs Metadata tokens generic parameters variables, so we need to check against our internal table and build one from it + if (_tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(fr.DeclaringType, out ushort referenceId)) + { + set.Add(new MetadataToken( + TokenType.TypeSpec, + referenceId)); + } + else + { + Debug.Fail($"Couldn't find a TypeSpec entry for {fr.DeclaringType}"); + } + } + else + { + set.Add(fr.DeclaringType.MetadataToken); + } } - if (fr.FieldType.MetadataType == MetadataType.Class) { set.Add(fr.FieldType.MetadataToken); @@ -476,6 +513,8 @@ private HashSet BuildDependencyList(MetadataToken token) } } + Debug.Assert(mr != null || fr != null); + break; case TokenType.TypeSpec: @@ -486,6 +525,8 @@ private HashSet BuildDependencyList(MetadataToken token) set.Add(token); } + Debug.Assert(ts != null); + break; case TokenType.TypeDef: @@ -696,6 +737,24 @@ private HashSet BuildDependencyList(MetadataToken token) set.Add(parameterType.MetadataToken); set.Add(parameterType.GetElementType().MetadataToken); } + else if (parameterType is GenericParameter) + { + set.Add(parameterType.MetadataToken); + + foreach (var gp in parameterType.GenericParameters) + { + set.Add(gp.MetadataToken); + if (parameterType.DeclaringType != null) + { + set.Add(parameterType.DeclaringType.MetadataToken); + } + } + + if (parameterType.DeclaringType != null) + { + set.Add(parameterType.DeclaringType.MetadataToken); + } + } else if (!parameterType.IsValueType && !parameterType.IsPrimitive && parameterType.FullName != "System.Void" && @@ -745,8 +804,19 @@ private HashSet BuildDependencyList(MetadataToken token) } else if (v.VariableType is GenericInstanceType) { - set.Add(v.VariableType.MetadataToken); - set.Add(v.VariableType.GetElementType().MetadataToken); + // Cecil.Mono has a bug providing TypeSpecs Metadata tokens generic parameters variables, so we need to check against our internal table and build one from it + if (_tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(v.VariableType, out ushort referenceId)) + { + set.Add(new MetadataToken( + TokenType.TypeSpec, + referenceId)); + + set.Add(v.VariableType.GetElementType().MetadataToken); + } + else + { + Debug.Fail($"Couldn't find a TypeSpec entry for {v.VariableType}"); + } } else if (v.VariableType.IsPointer) { @@ -760,15 +830,66 @@ private HashSet BuildDependencyList(MetadataToken token) // op codes foreach (var i in md.Body.Instructions) { - if (i.Operand is MethodReference || - i.Operand is FieldReference || - i.Operand is TypeDefinition || - i.Operand is TypeSpecification || - i.Operand is TypeReference || + if (i.Operand is MethodReference) + { + var methodReferenceType = i.Operand as MethodReference; + + set.Add(methodReferenceType.MetadataToken); + + if (_tablesContext.MethodReferencesTable.TryGetMethodReferenceId(methodReferenceType, out ushort referenceId)) + { + if (methodReferenceType.DeclaringType != null && + methodReferenceType.DeclaringType.IsGenericInstance) + { + // Cecil.Mono has a bug providing TypeSpecs Metadata tokens generic parameters variables, so we need to check against our internal table and build one from it + if (_tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(methodReferenceType.DeclaringType, out referenceId)) + { + set.Add(new MetadataToken( + TokenType.TypeSpec, + referenceId)); + } + else + { + Debug.Fail($"Couldn't find a TypeSpec entry for {methodReferenceType.DeclaringType}"); + } + } + } + } + else if (i.Operand is FieldReference || + i.Operand is TypeDefinition || + i.Operand is MethodSpecification || + i.Operand is TypeReference) + { + set.Add(((IMetadataTokenProvider)i.Operand).MetadataToken); + } + else if ( + i.OpCode.OperandType is OperandType.InlineType || i.Operand is GenericInstanceType || + i.Operand is GenericInstanceMethod || i.Operand is GenericParameter) { - set.Add(((IMetadataTokenProvider)i.Operand).MetadataToken); + var opType = (TypeReference)i.Operand; + + var opToken = ((IMetadataTokenProvider)i.Operand).MetadataToken; + + if (opToken.TokenType == TokenType.TypeSpec) + { + // Cecil.Mono has a bug providing TypeSpecs Metadata tokens generic parameters variables, so we need to check against our internal table and build one from it + if (_tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(opType, out ushort referenceId)) + { + set.Add(new MetadataToken( + TokenType.TypeSpec, + referenceId)); + } + else + { + Debug.Fail($"Couldn't find a TypeSpec entry for {opType}"); + } + } + else + { + set.Add(opToken); + } } else if (i.Operand is string) { @@ -778,7 +899,6 @@ i.Operand is GenericInstanceType || set.Add(newToken); } - } // exceptions @@ -823,9 +943,31 @@ i.Operand is GenericInstanceType || break; + case TokenType.MethodSpec: + var ms = _tablesContext.MethodSpecificationTable.Items.FirstOrDefault(i => i.MetadataToken == token); + + if (ms != null) + { + set.Add(token); + } + break; + case TokenType.GenericParam: + var gpar = _tablesContext.GenericParamsTable.Items.FirstOrDefault(i => i.MetadataToken == token); + + if (gpar != null) + { + // need to add their constraints if, any + foreach (var c in gpar.Constraints) + { + set.Add(c.MetadataToken); + } + } + break; + case TokenType.AssemblyRef: case TokenType.String: + case TokenType.GenericParamConstraint: // we are good with these, nothing to do here break; @@ -1017,6 +1159,14 @@ private string TokenToString(MetadataToken token) } break; + case TokenType.MethodSpec: + output.Append($"[MethodSpec 0x{token.ToUInt32().ToString("X8")}]"); + break; + + case TokenType.GenericParamConstraint: + output.Append($"[GenericParamConstraint 0x{token.ToUInt32().ToString("X8")}]"); + break; + default: Debug.Fail($"Unable to process token {token}."); break; @@ -1031,16 +1181,28 @@ private string TokenToString(MetadataToken token) return output.ToString(); } - public void Write( - XmlWriter xmlWriter) + public void Write(string fileName) { var pdbxWriter = new nanoPdbxFileWriter(_tablesContext); - pdbxWriter.Write(xmlWriter); + pdbxWriter.Write(fileName); } - private static IEnumerable GetTables( + /// + /// Count of tables in the assembly + /// + static public int TablesCount => 0x12; + + internal static IEnumerable GetTables( nanoTablesContext context) { + ////////////////////////////////////////////////// + // order matters and must follow CLR_TABLESENUM // + ////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////// + // update count property above whenever changing the tables // + ////////////////////////////////////////////////////////////// + yield return context.AssemblyReferenceTable; yield return context.TypeReferencesTable; @@ -1055,10 +1217,14 @@ private static IEnumerable GetTables( yield return context.MethodDefinitionTable; - yield return context.AttributesTable; + yield return context.GenericParamsTable; + + yield return context.MethodSpecificationTable; yield return context.TypeSpecificationsTable; + yield return context.AttributesTable; + yield return context.ResourcesTable; yield return context.ResourceDataTable; diff --git a/MetadataProcessor.Shared/nanoAssemblyDefinition.cs b/MetadataProcessor.Shared/nanoAssemblyDefinition.cs index 6f13654e..89d77559 100644 --- a/MetadataProcessor.Shared/nanoAssemblyDefinition.cs +++ b/MetadataProcessor.Shared/nanoAssemblyDefinition.cs @@ -1,8 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + // Original work from Oleg Rakhmatulin. -// See LICENSE file in the project root for full license information. -// using System.IO; @@ -14,10 +13,19 @@ namespace nanoFramework.Tools.MetadataProcessor public sealed class nanoAssemblyDefinition { /// - /// nanoFramework assembly marker V1. + /// .NET nanoFramework assembly marker V1. /// + /// + /// Not to be used. Kept for historical reasons. + /// + [System.Obsolete("Not to be used. Kept for historical reasons. Use V2 instead.")] private const string c_NFAssemblyMarker_v1 = "NFMRK1"; + /// + /// .NET nanoFramework assembly marker V2. + /// + private const string c_NFAssemblyMarker_v2 = "NFMRK2"; + /// /// Position of Assembly CRC32 in the PE file. /// @@ -48,6 +56,11 @@ public sealed class nanoAssemblyDefinition /// private long _paddingsOffset; + /// + /// Size of the PE file header + /// + private long _headerSize; + /// /// Creates new instance of object. /// @@ -71,10 +84,10 @@ public void Write( nanoBinaryWriter writer, bool isPreAllocationCall) { - // this replicates the original struct CLR_RECORD_ASSEMBLY + // this follows the struct CLR_RECORD_ASSEMBLY // marker - writer.WriteString(c_NFAssemblyMarker_v1); + writer.WriteString(c_NFAssemblyMarker_v2); // need to set position because marker could be shorter writer.BaseStream.Seek(c_HeaderCrc32Position, SeekOrigin.Begin); @@ -85,21 +98,22 @@ public void Write( // assembly CRC32 writer.WriteUInt32(0); - // current builds are for little endian targets only - // keeping this here for now, just for compatibility + // flags writer.WriteUInt32(0); + // nativeMethodsChecksum writer.WriteUInt32(_context.NativeMethodsCrc.CurrentCrc); - // Native methods offset - writer.WriteUInt32(0xFFFFFFFF); - + // version writer.WriteVersion(_context.AssemblyDefinition.Name.Version); + // assemblyName writer.WriteUInt16(isPreAllocationCall ? (ushort)0x0000 : _context.StringTable.GetOrCreateStringId(_context.AssemblyDefinition.Name.Name)); - writer.WriteUInt16(1); // String table version + + // string table version + writer.WriteUInt16(1); //For every table, a number of bytes that were padded to the end of the table //to align to unsigned long. Each table starts at a unsigned long boundary, and ends @@ -108,21 +122,29 @@ public void Write( //compact form to hold this information, but it only costs 16 bytes/assembly. //Trying to only align some of the tables is just much more hassle than it's worth. //And, of course, this field also has to be unsigned long-aligned. + + // startOfTables + // paddingOfTables + if (isPreAllocationCall) { _tablesOffset = writer.BaseStream.Position; - for (var i = 0; i < 16; ++i) + for (var i = 0; i < nanoAssemblyBuilder.TablesCount; ++i) { writer.WriteUInt32(0); } - writer.WriteUInt32(0); // Number of patched methods - _paddingsOffset = writer.BaseStream.Position; - for (var i = 0; i < 16; ++i) + for (var i = 0; i < nanoAssemblyBuilder.TablesCount; ++i) { writer.WriteByte(0); } + + // store the header size which is required to compute the CRC32 ahead + _headerSize = (writer.BaseStream.Position + 3) & 0xFFFFFFFC; + + // check if we need to write any padding bytes + writer.WriteBytes(new byte[_headerSize - writer.BaseStream.Position]); } else { @@ -134,8 +156,8 @@ public void Write( var assemblyCrc32 = ComputeCrc32( writer.BaseStream, - _paddingsOffset, - writer.BaseStream.Length - _paddingsOffset); + _headerSize, + writer.BaseStream.Length - _headerSize); writer.WriteUInt32(assemblyCrc32); // set writer position at Header CRC32 position @@ -144,7 +166,7 @@ public void Write( var headerCrc32 = ComputeCrc32( writer.BaseStream, 0, - _paddingsOffset); + _headerSize); writer.WriteUInt32(headerCrc32); } } diff --git a/MetadataProcessor.Shared/nanoDependencyGenerator.cs b/MetadataProcessor.Shared/nanoDependencyGenerator.cs index 83a2d2b7..257e49f7 100644 --- a/MetadataProcessor.Shared/nanoDependencyGenerator.cs +++ b/MetadataProcessor.Shared/nanoDependencyGenerator.cs @@ -1,10 +1,10 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Original work from Oleg Rakhmatulin. -using Mono.Cecil; using System.Xml; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor.Core { diff --git a/MetadataProcessor.Shared/nanoDumperGenerator.cs b/MetadataProcessor.Shared/nanoDumperGenerator.cs index 452c84c3..d321f3a8 100644 --- a/MetadataProcessor.Shared/nanoDumperGenerator.cs +++ b/MetadataProcessor.Shared/nanoDumperGenerator.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; @@ -37,12 +38,13 @@ public void DumpAll() DumpAssemblyReferences(dumpTable); //DumpModuleReferences(dumpTable); DumpTypeReferences(dumpTable); - DumpTypeDefinitions(dumpTable); + _tablesContext.TypeSpecificationsTable.ForEachItems((index, typeReference) => DumpTypeSpecifications(typeReference, dumpTable)); + _tablesContext.GenericParamsTable.ForEachItems((index, genericParameter) => DumpGenericParams(genericParameter, dumpTable)); DumpCustomAttributes(dumpTable); + DumpStringHeap(dumpTable); DumpUserStrings(dumpTable); - FormatCompiler compiler = new FormatCompiler(); Generator generator = compiler.Compile(DumpTemplates.DumpAllTemplate); @@ -53,6 +55,33 @@ public void DumpAll() } } + private void DumpGenericParams(GenericParameter genericParameter, DumpAllTable dumpTable) + { + _tablesContext.GenericParamsTable.TryGetParameterId(genericParameter, out ushort referenceId); + + var genericParam = new GenericParam() + { + Position = referenceId.ToString(), + Owner = genericParameter.Owner.ToString(), + Name = genericParameter.Name + }; + + if (genericParameter.Owner is TypeDefinition && _tablesContext.TypeDefinitionTable.TryGetTypeReferenceId((TypeDefinition)genericParameter.Owner, out ushort typeRefId)) + { + string realToken = genericParameter.MetadataToken.ToInt32().ToString("X8"); + + genericParam.Owner = $"Owner: {genericParameter.Owner} [{new nanoMetadataToken(genericParameter.Owner.MetadataToken, typeRefId)}] /*{realToken}*/"; + } + else if (_tablesContext.MethodDefinitionTable.TryGetMethodReferenceId((MethodDefinition)genericParameter.Owner, out ushort refId)) + { + string realToken = genericParameter.Owner.MetadataToken.ToInt32().ToString("X8"); + + genericParam.Owner = $"Owner: {((MethodDefinition)genericParameter.Owner)} [{new nanoMetadataToken(genericParameter.Owner.MetadataToken, refId)}] /*{realToken}*/"; + } + + dumpTable.GenericParams.Add(genericParam); + } + private void DumpCustomAttributes(DumpAllTable dumpTable) { foreach (var a in _tablesContext.TypeDefinitionTable.Items.Where(td => td.HasCustomAttributes)) @@ -64,8 +93,8 @@ private void DumpCustomAttributes(DumpAllTable dumpTable) var attribute = new AttributeCustom() { Name = a.Module.Assembly.Name.Name, - ReferenceId = ma.MetadataToken.ToInt32().ToString("x8"), - TypeToken = ma.CustomAttributes[0].Constructor.MetadataToken.ToInt32().ToString("x8") + ReferenceId = ma.MetadataToken.ToInt32().ToString("X8"), + TypeToken = ma.CustomAttributes[0].Constructor.MetadataToken.ToInt32().ToString("X8") }; if (ma.CustomAttributes[0].HasConstructorArguments) @@ -87,8 +116,8 @@ private void DumpCustomAttributes(DumpAllTable dumpTable) var attribute = new AttributeCustom() { Name = a.Module.Assembly.Name.Name, - ReferenceId = fa.MetadataToken.ToInt32().ToString("x8"), - TypeToken = fa.CustomAttributes[0].Constructor.MetadataToken.ToInt32().ToString("x8") + ReferenceId = fa.MetadataToken.ToInt32().ToString("X8"), + TypeToken = fa.CustomAttributes[0].Constructor.MetadataToken.ToInt32().ToString("X8") }; if (!nanoTablesContext.IgnoringAttributes.Contains(fa.CustomAttributes[0].AttributeType.FullName) @@ -182,11 +211,27 @@ private List BuildFixedArgsAttribute(CustomAttributeArgument value return new List() { newArg }; } - private void DumpUserStrings(DumpAllTable dumpTable) + private void DumpStringHeap(DumpAllTable dumpTable) { - // start at 1, because 0 is the empty string entry - int tokenId = 1; + foreach (var s in _tablesContext.StringTable.GetItems().OrderBy(i => i.Value)) + { + // don't output the empty string + if (s.Value == 0) + { + continue; + } + dumpTable.StringHeap.Add( + new HeapString() + { + ReferenceId = s.Value.ToString("X8"), + Content = s.Key + }); + } + } + + private void DumpUserStrings(DumpAllTable dumpTable) + { foreach (var s in _tablesContext.StringTable.GetItems().OrderBy(i => i.Value).Where(i => i.Value > _tablesContext.StringTable.LastPreAllocatedId)) { // don't output the empty string @@ -195,13 +240,11 @@ private void DumpUserStrings(DumpAllTable dumpTable) continue; } - // fake the metadata token from the ID - var stringMetadataToken = new MetadataToken(TokenType.String, tokenId++); - dumpTable.UserStrings.Add( new UserString() { - ReferenceId = stringMetadataToken.ToInt32().ToString("x8"), + ReferenceId = new nanoMetadataToken(NanoClrTable.TBL_Strings, _tablesContext.StringTable.GetOrCreateStringId(s.Key, true)).ToString(), + Length = s.Key.Length.ToString("x2"), Content = s.Key }); } @@ -211,10 +254,12 @@ private void DumpTypeDefinitions(DumpAllTable dumpTable) { foreach (TypeDefinition t in _tablesContext.TypeDefinitionTable.Items.OrderBy(tr => tr.MetadataToken.ToInt32())) { + _tablesContext.TypeDefinitionTable.TryGetTypeReferenceId(t, out ushort referenceId); + // fill type definition var typeDef = new TypeDef() { - ReferenceId = t.MetadataToken.ToInt32().ToString("x8"), + ReferenceId = TypeDefRefIdToString(t, referenceId) }; if (t.IsNested) @@ -230,37 +275,47 @@ private void DumpTypeDefinitions(DumpAllTable dumpTable) t, _tablesContext.MethodDefinitionTable); - typeDef.Flags = typeFlags.ToString("x8"); + typeDef.Flags = typeFlags.ToString("X8"); if (t.BaseType != null) { - typeDef.ExtendsType = t.BaseType.MetadataToken.ToInt32().ToString("x8"); + _tablesContext.TypeReferencesTable.TryGetTypeReferenceId(t.BaseType, out referenceId); + + typeDef.ExtendsType = TypeDefExtendsTypeToString(t.BaseType, referenceId); } else { - var token = new MetadataToken(TokenType.TypeRef, 0); - typeDef.ExtendsType = token.ToInt32().ToString("x8"); + typeDef.ExtendsType = "(none)"; } if (t.DeclaringType != null) { - typeDef.EnclosedType = t.DeclaringType.MetadataToken.ToInt32().ToString("x8"); + string realToken = t.DeclaringType.MetadataToken.ToInt32().ToString("X8"); + + _tablesContext.TypeReferencesTable.TryGetTypeReferenceId(t.DeclaringType, out referenceId); + + typeDef.EnclosedType = $"{t.DeclaringType.FullName}[{new nanoMetadataToken(t.DeclaringType.MetadataToken, referenceId)}] /*{realToken}*/"; } else { - var token = new MetadataToken(TokenType.TypeDef, 0); - typeDef.EnclosedType = token.ToInt32().ToString("x8"); + typeDef.EnclosedType = "(none)"; } // list generic parameters foreach (GenericParameter gp in t.GenericParameters) { + string realToken = gp.MetadataToken.ToInt32().ToString("X8"); + _tablesContext.GenericParamsTable.TryGetParameterId(gp, out referenceId); + + var ownerRealToken = gp.Owner.MetadataToken.ToInt32().ToString("X8"); + _tablesContext.TypeDefinitionTable.TryGetTypeReferenceId(gp.Owner as TypeDefinition, out ushort ownerReferenceId); + var genericParam = new GenericParam() { Position = gp.Position.ToString(), - GenericParamToken = gp.MetadataToken.ToInt32().ToString("x8"), - Name = gp.FullName, - Owner = gp.Owner.MetadataToken.ToInt32().ToString("x8"), + GenericParamToken = $"[{new nanoMetadataToken(gp.MetadataToken, referenceId)}] /*{realToken}*/", + Name = new string('!', gp.Position + 1) + gp.FullName, + Owner = $"[{ownerReferenceId:x4}] /*{ownerRealToken}*/", Signature = gp.DeclaringType.Name }; @@ -272,12 +327,15 @@ private void DumpTypeDefinitions(DumpAllTable dumpTable) { uint att = (uint)f.Attributes; + string realToken = f.MetadataToken.ToInt32().ToString("X8"); + _tablesContext.FieldsTable.TryGetFieldReferenceId(f, false, out referenceId); + var fieldDef = new FieldDef() { - ReferenceId = f.MetadataToken.ToInt32().ToString("x8"), + ReferenceId = $"[{new nanoMetadataToken(f.MetadataToken, referenceId)}] /*{realToken}*/", Name = f.Name, - Flags = att.ToString("x8"), - Attributes = att.ToString("x8"), + Flags = att.ToString("X8"), + Attributes = att.ToString("X8"), Signature = f.FieldType.TypeSignatureAsString() }; @@ -287,38 +345,57 @@ private void DumpTypeDefinitions(DumpAllTable dumpTable) // list type methods foreach (MethodDefinition m in t.Methods) { + string realToken = m.MetadataToken.ToInt32().ToString("X8"); + _tablesContext.MethodDefinitionTable.TryGetMethodReferenceId(m, out referenceId); + var methodDef = new MethodDef() { - ReferenceId = m.MetadataToken.ToInt32().ToString("x8"), + ReferenceId = MethodDefIdToString(m, referenceId), Name = m.FullName(), - RVA = m.RVA.ToString("x8"), + RVA = _tablesContext.ByteCodeTable.GetMethodRva(m).ToString("X8"), Implementation = "00000000", Signature = PrintSignatureForMethod(m) }; - uint methodFlags = nanoMethodDefinitionTable.GetFlags(m); - methodDef.Flags = methodFlags.ToString("x8"); + // check for entry point + if (m == m.Module.EntryPoint) + { + methodDef.ReferenceId += " [ENTRYPOINT]"; + } + + var methodFlags = nanoMethodDefinitionTable.GetFlags(m); + methodDef.Flags = methodFlags.ToString("X8"); if (m.HasBody) { // locals if (m.Body.HasVariables) { - methodDef.Locals = PrintSignatureForLocalVar(m.Body.Variables); + var locaStringBuilder = new StringBuilder(); + + // get signature Id for locals + var signatureId = _tablesContext.SignaturesTable.GetOrCreateSignatureId(m.Body.Variables); + locaStringBuilder.Append($"[{new nanoMetadataToken(NanoClrTable.TBL_Signatures, signatureId)}]"); + + // print locals ids + locaStringBuilder.Append($": {PrintSignatureForLocalVar(m.Body.Variables)}"); + + methodDef.Locals = locaStringBuilder.ToString(); } // exceptions foreach (Mono.Cecil.Cil.ExceptionHandler eh in m.Body.ExceptionHandlers) { - var h = new ExceptionHandler(); - - h.Handler = $"{((int)eh.HandlerType).ToString("x2")} " + - $"{eh.TryStart?.Offset.ToString("x8")}->{eh.TryEnd?.Offset.ToString("x8")} " + - $"{eh.HandlerStart?.Offset.ToString("x8")}->{eh.HandlerEnd?.Offset.ToString("x8")} "; + var h = new ExceptionHandler + { + Handler = $"{(int)eh.HandlerType:x2} " + + $"{eh.TryStart?.Offset.ToString("X8")}->{eh.TryEnd?.Offset.ToString("X8")} " + + $"{eh.HandlerStart?.Offset.ToString("X8")}->{eh.HandlerEnd?.Offset.ToString("X8")} " + }; if (eh.CatchType != null) { - h.Handler += $"{eh.CatchType.MetadataToken.ToInt32().ToString("x8")}"; + h.Handler += $"{eh.CatchType.MetadataToken.ToInt32():X8}"; } else { @@ -333,68 +410,148 @@ private void DumpTypeDefinitions(DumpAllTable dumpTable) // IL code foreach (Instruction instruction in m.Body.Instructions) { + if (instruction.OpCode.OperandType == OperandType.InlineMethod || + instruction.OpCode.OperandType == OperandType.InlineField || + instruction.OpCode.OperandType == OperandType.InlineTok || + instruction.OpCode.OperandType == OperandType.InlineType) + { + realToken = ((IMetadataTokenProvider)instruction.Operand).MetadataToken.ToInt32().ToString("X8"); + } + + string typeName = string.Empty; + ILCode ilCode = new ILCode(); - ilCode.IL += instruction.OpCode.Name.PadRight(12); + StringBuilder ilDescription = new StringBuilder(); + + ilDescription.Append($"IL_{instruction.Offset:x4}: "); + + ilDescription.Append(instruction.OpCode.Name.PadRight(12)); if (instruction.Operand != null) { - if (instruction.OpCode.OperandType == OperandType.InlineTok || - instruction.OpCode.OperandType == OperandType.InlineSig) + if (instruction.OpCode.OperandType == OperandType.InlineMethod) { - ilCode.IL += $"[{((IMetadataTokenProvider)instruction.Operand).MetadataToken.ToInt32():x8}]"; + typeName = (instruction.Operand as MethodReference).FullName; + + referenceId = _tablesContext.GetMethodReferenceId((MethodReference)instruction.Operand); + + // get CLR table + var clrTable = nanoTokenHelpers.DecodeTableIndex(referenceId, nanoTokenHelpers.NanoMemberRefTokenTables); + + // need to clear the encoded type mask + referenceId = nanoTokenHelpers.DecodeReferenceIndex(referenceId, nanoTokenHelpers.NanoMemberRefTokenTables); + + ilDescription.Append($"{typeName} [{new nanoMetadataToken(clrTable, referenceId)}] /*{realToken}*/"); } else if (instruction.OpCode.OperandType == OperandType.InlineField) { - // output the field type name - ilCode.IL += $"{((FieldReference)instruction.Operand).FieldType.FullName}"; + typeName = (instruction.Operand as FieldReference).FullName; + + referenceId = _tablesContext.GetFieldReferenceId((FieldReference)instruction.Operand); - // output the token - ilCode.IL += $" [{((IMetadataTokenProvider)instruction.Operand).MetadataToken.ToInt32():x8}]"; + // get CLR table + var clrTable = nanoTokenHelpers.DecodeTableIndex(referenceId, nanoTokenHelpers.NanoFieldMemberRefTokenTables); + + // need to clear the encoded type mask + referenceId = nanoTokenHelpers.DecodeReferenceIndex(referenceId, nanoTokenHelpers.NanoFieldMemberRefTokenTables); + + ilDescription.Append($"{typeName} [{new nanoMetadataToken(clrTable, referenceId)}] /*{realToken}*/"); } - else if (instruction.OpCode.OperandType == Mono.Cecil.Cil.OperandType.InlineMethod) + else if (instruction.OpCode.OperandType == OperandType.InlineTok) { - // output the method name - ilCode.IL += $"{((MethodReference)instruction.Operand).FullName}"; + var token = _tablesContext.GetMetadataToken((IMetadataTokenProvider)instruction.Operand); - // output the token - ilCode.IL += $" [{((IMetadataTokenProvider)instruction.Operand).MetadataToken.ToInt32():x8}]"; + ilDescription.Append($"[{token:X8}] /*{realToken}*/"); } else if (instruction.OpCode.OperandType == OperandType.InlineType) { - // Mono.Cecil.ArrayType - if (instruction.Operand is ArrayType arrayType) - { - // output the type name - ilCode.IL += $"{arrayType.ElementType.FullName}[]"; - } - else + referenceId = _tablesContext.GetTypeReferenceId((TypeReference)instruction.Operand); + var nfToken = new nanoMetadataToken(); + + // get CLR table + var clrTable = nanoTokenHelpers.DecodeTableIndex(referenceId, nanoTokenHelpers.NanoTypeTokenTables); + + // need to clear the encoded type mask + referenceId = nanoTokenHelpers.DecodeReferenceIndex(referenceId, nanoTokenHelpers.NanoTypeTokenTables); + + switch (clrTable) { - // output the type name - ilCode.IL += $"{((TypeReference)instruction.Operand).FullName}"; + case NanoClrTable.TBL_GenericParam: + typeName = (instruction.Operand as GenericParameter).TypeSignatureAsString(); + nfToken = new nanoMetadataToken(NanoClrTable.TBL_GenericParam, referenceId); + break; + + case NanoClrTable.TBL_TypeSpec: + if (instruction.Operand is TypeSpecification) + { + typeName = (instruction.Operand as TypeSpecification).FullName; + } + else if (instruction.Operand is GenericParameter) + { + typeName = (instruction.Operand as GenericParameter).FullName; + + if ((instruction.Operand as GenericParameter).Owner is TypeDefinition) + { + ilDescription.Append("!"); + } + if ((instruction.Operand as GenericParameter).Owner is MethodDefinition) + { + ilDescription.Append("!!"); + } + } + else + { + Debug.Fail($"Can't find table for operand type {instruction.Operand}."); + } + + // need to fake a MetadataToken and add one because ours is 0 indexed + realToken = new MetadataToken(TokenType.TypeSpec, referenceId + 1).ToUInt32().ToString("X8"); + + nfToken = new nanoMetadataToken(NanoClrTable.TBL_TypeSpec, referenceId); + + break; + + case NanoClrTable.TBL_TypeRef: + typeName = (instruction.Operand as TypeReference).FullName; + nfToken = new nanoMetadataToken(NanoClrTable.TBL_TypeRef, referenceId); + break; + + case NanoClrTable.TBL_TypeDef: + typeName = (instruction.Operand as TypeDefinition).FullName; + nfToken = new nanoMetadataToken(NanoClrTable.TBL_TypeDef, referenceId); + break; + + default: + Debug.Fail($"Can't find table for operand type {instruction.Operand}."); + break; } - // output the token - ilCode.IL += $" [{((IMetadataTokenProvider)instruction.Operand).MetadataToken.ToInt32():x8}]"; + ilDescription.Append($"{typeName}[{nfToken}] /*{realToken}*/"); } else if (instruction.OpCode.OperandType == OperandType.InlineString) { // strings need a different processing // get string ID from table - ushort stringReferenceId = _tablesContext.StringTable.GetOrCreateStringId((string)instruction.Operand, true); - - // fake the metadata token from the ID - MetadataToken stringMetadataToken = new MetadataToken(TokenType.String, stringReferenceId); + referenceId = _tablesContext.StringTable.GetOrCreateStringId((string)instruction.Operand, true); - // output the string - ilCode.IL += $"\"{(string)instruction.Operand}\""; - - // ouput the metadata token - ilCode.IL += $" [{stringMetadataToken.ToInt32():x8}]"; + ilDescription.Append($"\"{instruction.Operand}\" [{new nanoMetadataToken(NanoClrTable.TBL_Strings, referenceId)}]"); + } + else if (instruction.OpCode.OperandType == OperandType.InlineI + || instruction.OpCode.OperandType == OperandType.ShortInlineI) + { + ilDescription.Append($"{instruction.Operand:x8}"); + } + else if (instruction.OpCode.OperandType == OperandType.InlineSig) + { + Debug.Fail("Check this"); + ilDescription.Append($"InlineSig ???? /*{realToken}*/"); } - } + // clean-up trailing spaces + ilCode.IL = ilDescription.ToString().TrimEnd(); + methodDef.ILCode.Add(ilCode); } } @@ -405,11 +562,19 @@ private void DumpTypeDefinitions(DumpAllTable dumpTable) // list interface implementations foreach (InterfaceImplementation i in t.Interfaces) { + string realInterfaceToken = i.MetadataToken.ToInt32().ToString("X8"); + string realInterfaceTypeToken = i.InterfaceType.MetadataToken.ToInt32().ToString("X8"); + + // TODO + //_tablesContext.TypeDefinitionTable.TryGetTypeReferenceId(i as TypeDefinition, out ushort interfaceTypeReferenceId); + _tablesContext.TypeDefinitionTable.TryGetTypeReferenceId(i.InterfaceType as TypeDefinition, out ushort interfaceTypeReferenceId); + ushort interfaceReferenceId = 0xFFFF; + typeDef.InterfaceDefinitions.Add( new InterfaceDef() { - ReferenceId = i.MetadataToken.ToInt32().ToString("x8"), - Interface = i.InterfaceType.MetadataToken.ToInt32().ToString("x8") + ReferenceId = $"[{interfaceReferenceId:x4}] /*{realInterfaceToken}*/", + Interface = $"[{interfaceTypeReferenceId:x4}] /*{realInterfaceTypeToken}*/" }); } @@ -421,19 +586,17 @@ private void DumpTypeReferences(DumpAllTable dumpTable) { foreach (var t in _tablesContext.TypeReferencesTable.Items.OrderBy(tr => tr.MetadataToken.ToInt32())) { - ushort refId; + string realToken = t.MetadataToken.ToInt32().ToString("X8"); var typeRef = new TypeRef() { Name = t.FullName, // need to add 1 to match the index on the old MDP - Scope = new MetadataToken(TokenType.AssemblyRef, _tablesContext.TypeReferencesTable.GetScope(t) + 1).ToInt32().ToString("x8") + Scope = $"[{_tablesContext.TypeReferencesTable.GetScope(t):x4}] /*{realToken}*/" }; - if (_tablesContext.TypeReferencesTable.TryGetTypeReferenceId(t, out refId)) - { - typeRef.ReferenceId = t.MetadataToken.ToInt32().ToString("x8"); - } + _tablesContext.TypeReferencesTable.TryGetTypeReferenceId(t, out ushort referenceId); + typeRef.ReferenceId = $"[{new nanoMetadataToken(t.MetadataToken, referenceId)}] /*{realToken}*/"; // list member refs foreach (var m in _tablesContext.MethodReferencesTable.Items.Where(mr => mr.DeclaringType == t)) @@ -443,11 +606,12 @@ private void DumpTypeReferences(DumpAllTable dumpTable) Name = m.Name }; - if (_tablesContext.MethodReferencesTable.TryGetMethodReferenceId(m, out refId)) - { - memberRef.ReferenceId = m.MetadataToken.ToInt32().ToString("x8"); - memberRef.Signature = PrintSignatureForMethod(m); - } + realToken = m.MetadataToken.ToInt32().ToString("X8"); + + _tablesContext.MethodReferencesTable.TryGetMethodReferenceId(m, out referenceId); + + memberRef.ReferenceId = $"[{new nanoMetadataToken(m.MetadataToken, referenceId)}] /*{realToken}*/"; + memberRef.Signature = PrintSignatureForMethod(m); typeRef.MemberReferences.Add(memberRef); } @@ -465,17 +629,119 @@ private void DumpAssemblyReferences(DumpAllTable dumpTable) { foreach (var a in _tablesContext.AssemblyReferenceTable.Items) { + string realToken = a.MetadataToken.ToInt32().ToString("X8"); + + var referenceId = _tablesContext.AssemblyReferenceTable.GetReferenceId(a); + dumpTable.AssemblyReferences.Add(new AssemblyRef() { Name = a.Name, // need to add 1 to match the index on the old MDP - ReferenceId = new MetadataToken(TokenType.AssemblyRef, _tablesContext.AssemblyReferenceTable.GetReferenceId(a) + 1).ToInt32().ToString("x8"), + ReferenceId = $"[{new nanoMetadataToken(a.MetadataToken, referenceId)}] /*{realToken}*/", Flags = "00000000" }); } } - private string PrintSignatureForMethod(MethodReference method) + private void DumpTypeSpecifications( + TypeReference typeReference, + DumpAllTable dumpTable) + { + + // get real token for the TypeSpec + string realToken = string.Empty; + + _tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(typeReference, out ushort index); + + var typeSpec = new TypeSpec(); + + // assume that real token index is the same as ours + // need to add one because ours is 0 indexed + realToken = new MetadataToken(TokenType.TypeSpec, index + 1).ToUInt32().ToString("X8"); + + typeSpec.ReferenceId = $"[{new nanoMetadataToken(NanoClrTable.TBL_TypeSpec, index)}] /*{realToken}*/"; + + // build name + StringBuilder typeSpecName = new StringBuilder(); + + if (typeReference is GenericParameter) + { + var genericParam = typeReference as GenericParameter; + + typeSpecName.Append(typeReference.MetadataType); + + if (genericParam.Owner is TypeDefinition) + { + typeSpecName.Append("!"); + } + if (genericParam.Owner is MethodDefinition) + { + typeSpecName.Append("!!"); + } + + typeSpecName.Append(genericParam.Owner.GenericParameters.IndexOf(genericParam)); + + typeSpec.Name = typeSpecName.ToString(); + } + else if (typeReference is GenericInstanceType) + { + // type is a GenericInstance + // can't compare with Cecil MetadataToken because the tables have been cleaned-up and re-indexed + + typeSpec.Name = typeReference.FullName; + + foreach (var mr in _tablesContext.MethodReferencesTable.Items) + { + if (_tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(mr.DeclaringType, out ushort referenceId) && + referenceId == index) + { + var memberRef = new MemberRef() + { + Name = mr.Name + }; + + if (_tablesContext.MethodReferencesTable.TryGetMethodReferenceId(mr, out ushort memberRefId)) + { + realToken = mr.MetadataToken.ToInt32().ToString("X8"); + + memberRef.ReferenceId = $"[{new nanoMetadataToken(NanoClrTable.TBL_MethodRef, memberRefId)}] /*{realToken}*/"; + memberRef.Signature = PrintSignatureForMethod(mr); + } + + typeSpec.MemberReferences.Add(memberRef); + } + } + + foreach (var ms in _tablesContext.MethodSpecificationTable.Items) + { + if (_tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(ms.DeclaringType, out ushort referenceId) && + referenceId == index) + { + var memberRef = new MemberRef() + { + Name = ms.Name + }; + + if (_tablesContext.MethodSpecificationTable.TryGetMethodSpecificationId(ms, out ushort methodSpecId)) + { + realToken = ms.MetadataToken.ToInt32().ToString("X8"); + + memberRef.ReferenceId = $"[{new nanoMetadataToken(NanoClrTable.TBL_MethodSpec, methodSpecId)}] /*{realToken}*/"; + memberRef.Signature = PrintSignatureForMethod(ms); + } + + typeSpec.MemberReferences.Add(memberRef); + } + } + + Debug.Assert(typeSpec.MemberReferences.Count > 0, $"Couldn't find any MethodRef for TypeSpec[{typeReference}] {typeReference.FullName}"); + } + + dumpTable.TypeSpecifications.Add(typeSpec); + } + + + internal static string PrintSignatureForMethod(MethodReference method) { var sig = new StringBuilder(method.ReturnType.TypeSignatureAsString()); @@ -504,26 +770,98 @@ private string PrintSignatureForMethod(MethodReference method) private string PrintSignatureForLocalVar(Collection variables) { - const string localIdentation = " "; - StringBuilder sig = new StringBuilder(); + sig.Append("( "); - sig.Append('('); - - for (int localIndex = 0; localIndex < variables.Count; localIndex++) + foreach (var l in variables) { - sig.Append($"{(localIndex > 0 ? localIdentation : "")} [{localIndex}] "); - sig.Append(variables[localIndex].VariableType.TypeSignatureAsString()); + // ident locals after the 1st one + if (l.Index > 0) + { + sig.Append(" "); + } + + sig.Append($"[{l.Index}] "); + + if (l.VariableType.MetadataType == MetadataType.Class) + { + sig.Append($"class {l.VariableType.FullName}"); + + _tablesContext.TypeDefinitionTable.TryGetTypeReferenceId(l.VariableType as TypeDefinition, out ushort referenceId); + + sig.Append($"[{new nanoMetadataToken(NanoClrTable.TBL_TypeDef, referenceId)}] /*{l.VariableType.MetadataToken.ToInt32().ToString("X8")}*/"); + } + else if (l.VariableType.IsGenericInstance) + { + sig.Append($"class {l.VariableType.FullName}"); + + _tablesContext.TypeSpecificationsTable.TryGetTypeReferenceId(l.VariableType as TypeSpecification, out ushort referenceId); + + sig.Append($"[{new nanoMetadataToken(NanoClrTable.TBL_TypeSpec, referenceId)}] /*{l.VariableType.GetElementType().MetadataToken.ToInt32().ToString("X8")}*/"); + + // now the generic parameters + sig.Append("<"); + + foreach (var p in l.VariableType.GenericParameters) + { + sig.Append(p.Name); + + if (!p.Equals(l.VariableType.GenericParameters.Last())) + { + sig.Append(","); + } + } - if (localIndex < variables.Count - 1) + sig.Append(">"); + } + else { - sig.AppendLine(", "); + sig.Append(l.VariableType.TypeSignatureAsString()); } + + sig.AppendLine(", "); + } + + // remove trailing", " + if (variables.Count > 0) + { + sig.Remove(sig.Length - 4, 4); + } + else + { + sig.Append(" "); } sig.Append(" )"); return sig.ToString(); } + + internal static string TypeDefExtendsTypeToString( + TypeReference baseType, + ushort referenceId) + { + string realToken = baseType.MetadataToken.ToInt32().ToString("X8"); + + return $"{baseType.FullName}[{new nanoMetadataToken(baseType.MetadataToken, referenceId)}] /*{realToken}*/"; + } + + internal static string TypeDefRefIdToString( + TypeDefinition typeDef, + ushort referenceId) + { + string realToken = typeDef.MetadataToken.ToInt32().ToString("X8"); + + return $"[{new nanoMetadataToken(typeDef.MetadataToken, referenceId)}] /*{realToken}*/"; + } + + internal static string MethodDefIdToString( + MethodReference methodRef, + ushort referenceId) + { + string realToken = methodRef.MetadataToken.ToInt32().ToString("X8"); + + return $"[{new nanoMetadataToken(methodRef.MetadataToken, referenceId)}] /*{realToken}*/"; + } } } diff --git a/MetadataProcessor.Shared/nanoFramework.Tools.MetaDataProcessor.Core.targets b/MetadataProcessor.Shared/nanoFramework.Tools.MetaDataProcessor.Core.targets index b6e00e04..7b9846a3 100644 --- a/MetadataProcessor.Shared/nanoFramework.Tools.MetaDataProcessor.Core.targets +++ b/MetadataProcessor.Shared/nanoFramework.Tools.MetaDataProcessor.Core.targets @@ -1,22 +1,22 @@ - - - MSBuild - nanoFramework\v1.0\ - Always - true - - - MSBuild - nanoFramework\v1.0\ - Always - true - - - MSBuild - nanoFramework\v1.0\ - Always - true - - + + + MSBuild + nanoFramework\v1.0\ + Always + true + + + MSBuild + nanoFramework\v1.0\ + Always + true + + + MSBuild + nanoFramework\v1.0\ + Always + true + + diff --git a/MetadataProcessor.Shared/nanoSkeletonGenerator.cs b/MetadataProcessor.Shared/nanoSkeletonGenerator.cs index 093bbad0..0af6a405 100644 --- a/MetadataProcessor.Shared/nanoSkeletonGenerator.cs +++ b/MetadataProcessor.Shared/nanoSkeletonGenerator.cs @@ -1,17 +1,20 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// uncomment this for verbose output of library method lookup +#if DEBUG +//#define VERBOSE_OUTPUT +#endif -using Mono.Cecil; -using Mustache; -using nanoFramework.Tools.MetadataProcessor.Core.Extensions; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; +using Mono.Cecil; +using Mustache; +using nanoFramework.Tools.MetadataProcessor.Core.Extensions; namespace nanoFramework.Tools.MetadataProcessor.Core { @@ -66,9 +69,9 @@ public void GenerateSkeleton() GenerateStubs(); // output native checksum so it shows in build log - Console.WriteLine("++++++++++++++++++++++++++++++++++++++++++++"); + Console.WriteLine("+++++++++++++++++++++++++++++++++++++++++++"); Console.WriteLine($"+ Native declaration checksum: 0x{_tablesContext.NativeMethodsCrc.CurrentCrc.ToString("X8")} +"); - Console.WriteLine("++++++++++++++++++++++++++++++++++++++++++++"); + Console.WriteLine("+++++++++++++++++++++++++++++++++++++++++++"); } else { @@ -89,7 +92,7 @@ private void GenerateStubs() IsInterop = !_withoutInteropCode }; - foreach (TypeDefinition c in _tablesContext.TypeDefinitionTable.TypeDefinitions) + foreach (TypeDefinition c in _tablesContext.TypeDefinitionTable.Items) { if (ShouldIncludeType(c)) { @@ -151,7 +154,7 @@ private void GenerateStubs() { int parameterIndex = 0; - foreach (var item in m.Parameters) + foreach (ParameterDefinition item in m.Parameters) { // get the parameter type string parameterType = string.Empty; @@ -228,7 +231,6 @@ private void GenerateStubs() newMethod.ParameterDeclaration.Add(parameterDeclaration); parameterIndex++; } - declaration.Append("HRESULT &hr )"); marshallingCall.Append("hr )"); } @@ -399,10 +401,10 @@ private void GenerateAssemblyLookup() // need to add a NULL entry for it assemblyLookup.LookupTable.Add(new MethodStub() { -#if DEBUG - Declaration = $"NULL, // <<<<< Library_{_safeProjectName}_{NativeMethodsCrc.GetClassName(c)}::{NativeMethodsCrc.GetMethodName(m)}", +#if DEBUG && VERBOSE_OUTPUT + Declaration = $"nullptr, // <<<<< Library_{_safeProjectName}_{NativeMethodsCrc.GetClassName(c)}::{NativeMethodsCrc.GetMethodName(m)}", #else - Declaration = "NULL" + Declaration = "nullptr" #endif }); } @@ -416,10 +418,10 @@ private void GenerateAssemblyLookup() { assemblyLookup.LookupTable.Add(new MethodStub() { -#if DEBUG - Declaration = $"NULL, // <<<<< Library_{_safeProjectName}_{NativeMethodsCrc.GetClassName(c)}::{NativeMethodsCrc.GetMethodName(m)}", +#if DEBUG && VERBOSE_OUTPUT + Declaration = $"nullptr, // <<<<< Library_{_safeProjectName}_{NativeMethodsCrc.GetClassName(c)}::{NativeMethodsCrc.GetMethodName(m)}", #else - Declaration = "NULL" + Declaration = "nullptr" #endif }); } @@ -604,11 +606,12 @@ private int GetInstanceFieldsOffset(TypeDefinition c) private int GetNestedFieldsCount(TypeDefinition c) { + ushort tt; + int fieldCount = 0; if (c.BaseType != null && - c.BaseType.FullName != "System.Object" && - c.BaseType.FullName != "System.MarshalByRefObject") + c.BaseType.FullName != "System.Object") { // get parent type fields count fieldCount = GetNestedFieldsCount(c.BaseType.Resolve()); diff --git a/MetadataProcessor.Tests/Core/ClrIntegrationTests.cs b/MetadataProcessor.Tests/Core/ClrIntegrationTests.cs index 1cd29857..aa8f1bf3 100644 --- a/MetadataProcessor.Tests/Core/ClrIntegrationTests.cs +++ b/MetadataProcessor.Tests/Core/ClrIntegrationTests.cs @@ -21,12 +21,6 @@ namespace nanoFramework.Tools.MetadataProcessor.Tests.Core [TestClass] public class ClrIntegrationTests { - -#if DEBUG - // path to local instance of nanoCLR DLL (to be used when debugging) - private static string _localClrInstancePath = "E:\\GitHub\\nf-interpreter\\build\\bin\\Debug\\net6.0\\NanoCLR\\nanoFramework.nanoCLR.dll"; -#endif - public static bool NanoClrIsInstalled { get; private set; } = false; [ClassInitialize] @@ -140,7 +134,7 @@ public static void InstallNanoClr(TestContext context) // Tool 'nanoclr' was successfully updated from version '1.0.205' to version '1.0.208'. // or (update becoming reinstall with same version, if there is no new version): // Tool 'nanoclr' was reinstalled with the latest stable version (version '1.0.208'). - var regexResult = Regex.Match(cliResult.StandardOutput, @"((?>version ')(?'version'\d+\.\d+\.\d+)(?>'))"); + Match regexResult = Regex.Match(cliResult.StandardOutput, @"((?>version ')(?'version'\d+\.\d+\.\d+)(?>'))"); if (regexResult.Success) { @@ -172,19 +166,10 @@ public static void InstallNanoClr(TestContext context) } } -#if DEBUG - if (!string.IsNullOrEmpty(_localClrInstancePath)) - { - // done here as we are using a local instance of nanoCLR DLL - return; - } -#else if (!string.IsNullOrEmpty(TestObjectHelper.NanoClrLocalInstance)) { // done here as we are using a local instance of nanoCLR DLL - return; } -#endif else { Console.WriteLine("Upate nanoCLR instance"); @@ -245,14 +230,13 @@ public async Task RunBCLTest() .WithArguments(arguments) .WithValidation(CommandResultValidation.None); - // setup cancellation token with a timeout of 1 minute + // setup cancellation token with a timeout of 30 seconds using (var cts = new CancellationTokenSource()) { - cts.CancelAfter(TimeSpan.FromMinutes(1)); + cts.CancelAfter(TimeSpan.FromSeconds(30)); BufferedCommandResult cliResult = await cmd.ExecuteBufferedAsync(cts.Token); int exitCode = cliResult.ExitCode; - // read standard output string output = cliResult.StandardOutput; @@ -263,10 +247,12 @@ public async Task RunBCLTest() // look for the error message reporting that there is no entry point Assert.IsTrue(output.Contains("Cannot find any entrypoint!")); + + Console.WriteLine($"\r\n>>>>>>>>>>>>>\r\n{output}\r\n>>>>>>>>>>>>>"); } else { - Assert.Fail($"nanoCLR ended with '{exitCode}' exit code.\r\n>>>>>>>>>>>>>\r\n{output}\r\n<<<<<<<<<<<<<"); + Assert.Fail($"nanoCLR ended with '{exitCode}' exit code.\r\n>>>>>>>>>>>>>\r\n{output}\r\n>>>>>>>>>>>>>"); } } } @@ -292,14 +278,13 @@ public async Task RunTestNFAppTest() .WithArguments(arguments) .WithValidation(CommandResultValidation.None); - // setup cancellation token with a timeout of 1 minute - using (var cts = new CancellationTokenSource()) + // setup cancellation token with a timeout of 30 seconds + using (CancellationTokenSource cts = new CancellationTokenSource()) { - cts.CancelAfter(TimeSpan.FromMinutes(1)); + cts.CancelAfter(TimeSpan.FromSeconds(30)); BufferedCommandResult cliResult = await cmd.ExecuteBufferedAsync(cts.Token); int exitCode = cliResult.ExitCode; - // read standard output string output = cliResult.StandardOutput; @@ -318,10 +303,12 @@ public async Task RunTestNFAppTest() // look for the error message reporting that there is no entry point Assert.IsFalse(output.Contains("Cannot find any entrypoint!")); + + Console.WriteLine($"\r\n>>>>>>>>>>>>>\r\n{output}\r\n>>>>>>>>>>>>>"); } else { - Assert.Fail($"nanoCLR ended with '{exitCode}' exit code.\r\n>>>>>>>>>>>>>\r\n{output}\r\n<<<<<<<<<<<<<"); + Assert.Fail($"nanoCLR ended with '{exitCode}' exit code.\r\n>>>>>>>>>>>>>\r\n{output}\r\n>>>>>>>>>>>>>"); } } } @@ -330,10 +317,6 @@ private string ComposeLocalClrInstancePath() { StringBuilder arguments = new StringBuilder(" --localinstance"); -#if DEBUG - arguments.Append($" \"{_localClrInstancePath}\""); - -#else if (string.IsNullOrEmpty(TestObjectHelper.NanoClrLocalInstance)) { return null; @@ -342,7 +325,6 @@ private string ComposeLocalClrInstancePath() { arguments.Append($" \"{TestObjectHelper.NanoClrLocalInstance}\""); } -#endif return arguments.ToString(); } diff --git a/MetadataProcessor.Tests/Core/Endianness/nanoBinaryWriterTests.cs b/MetadataProcessor.Tests/Core/Endianness/nanoBinaryWriterTests.cs index 44312a59..caa0c6d3 100644 --- a/MetadataProcessor.Tests/Core/Endianness/nanoBinaryWriterTests.cs +++ b/MetadataProcessor.Tests/Core/Endianness/nanoBinaryWriterTests.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; using System.IO; diff --git a/MetadataProcessor.Tests/Core/Extensions/ByteArrayExtensionsTests.cs b/MetadataProcessor.Tests/Core/Extensions/ByteArrayExtensionsTests.cs index 4ea38383..97d7cfa0 100644 --- a/MetadataProcessor.Tests/Core/Extensions/ByteArrayExtensionsTests.cs +++ b/MetadataProcessor.Tests/Core/Extensions/ByteArrayExtensionsTests.cs @@ -1,9 +1,6 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using nanoFramework.Tools.MetadataProcessor.Core.Extensions; diff --git a/MetadataProcessor.Tests/Core/Extensions/ParameterDefintionExtensionsTests.cs b/MetadataProcessor.Tests/Core/Extensions/ParameterDefintionExtensionsTests.cs index 65750e70..0f1f0aa5 100644 --- a/MetadataProcessor.Tests/Core/Extensions/ParameterDefintionExtensionsTests.cs +++ b/MetadataProcessor.Tests/Core/Extensions/ParameterDefintionExtensionsTests.cs @@ -1,9 +1,6 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using nanoFramework.Tools.MetadataProcessor.Core.Extensions; diff --git a/MetadataProcessor.Tests/Core/Extensions/TypeDefinitionExtensionsTests.cs b/MetadataProcessor.Tests/Core/Extensions/TypeDefinitionExtensionsTests.cs index 75a20fcf..4bdddf8d 100644 --- a/MetadataProcessor.Tests/Core/Extensions/TypeDefinitionExtensionsTests.cs +++ b/MetadataProcessor.Tests/Core/Extensions/TypeDefinitionExtensionsTests.cs @@ -1,15 +1,13 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; +using System.IO; using System.Linq; -using nanoFramework.Tools.MetadataProcessor.Core.Extensions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Mono.Cecil; -using System.IO; -using System.Collections.Generic; +using nanoFramework.Tools.MetadataProcessor.Core.Extensions; namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Extensions { diff --git a/MetadataProcessor.Tests/Core/Extensions/TypeReferenceExtensionsTests.cs b/MetadataProcessor.Tests/Core/Extensions/TypeReferenceExtensionsTests.cs index f15ac330..4083cd9a 100644 --- a/MetadataProcessor.Tests/Core/Extensions/TypeReferenceExtensionsTests.cs +++ b/MetadataProcessor.Tests/Core/Extensions/TypeReferenceExtensionsTests.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; using System.Linq; diff --git a/MetadataProcessor.Tests/Core/Mono.Cecil/CodeWriterTests.cs b/MetadataProcessor.Tests/Core/Mono.Cecil/CodeWriterTests.cs index 4a52e1b5..7c2845d1 100644 --- a/MetadataProcessor.Tests/Core/Mono.Cecil/CodeWriterTests.cs +++ b/MetadataProcessor.Tests/Core/Mono.Cecil/CodeWriterTests.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; @@ -435,9 +433,9 @@ public void WriteMethodBodyIntegrationTest() #if DEBUG - var expectedBytesWritten = new byte[] { 0x00, 0x16, 0x0A, 0x00, 0x03, 0x04, 0x58, 0x0A, 0x00, 0xDE, 0x18, 0x0B, 0x00, 0x72, 0x84, 0x01, 0x07, 0x73, 0x0D, 0x80, 0x0C, 0x08, 0x6F, 0x0E, 0x80, 0x0A, 0x00, 0xDE, 0x00, 0x06, 0x0D, 0x2B, 0x00, 0x09, 0x2A, 0x00, 0x00, 0x11, 0x80, 0x03, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x23, 0x00, 0x01 }; + var expectedBytesWritten = new byte[] { 0x00, 0x16, 0x0A, 0x00, 0x03, 0x04, 0x58, 0x0A, 0x00, 0xDE, 0x18, 0x0B, 0x00, 0x72, 0xAE, 0x01, 0x07, 0x73, 0x15, 0x80, 0x0C, 0x08, 0x6F, 0x16, 0x80, 0x0A, 0x00, 0xDE, 0x00, 0x06, 0x0D, 0x2B, 0x00, 0x09, 0x2A, 0x00, 0x00, 0x11, 0x80, 0x03, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x23, 0x00, 0x01 }; #else - var expectedBytesWritten = new byte[] { 0x16, 0x0A, 0x03, 0x04, 0x58, 0x0A, 0xDE, 0x16, 0x0B, 0x72, 0x48, 0x01, 0x07, 0x73, 0x0C, 0x80, 0x0C, 0x08, 0x6F, 0x0D, 0x80, 0x0A, 0xDE, 0x00, 0x06, 0x2A, 0x00, 0x00, 0x0F, 0x80, 0x02, 0x00, 0x08, 0x00, 0x08, 0x00, 0x1E, 0x00, 0x01 }; + var expectedBytesWritten = new byte[] { 0x16, 0x0A, 0x03, 0x04, 0x58, 0x0A, 0xDE, 0x16, 0x0B, 0x72, 0x72, 0x01, 0x07, 0x73, 0x13, 0x80, 0x0C, 0x08, 0x6F, 0x14, 0x80, 0x0A, 0xDE, 0x00, 0x06, 0x2A, 0x00, 0x00, 0x0F, 0x80, 0x02, 0x00, 0x08, 0x00, 0x08, 0x00, 0x1E, 0x00, 0x01 }; #endif Assert.AreEqual(expectedBytesWritten.Length, bytesWritten.Length, "Method body length differs."); diff --git a/MetadataProcessor.Tests/Core/Tables/nanoAssemblyReferenceTableTests.cs b/MetadataProcessor.Tests/Core/Tables/nanoAssemblyReferenceTableTests.cs index b25f56d6..982463ee 100644 --- a/MetadataProcessor.Tests/Core/Tables/nanoAssemblyReferenceTableTests.cs +++ b/MetadataProcessor.Tests/Core/Tables/nanoAssemblyReferenceTableTests.cs @@ -1,13 +1,11 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Tables { @@ -90,9 +88,6 @@ public void WriteTest() { writerTestOutput.Write(context.StringTable.GetOrCreateStringId(a.Name)); - // padding - writerTestOutput.Write((ushort)0x0); - // version writerTestOutput.Write((ushort)a.Version.Major); writerTestOutput.Write((ushort)a.Version.Minor); diff --git a/MetadataProcessor.Tests/Core/Tables/nanoAttributesTableTests.cs b/MetadataProcessor.Tests/Core/Tables/nanoAttributesTableTests.cs index 4390b9ac..8b0fa5e6 100644 --- a/MetadataProcessor.Tests/Core/Tables/nanoAttributesTableTests.cs +++ b/MetadataProcessor.Tests/Core/Tables/nanoAttributesTableTests.cs @@ -1,15 +1,13 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Mono.Cecil; -using nanoFramework.Tools.MetadataProcessor.Core.Extensions; using System; using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Mono.Cecil; +using nanoFramework.Tools.MetadataProcessor.Core.Extensions; using CustomAttribute = Mono.Cecil.CustomAttribute; namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Tables diff --git a/MetadataProcessor.Tests/Core/Tables/nanoMethodDefinitionTableTests.cs b/MetadataProcessor.Tests/Core/Tables/nanoMethodDefinitionTableTests.cs index e2e19b0e..2a4ca859 100644 --- a/MetadataProcessor.Tests/Core/Tables/nanoMethodDefinitionTableTests.cs +++ b/MetadataProcessor.Tests/Core/Tables/nanoMethodDefinitionTableTests.cs @@ -1,11 +1,9 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using Mono.Cecil; -using System.Linq; namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Tables { diff --git a/MetadataProcessor.Tests/Core/Tables/nanoReferenceTableBaseTests.cs b/MetadataProcessor.Tests/Core/Tables/nanoReferenceTableBaseTests.cs index 01107e41..a8c9c27b 100644 --- a/MetadataProcessor.Tests/Core/Tables/nanoReferenceTableBaseTests.cs +++ b/MetadataProcessor.Tests/Core/Tables/nanoReferenceTableBaseTests.cs @@ -1,15 +1,13 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Mono.Cecil; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Tables { diff --git a/MetadataProcessor.Tests/Core/Tables/nanoSignaturesTableTests.cs b/MetadataProcessor.Tests/Core/Tables/nanoSignaturesTableTests.cs index 833a75bf..0cf66d04 100644 --- a/MetadataProcessor.Tests/Core/Tables/nanoSignaturesTableTests.cs +++ b/MetadataProcessor.Tests/Core/Tables/nanoSignaturesTableTests.cs @@ -15,14 +15,14 @@ namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Tables [TestClass] public class nanoSignaturesTableTests { - [DataRow("System.DateTime", nanoCLR_DataType.DATATYPE_DATETIME)] - [DataRow("System.TimeSpan", nanoCLR_DataType.DATATYPE_TIMESPAN)] - [DataRow("System.String", nanoCLR_DataType.DATATYPE_STRING)] - [DataRow("System.Object", nanoCLR_DataType.DATATYPE_CLASS)] - [DataRow("System.IntPtr", nanoCLR_DataType.DATATYPE_VALUETYPE)] - [DataRow("System.WeakReference", nanoCLR_DataType.DATATYPE_WEAKCLASS)] + [DataRow("System.DateTime", NanoCLRDataType.DATATYPE_DATETIME)] + [DataRow("System.TimeSpan", NanoCLRDataType.DATATYPE_TIMESPAN)] + [DataRow("System.String", NanoCLRDataType.DATATYPE_STRING)] + [DataRow("System.Object", NanoCLRDataType.DATATYPE_CLASS)] + [DataRow("System.IntPtr", NanoCLRDataType.DATATYPE_VALUETYPE)] + [DataRow("System.WeakReference", NanoCLRDataType.DATATYPE_WEAKCLASS)] [TestMethod] - public void WriteDataTypeForTypeRef_ShouldWriteCorrectDataType(string typeFullName, nanoCLR_DataType dataType) + public void WriteDataTypeForTypeRef_ShouldWriteCorrectDataType(string typeFullName, NanoCLRDataType dataType) { // Arrange AssemblyDefinition mscorlibAssemblyDefinition = AssemblyDefinition.ReadAssembly(TestObjectHelper.MscorlibFullPath); diff --git a/MetadataProcessor.Tests/Core/Utility/Crc32Tests.cs b/MetadataProcessor.Tests/Core/Utility/Crc32Tests.cs index 0955fe28..7757de0b 100644 --- a/MetadataProcessor.Tests/Core/Utility/Crc32Tests.cs +++ b/MetadataProcessor.Tests/Core/Utility/Crc32Tests.cs @@ -1,10 +1,8 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Utility { diff --git a/MetadataProcessor.Tests/Core/Utility/DumperTests.cs b/MetadataProcessor.Tests/Core/Utility/DumperTests.cs index 03c9120a..284fdf79 100644 --- a/MetadataProcessor.Tests/Core/Utility/DumperTests.cs +++ b/MetadataProcessor.Tests/Core/Utility/DumperTests.cs @@ -2,17 +2,25 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics; using System.IO; -using System.Text.RegularExpressions; +using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Mono.Cecil; using nanoFramework.Tools.MetadataProcessor.Core; +using nanoFramework.Tools.MetadataProcessor.Core.Extensions; namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Utility { [TestClass] public class DumperTests { + private ushort refId; + [TestMethod] +#if !DEBUG + [Ignore("This test is ignored in Release builds.")] +#endif public void DumpAssemblyTest() { nanoTablesContext nanoTablesContext = TestObjectHelper.GetTestNFAppNanoTablesContext(); @@ -36,42 +44,114 @@ public void DumpAssemblyTest() // search for several bits // AssemblyRefs - Assert.IsTrue(dumpFileContent.Contains("AssemblyRefProps [23000001]: Flags: 00000000 'mscorlib'"), "Wrong entry for mscorlib in assembly ref"); - Assert.IsTrue(dumpFileContent.Contains("AssemblyRefProps [23000002]: Flags: 00000000 'TestNFClassLibrary'"), "Wrong entry for TestNFClassLibrary in assembly ref"); + Assert.IsTrue(dumpFileContent.Contains("AssemblyRef [00000000] /*23000001*/\r\n-------------------------------------------------------\r\n'mscorlib'")); + Assert.IsTrue(dumpFileContent.Contains("AssemblyRef [00000001] /*23000002*/\r\n-------------------------------------------------------\r\n'TestNFClassLibrary'")); // TypeRefs - Assert.IsTrue(dumpFileContent.Contains("TypeRefProps [01000001]: Scope: 23000001 'System.Diagnostics.DebuggableAttribute'"), "Wrong entry for System.Diagnostics.DebuggableAttribute in type ref"); - Assert.IsTrue(dumpFileContent.Contains(": Scope: 23000002 'TestNFClassLibrary.ClassOnAnotherAssembly'"), "Wrong entry for TestNFClassLibrary.ClassOnAnotherAssembly in type ref"); + Assert.IsTrue(dumpFileContent.Contains("TypeRef [01000000] /*01000001*/\r\n-------------------------------------------------------\r\nScope: [0000] /*01000001*/\r\n 'System.Diagnostics.DebuggableAttribute'")); + Assert.IsTrue(dumpFileContent.Contains("TypeRef [0100001E] /*0100001F*/\r\n-------------------------------------------------------\r\nScope: [0001] /*0100001F*/\r\n 'TestNFClassLibrary.ClassOnAnotherAssembly'")); - Assert.IsTrue(dumpFileContent.Contains(": Flags: 00001001 Extends: 01000010 Enclosed: 02000000 'TestNFApp.DummyCustomAttribute1'"), "Wrong entry for TestNFApp.DummyCustomAttribute1 in type ref"); + // TestNFApp.DummyCustomAttribute1 + string typeName = "TestNFApp.DummyCustomAttribute1"; + TypeDefinition type1 = nanoTablesContext.TypeDefinitionTable.Items.FirstOrDefault(t => t.FullName == typeName); + nanoTablesContext.TypeDefinitionTable.TryGetTypeReferenceId(type1, out ushort typeRefId); + nanoTablesContext.TypeReferencesTable.TryGetTypeReferenceId(type1.BaseType, out ushort baseTypeReferenceId); + uint typeFlags = (uint)nanoTypeDefinitionTable.GetFlags(type1, nanoTablesContext.MethodDefinitionTable); - Assert.IsTrue(dumpFileContent.Contains(": Flags: 00001001 Extends: 01000010 Enclosed: 02000000 'TestNFApp.DummyCustomAttribute2'"), "Wrong entry for TestNFApp.DummyCustomAttribute2 in type ref"); + Assert.IsTrue(dumpFileContent.Contains($"TypeDef {nanoDumperGenerator.TypeDefRefIdToString(type1, typeRefId)}\r\n-------------------------------------------------------\r\n '{typeName}'\r\n Flags: {typeFlags:X8}\r\n Extends: {nanoDumperGenerator.TypeDefExtendsTypeToString(type1.BaseType, baseTypeReferenceId)}\r\n Enclosed: (none)")); - Assert.IsTrue(dumpFileContent.Contains(": Flags: 00001061 Extends: 01000000 Enclosed: 02000000 'TestNFApp.IOneClassOverAll'"), "Wrong entry for TestNFApp.IOneClassOverAll in type ref"); - Assert.IsTrue(dumpFileContent.Contains(": Flags: 000007c6 Impl: 00000000 RVA: 00000000 'get_DummyProperty' [I4( )]"), "Wrong entry for get_DummyProperty in type ref"); - Assert.IsTrue(dumpFileContent.Contains(": Flags: 000007c6 Impl: 00000000 RVA: 00000000 'set_DummyProperty' [VOID(I4)]"), "Wrong entry for set_DummyProperty in type ref"); - Assert.IsTrue(dumpFileContent.Contains(": Flags: 000003c6 Impl: 00000000 RVA: 00000000 'DummyMethod' [VOID( )]"), "Wrong entry for DummyMethod in type ref"); + // TestNFApp.DummyCustomAttribute2 + typeName = "TestNFApp.DummyCustomAttribute2"; + type1 = nanoTablesContext.TypeDefinitionTable.Items.FirstOrDefault(t => t.FullName == typeName); + nanoTablesContext.TypeDefinitionTable.TryGetTypeReferenceId(type1, out typeRefId); + nanoTablesContext.TypeReferencesTable.TryGetTypeReferenceId(type1.BaseType, out baseTypeReferenceId); + typeFlags = (uint)nanoTypeDefinitionTable.GetFlags(type1, nanoTablesContext.MethodDefinitionTable); - Assert.IsTrue(dumpFileContent.Contains("Enclosed: 02000000 'TestNFApp.OneClassOverAll'"), "Wrong entry for TestNFApp.OneClassOverAll in type ref"); - Assert.IsTrue(dumpFileContent.Contains(": Attr: 00000001 Flags: 00000001 'dummyField' [STRING]"), "Wrong entry for dummyField in type ref"); - Assert.IsTrue(dumpFileContent.Contains(": Attr: 00000001 Flags: 00000001 'k__BackingField' [I4]"), "Wrong entry for k__BackingField in type ref"); - Assert.IsTrue(dumpFileContent.Contains(": Flags: 00000086 Impl: 00000000 RVA: 00000000 'DummyExternMethod' [VOID( )]"), "Wrong entry for DummyExternMethod in type ref"); + Assert.IsTrue(dumpFileContent.Contains($"TypeDef {nanoDumperGenerator.TypeDefRefIdToString(type1, typeRefId)}\r\n-------------------------------------------------------\r\n '{typeName}'\r\n Flags: {typeFlags:X8}\r\n Extends: {nanoDumperGenerator.TypeDefExtendsTypeToString(type1.BaseType, baseTypeReferenceId)}\r\n Enclosed: (none)")); - Assert.IsTrue(dumpFileContent.Contains("'TestNFApp.Program'"), "Wrong entry for TestNFApp.Program in type ref"); + // TestNFApp.IOneClassOverAll + typeName = "TestNFApp.IOneClassOverAll"; + type1 = nanoTablesContext.TypeDefinitionTable.Items.FirstOrDefault(t => t.FullName == typeName); + nanoTablesContext.TypeDefinitionTable.TryGetTypeReferenceId(type1, out typeRefId); + typeFlags = (uint)nanoTypeDefinitionTable.GetFlags(type1, nanoTablesContext.MethodDefinitionTable); - Assert.IsTrue(dumpFileContent.Contains("'SubClass'"), "Wrong entry for SubClass in type ref"); + Assert.IsTrue(dumpFileContent.Contains($"TypeDef {nanoDumperGenerator.TypeDefRefIdToString(type1, typeRefId)}\r\n-------------------------------------------------------\r\n '{typeName}'\r\n Flags: {typeFlags:X8}\r\n Extends: (none)\r\n Enclosed: (none)")); - // skip this assert to locals listing as the debug build will differ as it not optimized -#if !DEBUG - Assert.IsTrue(Regex.IsMatch(dumpFileContent, @"Locals \( \[0\] I4, \r\n\s+\[1\] CLASS System\.Exception \[\d{8}\], \r\n\s+\[2\] CLASS System\.ApplicationException \[\d{8}\] \)"), "Wrong listing of locals in UglyAdd method"); -#endif - Assert.IsTrue(dumpFileContent.Contains("callvirt System.Void TestNFApp.TestingDelegates/SimpleDelegate::Invoke(System.String)"), "Wrong reference to callvirt in DelegateTests body"); - Assert.IsTrue(dumpFileContent.Contains("ldstr \" DataRowAttribute.Arg[{0}] has: {1}\""), "Wrong reference to ldstr in ReflectionTests body"); + foreach (MethodDefinition m in type1.Methods) + { + _ = nanoTablesContext.MethodDefinitionTable.TryGetMethodReferenceId(m, out ushort methodReferenceId); + + Assert.IsTrue(dumpFileContent.Contains($" MethodDef {nanoDumperGenerator.MethodDefIdToString(m, methodReferenceId)}\r\n -------------------------------------------------------\r\n '{m.FullName()}'\r\n Flags: {nanoMethodDefinitionTable.GetFlags(m):X8}\r\n Impl: 00000000\r\n RVA: 0000FFFF\r\n [{nanoDumperGenerator.PrintSignatureForMethod(m)}]")); + } + + // TestNFApp.ComplexAttribute + typeName = "TestNFApp.ComplexAttribute"; + type1 = nanoTablesContext.TypeDefinitionTable.Items.FirstOrDefault(t => t.FullName == typeName); + nanoTablesContext.TypeDefinitionTable.TryGetTypeReferenceId(type1, out typeRefId); + nanoTablesContext.TypeReferencesTable.TryGetTypeReferenceId(type1.BaseType, out baseTypeReferenceId); + + FieldDefinition maxField = nanoTablesContext.FieldsTable.Items.FirstOrDefault(f => f.Name == "_max"); + string maxFieldRealToken = maxField.MetadataToken.ToInt32().ToString("X8"); + nanoTablesContext.FieldsTable.TryGetFieldReferenceId(maxField, false, out ushort maxFieldReferenceId); + + FieldDefinition sField = nanoTablesContext.FieldsTable.Items.FirstOrDefault(f => f.Name == "_s"); + string sFieldRealToken = sField.MetadataToken.ToInt32().ToString("X8"); + nanoTablesContext.FieldsTable.TryGetFieldReferenceId(sField, false, out ushort sFieldReferenceId); + + FieldDefinition bField = nanoTablesContext.FieldsTable.Items.FirstOrDefault(f => f.Name == "_b"); + string bFieldRealToken = bField.MetadataToken.ToInt32().ToString("X8"); + nanoTablesContext.FieldsTable.TryGetFieldReferenceId(bField, false, out ushort bFieldReferenceId); + + + typeFlags = (uint)nanoTypeDefinitionTable.GetFlags(type1, nanoTablesContext.MethodDefinitionTable); + + Assert.IsTrue(dumpFileContent.Contains($"TypeDef {nanoDumperGenerator.TypeDefRefIdToString(type1, typeRefId)}\r\n-------------------------------------------------------\r\n '{typeName}'\r\n Flags: {typeFlags:X8}\r\n Extends: {nanoDumperGenerator.TypeDefExtendsTypeToString(type1.BaseType, baseTypeReferenceId)}\r\n Enclosed: (none)")); + Assert.IsTrue(dumpFileContent.Contains($" FieldDef [{new nanoMetadataToken(maxField.MetadataToken, maxFieldReferenceId)}] /*{maxFieldRealToken}*/\r\n -------------------------------------------------------\r\n Attr: 00000021\r\n Flags: 00000021\r\n '_max'\r\n [U4]\r\n")); + Assert.IsTrue(dumpFileContent.Contains($" FieldDef [{new nanoMetadataToken(sField.MetadataToken, sFieldReferenceId)}] /*{sFieldRealToken}*/\r\n -------------------------------------------------------\r\n Attr: 00000021\r\n Flags: 00000021\r\n '_s'\r\n [STRING]\r\n")); + Assert.IsTrue(dumpFileContent.Contains($" FieldDef [{new nanoMetadataToken(bField.MetadataToken, bFieldReferenceId)}] /*{bFieldRealToken}*/\r\n -------------------------------------------------------\r\n Attr: 00000021\r\n Flags: 00000021\r\n '_b'\r\n [BOOLEAN]\r\n")); + + foreach (MethodDefinition m in type1.Methods) + { + _ = nanoTablesContext.MethodDefinitionTable.TryGetMethodReferenceId(m, out ushort methodReferenceId); + + Assert.IsTrue(dumpFileContent.Contains($" MethodDef {nanoDumperGenerator.MethodDefIdToString(m, methodReferenceId)}\r\n -------------------------------------------------------\r\n '{m.FullName()}'\r\n Flags: {nanoMethodDefinitionTable.GetFlags(m):X8}\r\n Impl: 00000000\r\n RVA: 0000FFFF\r\n [{nanoDumperGenerator.PrintSignatureForMethod(m)}]")); + } + + // TestNFApp.Program + typeName = "TestNFApp.Program"; + type1 = nanoTablesContext.TypeDefinitionTable.Items.FirstOrDefault(t => t.FullName == typeName); + nanoTablesContext.TypeDefinitionTable.TryGetTypeReferenceId(type1, out typeRefId); + nanoTablesContext.TypeReferencesTable.TryGetTypeReferenceId(type1.BaseType, out baseTypeReferenceId); + typeFlags = (uint)nanoTypeDefinitionTable.GetFlags(type1, nanoTablesContext.MethodDefinitionTable); + + Assert.IsTrue(dumpFileContent.Contains($"TypeDef {nanoDumperGenerator.TypeDefRefIdToString(type1, typeRefId)}\r\n-------------------------------------------------------\r\n '{typeName}'\r\n Flags: {typeFlags:X8}\r\n Extends: {nanoDumperGenerator.TypeDefExtendsTypeToString(type1.BaseType, baseTypeReferenceId)}\r\n Enclosed: (none)")); + + // OneClassOverAll/SubClass + typeName = "TestNFApp.OneClassOverAll/SubClass"; + type1 = nanoTablesContext.TypeDefinitionTable.Items.FirstOrDefault(t => t.FullName == typeName); + nanoTablesContext.TypeDefinitionTable.TryGetTypeReferenceId(type1, out typeRefId); + nanoTablesContext.TypeReferencesTable.TryGetTypeReferenceId(type1.BaseType, out baseTypeReferenceId); + typeFlags = (uint)nanoTypeDefinitionTable.GetFlags(type1, nanoTablesContext.MethodDefinitionTable); + + Assert.IsTrue(dumpFileContent.Contains($"TypeDef {nanoDumperGenerator.TypeDefRefIdToString(type1, typeRefId)}\r\n-------------------------------------------------------\r\n '{type1.Name}'\r\n Flags: {typeFlags:X8}\r\n Extends: {nanoDumperGenerator.TypeDefExtendsTypeToString(type1.BaseType, baseTypeReferenceId)}\r\n Enclosed: TestNFApp.OneClassOverAll[04000000] /*0200001B*/")); + + // String heap + foreach (string stringKey in nanoTablesContext.StringTable.GetItems().Keys) + { + // skip initial empty string + if (string.IsNullOrEmpty(stringKey)) + { + continue; + } + + string expectedString = $"{nanoTablesContext.StringTable.GetItems()[stringKey]:X8}: {stringKey}"; + + Assert.IsTrue(dumpFileContent.Contains(expectedString)); + } // UserStrings - Assert.IsTrue(dumpFileContent.Contains(": 'TestNFClassLibrary'"), "Wrong entry for TestNFClassLibrary in user string"); - Assert.IsTrue(dumpFileContent.Contains(": 'get_DummyProperty'"), "Wrong entry for get_DummyProperty in user string"); - Assert.IsTrue(dumpFileContent.Contains(": 'blabla'"), "Wrong entry for blabla in user string"); + System.Collections.Generic.KeyValuePair lastStringEntry = nanoTablesContext.StringTable.GetItems().OrderBy(i => i.Value).Last(); + Assert.IsTrue(dumpFileContent.Contains($"{new nanoMetadataToken(NanoClrTable.TBL_Strings, nanoTablesContext.StringTable.GetOrCreateStringId(lastStringEntry.Key, true))} : ({lastStringEntry.Key.Length:x2}) \"{lastStringEntry.Key}\"")); } } } diff --git a/MetadataProcessor.Tests/Core/Utility/LoadHintsAssemblyResolverTests.cs b/MetadataProcessor.Tests/Core/Utility/LoadHintsAssemblyResolverTests.cs index b526c6ad..f72adf03 100644 --- a/MetadataProcessor.Tests/Core/Utility/LoadHintsAssemblyResolverTests.cs +++ b/MetadataProcessor.Tests/Core/Utility/LoadHintsAssemblyResolverTests.cs @@ -1,11 +1,9 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Utility { @@ -19,7 +17,7 @@ public void ConstructorTest() using (var iut = new LoadHintsAssemblyResolver(new Dictionary())) { // no op - }; + } } [TestMethod] diff --git a/MetadataProcessor.Tests/Core/Utility/NativeMethodsCrcTests.cs b/MetadataProcessor.Tests/Core/Utility/NativeMethodsCrcTests.cs index 7a324ccb..71386720 100644 --- a/MetadataProcessor.Tests/Core/Utility/NativeMethodsCrcTests.cs +++ b/MetadataProcessor.Tests/Core/Utility/NativeMethodsCrcTests.cs @@ -1,12 +1,10 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Mono.Cecil; using System; using System.Collections.Generic; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Mono.Cecil; namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Utility { @@ -72,46 +70,46 @@ public void GetMethodNameTest() } [TestMethod] - public void GetnanoClrTypeNameTest() + public void GetNanoCLRTypeNameTest() { var assemblyDefinition = TestObjectHelper.GetTestNFAppAssemblyDefinition(); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(void), "DATATYPE_VOID"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(sbyte), "DATATYPE_I1"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(short), "DATATYPE_I2"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(int), "DATATYPE_I4"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(long), "DATATYPE_I8"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(void), "DATATYPE_VOID"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(sbyte), "DATATYPE_I1"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(short), "DATATYPE_I2"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(int), "DATATYPE_I4"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(long), "DATATYPE_I8"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(byte), "DATATYPE_U1"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(ushort), "DATATYPE_U2"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(uint), "DATATYPE_U4"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(ulong), "DATATYPE_U8"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(byte), "DATATYPE_U1"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(ushort), "DATATYPE_U2"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(uint), "DATATYPE_U4"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(ulong), "DATATYPE_U8"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(float), "DATATYPE_R4"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(double), "DATATYPE_R8"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(float), "DATATYPE_R4"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(double), "DATATYPE_R8"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(char), "DATATYPE_CHAR"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(string), "DATATYPE_STRING"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(bool), "DATATYPE_BOOLEAN"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(char), "DATATYPE_CHAR"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(string), "DATATYPE_STRING"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(bool), "DATATYPE_BOOLEAN"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(object), "DATATYPE_OBJECT"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(IntPtr), "DATATYPE_I4"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(UIntPtr), "DATATYPE_U4"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(object), "DATATYPE_OBJECT"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(IntPtr), "DATATYPE_I4"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(UIntPtr), "DATATYPE_U4"); - DoGetnanoClrTypeNameTest(assemblyDefinition, typeof(System.WeakReference), "DATATYPE_WEAKCLASS"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, typeof(System.WeakReference), "DATATYPE_WEAKCLASS"); - DoGetnanoClrTypeNameTest(assemblyDefinition, this.GetType(), "nanoFrameworkToolsMetadataProcessorTestsCoreUtilityNativeMethodsCrcTests"); + DoGetNanoCLRTypeNameTest(assemblyDefinition, this.GetType(), "nanoFrameworkToolsMetadataProcessorTestsCoreUtilityNativeMethodsCrcTests"); } - private void DoGetnanoClrTypeNameTest(AssemblyDefinition assemblyDefinition, Type type, string expectedNanoClrTypeName) + private void DoGetNanoCLRTypeNameTest(AssemblyDefinition assemblyDefinition, Type type, string expectedNanoCLRTypeName) { var typeReference = assemblyDefinition.MainModule.ImportReference(type); // test - var r = NativeMethodsCrc.GetnanoClrTypeName(typeReference); + var r = NativeMethodsCrc.GetNanoCLRTypeName(typeReference); - Assert.AreEqual(expectedNanoClrTypeName, r); + Assert.AreEqual(expectedNanoCLRTypeName, r); } @@ -157,7 +155,7 @@ public void CrcWithMethodDefinitionTest() // test iut.UpdateCrc(nonExternMethodDefinition); - Assert.AreEqual((uint)2748897355, iut.CurrentCrc); + Assert.AreEqual((uint)882012044, iut.CurrentCrc); } [TestMethod] diff --git a/MetadataProcessor.Tests/Core/Utility/nanoBitmapProcessorTests.cs b/MetadataProcessor.Tests/Core/Utility/nanoBitmapProcessorTests.cs index e7d206c8..b89d246d 100644 --- a/MetadataProcessor.Tests/Core/Utility/nanoBitmapProcessorTests.cs +++ b/MetadataProcessor.Tests/Core/Utility/nanoBitmapProcessorTests.cs @@ -1,10 +1,8 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Drawing; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Utility { diff --git a/MetadataProcessor.Tests/Core/Utility/nanoDependencyGeneratorWriterTests.cs b/MetadataProcessor.Tests/Core/Utility/nanoDependencyGeneratorWriterTests.cs index 2cc209d4..9068bb6d 100644 --- a/MetadataProcessor.Tests/Core/Utility/nanoDependencyGeneratorWriterTests.cs +++ b/MetadataProcessor.Tests/Core/Utility/nanoDependencyGeneratorWriterTests.cs @@ -1,11 +1,9 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.VisualStudio.TestTools.UnitTesting; using System.IO; using System.Xml; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Utility { diff --git a/MetadataProcessor.Tests/Core/Utility/nanoStringsConstantsTests.cs b/MetadataProcessor.Tests/Core/Utility/nanoStringsConstantsTests.cs index a39a78dc..ccb639aa 100644 --- a/MetadataProcessor.Tests/Core/Utility/nanoStringsConstantsTests.cs +++ b/MetadataProcessor.Tests/Core/Utility/nanoStringsConstantsTests.cs @@ -1,10 +1,8 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.VisualStudio.TestTools.UnitTesting; using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Utility { diff --git a/MetadataProcessor.Tests/Core/nanoAssemblyBuilderTests.cs b/MetadataProcessor.Tests/Core/nanoAssemblyBuilderTests.cs new file mode 100644 index 00000000..be6f5b89 --- /dev/null +++ b/MetadataProcessor.Tests/Core/nanoAssemblyBuilderTests.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace nanoFramework.Tools.MetadataProcessor.Tests.Core +{ + [TestClass] + public class nanoAssemblyBuilderTests + { + [TestMethod] + public void AssemblyTablesCountTest() + { + var nanoTablesContext = TestObjectHelper.GetTestNFAppNanoTablesContext(); + + Assert.IsTrue( + nanoAssemblyBuilder.GetTables(nanoTablesContext).Count() == nanoAssemblyBuilder.TablesCount, + "Tables count from context doesn't match the nanoAssemblyBuilder.TablesCount property."); + + Assert.IsTrue( + nanoAssemblyBuilder.GetTables(nanoTablesContext).Count() == Enum.GetNames(typeof(NanoClrTable)).Length, + "Tables count from context doesn't match number of items in CLR Tables enum."); + } + } +} diff --git a/MetadataProcessor.Tests/MdpNFTestApp/MdpNFTestApp.sln b/MetadataProcessor.Tests/MdpNFTestApp/MdpNFTestApp.sln index a213d3af..6dcad06b 100644 --- a/MetadataProcessor.Tests/MdpNFTestApp/MdpNFTestApp.sln +++ b/MetadataProcessor.Tests/MdpNFTestApp/MdpNFTestApp.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.33530.505 diff --git a/MetadataProcessor.Tests/MetadataProcessor.Tests.csproj b/MetadataProcessor.Tests/MetadataProcessor.Tests.csproj index 5320fe42..760a930e 100644 --- a/MetadataProcessor.Tests/MetadataProcessor.Tests.csproj +++ b/MetadataProcessor.Tests/MetadataProcessor.Tests.csproj @@ -55,12 +55,12 @@ + - @@ -101,19 +101,23 @@ {e32f7d15-2499-440c-8026-4d5ee1c5ec3a} MetadataProcessor.Core + + {9e5e0766-701d-4266-9eba-7b3e4338ed21} + TestNFApp + - 3.8.0 + 3.8.2 0.11.6 - 3.7.2 + 3.8.3 - 3.7.2 + 3.8.3 13.0.3 @@ -124,8 +128,8 @@ nuget restore "$(ProjectDir)mscorlib\nanoFramework.CoreLibrary.sln" - "$(MSBuildBinPath)\msbuild" "$(ProjectDir)mscorlib\nanoFramework.CoreLibrary.sln" -t:Build -nr:False -p:Configuration=$(Configuration) -p:NF_MDP_MSBUILDTASK_PATH="$(ProjectDir)..\MetadataProcessor.MsBuildTask\bin\$(Configuration)\net472" /m - "$(MSBuildBinPath)\msbuild" "$(ProjectDir)TestNFClassLibrary\TestNFClassLibrary\TestNFClassLibrary.nfproj" -t:Build -nr:False -p:Configuration=$(Configuration) -p:NF_MDP_MSBUILDTASK_PATH="$(ProjectDir)..\MetadataProcessor.MsBuildTask\bin\$(Configuration)\net472" + "$(MSBuildBinPath)\msbuild" "$(ProjectDir)mscorlib\nanoFramework.CoreLibrary\CoreLibrary.nfproj" -t:Build -nr:False -p:Configuration=$(Configuration) -p:NF_MDP_MSBUILDTASK_PATH="$(ProjectDir)..\MetadataProcessor.MsBuildTask\bin\$(Configuration)\net472" /m + "$(MSBuildBinPath)\msbuild" "$(ProjectDir)TestNFClassLibrary\TestNFClassLibrary\TestNFClassLibrary.nfproj" -t:Build -nr:False -p:Configuration=$(Configuration) -p:NF_MDP_MSBUILDTASK_PATH="$(ProjectDir)..\MetadataProcessor.MsBuildTask\bin\$(Configuration)\net472" -p:MDP_UNIT_TESTS_BUILD=1 /m "$(MSBuildBinPath)\msbuild" "$(ProjectDir)TestNFApp\TestNFApp.nfproj" -t:Build -nr:False -p:Configuration=$(Configuration) -p:NF_MDP_MSBUILDTASK_PATH="$(ProjectDir)..\MetadataProcessor.MsBuildTask\bin\$(Configuration)\net472" "$(MSBuildBinPath)\msbuild" "$(ProjectDir)StubsGenerationTestNFApp\StubsGenerationTestNFApp.nfproj" -t:Build -nr:False -p:Configuration=$(Configuration) -p:NF_MDP_MSBUILDTASK_PATH="$(ProjectDir)..\MetadataProcessor.MsBuildTask\bin\$(Configuration)\net472" mkdir "$(TargetDir)\TestNFApp" diff --git a/MetadataProcessor.Tests/MsbuildTask/MsbuildTaskTests.cs b/MetadataProcessor.Tests/MsbuildTask/MsbuildTaskTests.cs index 72806204..ab56b27d 100644 --- a/MetadataProcessor.Tests/MsbuildTask/MsbuildTaskTests.cs +++ b/MetadataProcessor.Tests/MsbuildTask/MsbuildTaskTests.cs @@ -1,18 +1,12 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Mono.Cecil; -using nanoFramework.Tools.MetadataProcessor.Core; using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Mono.Cecil; +using nanoFramework.Tools.MetadataProcessor.Core; namespace nanoFramework.Tools.MetadataProcessor.Tests.MsbuildTask { @@ -111,10 +105,7 @@ private void ProcessAssembly( } // output PDBX - using (var writer = XmlWriter.Create(Path.ChangeExtension(fileToCompile, "pdbx"))) - { - _assemblyBuilder.Write(writer); - } + _assemblyBuilder.Write(Path.ChangeExtension(fileToCompile, "pdbx")); // output assembly metadata dumpFile = Path.ChangeExtension(fileToCompile, "dump.txt"); diff --git a/MetadataProcessor.Tests/Properties/AssemblyInfo.cs b/MetadataProcessor.Tests/Properties/AssemblyInfo.cs index d22763be..ea925b68 100644 --- a/MetadataProcessor.Tests/Properties/AssemblyInfo.cs +++ b/MetadataProcessor.Tests/Properties/AssemblyInfo.cs @@ -1,5 +1,7 @@ -using System.Reflection; -using System.Runtime.CompilerServices; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; using System.Runtime.InteropServices; [assembly: AssemblyTitle("nanoFramework.MetadataProcessor.Tests")] diff --git a/MetadataProcessor.Tests/StubsGenerationTestNFApp/NativeMethodGeneration.cs b/MetadataProcessor.Tests/StubsGenerationTestNFApp/NativeMethodGeneration.cs index 137c281c..c49c1e0a 100644 --- a/MetadataProcessor.Tests/StubsGenerationTestNFApp/NativeMethodGeneration.cs +++ b/MetadataProcessor.Tests/StubsGenerationTestNFApp/NativeMethodGeneration.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; diff --git a/MetadataProcessor.Tests/StubsGenerationTestNFApp/Program.cs b/MetadataProcessor.Tests/StubsGenerationTestNFApp/Program.cs index def10b41..9216110f 100644 --- a/MetadataProcessor.Tests/StubsGenerationTestNFApp/Program.cs +++ b/MetadataProcessor.Tests/StubsGenerationTestNFApp/Program.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System.Threading; diff --git a/MetadataProcessor.Tests/StubsGenerationTestNFApp/Properties/AssemblyInfo.cs b/MetadataProcessor.Tests/StubsGenerationTestNFApp/Properties/AssemblyInfo.cs index 14a6d733..122dcb38 100644 --- a/MetadataProcessor.Tests/StubsGenerationTestNFApp/Properties/AssemblyInfo.cs +++ b/MetadataProcessor.Tests/StubsGenerationTestNFApp/Properties/AssemblyInfo.cs @@ -1,5 +1,7 @@ -using System.Reflection; -using System.Runtime.CompilerServices; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/MetadataProcessor.Tests/TestNFApp/AuthorAttribute.cs b/MetadataProcessor.Tests/TestNFApp/AuthorAttribute.cs index ee239bc5..a77e9175 100644 --- a/MetadataProcessor.Tests/TestNFApp/AuthorAttribute.cs +++ b/MetadataProcessor.Tests/TestNFApp/AuthorAttribute.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; diff --git a/MetadataProcessor.Tests/TestNFApp/ClassWithNullAttribs.cs b/MetadataProcessor.Tests/TestNFApp/ClassWithNullAttribs.cs index b7502371..d8a723dc 100644 --- a/MetadataProcessor.Tests/TestNFApp/ClassWithNullAttribs.cs +++ b/MetadataProcessor.Tests/TestNFApp/ClassWithNullAttribs.cs @@ -1,4 +1,7 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; using System.Diagnostics.CodeAnalysis; namespace TestNFApp diff --git a/MetadataProcessor.Tests/TestNFApp/ComplexAttribute.cs b/MetadataProcessor.Tests/TestNFApp/ComplexAttribute.cs index 36e582ee..8aab6ee6 100644 --- a/MetadataProcessor.Tests/TestNFApp/ComplexAttribute.cs +++ b/MetadataProcessor.Tests/TestNFApp/ComplexAttribute.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; @@ -13,7 +11,7 @@ public class ComplexAttribute : Attribute private readonly string _s; private readonly bool _b; - public uint Max => _max; + public uint Max => _max; public string S => _s; public bool B => _b; diff --git a/MetadataProcessor.Tests/TestNFApp/DataRowAttribute.cs b/MetadataProcessor.Tests/TestNFApp/DataRowAttribute.cs index 732aa4ba..8a3ed032 100644 --- a/MetadataProcessor.Tests/TestNFApp/DataRowAttribute.cs +++ b/MetadataProcessor.Tests/TestNFApp/DataRowAttribute.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; diff --git a/MetadataProcessor.Tests/TestNFApp/DummyCustomAttribute1.cs b/MetadataProcessor.Tests/TestNFApp/DummyCustomAttribute1.cs index 13c503c6..99b2d174 100644 --- a/MetadataProcessor.Tests/TestNFApp/DummyCustomAttribute1.cs +++ b/MetadataProcessor.Tests/TestNFApp/DummyCustomAttribute1.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; diff --git a/MetadataProcessor.Tests/TestNFApp/DummyCustomAttribute2.cs b/MetadataProcessor.Tests/TestNFApp/DummyCustomAttribute2.cs index 87d194cf..7a2db31d 100644 --- a/MetadataProcessor.Tests/TestNFApp/DummyCustomAttribute2.cs +++ b/MetadataProcessor.Tests/TestNFApp/DummyCustomAttribute2.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; diff --git a/MetadataProcessor.Tests/TestNFApp/GenericClass.cs b/MetadataProcessor.Tests/TestNFApp/GenericClass.cs new file mode 100644 index 00000000..c7ddd462 --- /dev/null +++ b/MetadataProcessor.Tests/TestNFApp/GenericClass.cs @@ -0,0 +1,235 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace TestNFApp +{ + interface IDo + { + void Do1(); + void Do2(); + } + + interface IDoThat + { + void DoThat1(); + void DoThat2(); + } + + class ClassDoThis : IDo + { + public void Do1() + { + Debug.WriteLine($"{nameof(Do1)}"); + } + + public void Do2() + { + Debug.WriteLine($"{nameof(Do2)}"); + } + + public void DoThis1() + { + Debug.WriteLine($"{nameof(DoThis1)}"); + } + + public void DoThis2() + { + Debug.WriteLine($"{nameof(DoThis2)}"); + } + } + + class ClassDoInt : IDo + { + public void Do1() + { + Debug.WriteLine($"{nameof(Do1)}"); + } + + public void Do2() + { + Debug.WriteLine($"{nameof(Do2)}"); + } + } + + class ClassDoThatInt : IDo, IDoThat + { + public void Do1() + { + Debug.WriteLine($"{nameof(Do1)}"); + } + + public void Do2() + { + Debug.WriteLine($"{nameof(Do2)}"); + } + + public void DoThat1() + { + Debug.WriteLine($"{nameof(DoThat1)}"); + } + + public void DoThat2() + { + Debug.WriteLine($"{nameof(DoThat2)}"); + } + + } + + class ClassDoThisAndThat : ClassDoThis, IDoThat + { + public void DoThat1() + { + Debug.WriteLine($"{nameof(DoThat1)}"); + } + + public void DoThat2() + { + Debug.WriteLine($"{nameof(DoThat2)}"); + } + } + + public class ClassDoString : IDo + { + public void Do1() + { + Debug.WriteLine($"{nameof(Do1)}"); + } + + public void Do2() + { + Debug.WriteLine($"{nameof(Do2)}"); + } + } + + class GenericClass + { + public int NativeField; + + public T GenericField; + + public void NoGenerics() + { + int v = 1; + } + + public void InstanceGenericDoOne(T t) + { + T v = t; + + Debug.WriteLine($"{nameof(InstanceGenericDoOne)} --> {v} is <{v.GetType()}>"); + } + + public void InstanceGenericDoTwo(T p1, T2 p2) + { + T v1 = p1; + T2 v2 = p2; + + Debug.WriteLine($"{nameof(InstanceGenericDoTwo)}<{v2.GetType()}> --> {v1},{v2} is <{v1.GetType()},{v2.GetType()}>"); + } + + public void InstanceGenericDoOneOther(T1 t) + { + T1 v1 = t; + + Debug.WriteLine($"{nameof(InstanceGenericDoOneOther)}<{v1.GetType()}> --> {v1} is <{v1.GetType()}>"); + } + } + + class AnotherGenericClass + { + public int NativeField; + + public T GenericField; + public T1 AnotherGenericField; + + public void InstanceGenericDoOne(T t) + { + T v = t; + + Debug.WriteLine($"{nameof(InstanceGenericDoOne)} --> {v} is <{typeof(T).FullName}>"); + } + + public void InstanceGenericDoTwo(T p1, T1 p2, T2 p3) + { + T v1 = p1; + T1 v2 = p2; + T2 v3 = p3; + + Debug.WriteLine($"{nameof(InstanceGenericDoTwo)}<{v3.GetType()}> --> {v1},{v2},{v3} is <{v1.GetType()},{v2.GetType()},{v3.GetType()}>"); + } + + public void InstanceGenericDoOneOther(T1 p1, T2 p2) + { + T1 v1 = p1; + T2 v2 = p2; + + Debug.WriteLine($"{nameof(InstanceGenericDoOneOther)}<{v1.GetType()}> --> {v1},{v2} is <{typeof(T1).FullName},{typeof(T2).FullName}>"); + } + } + + public class GenericClassTests + { + private static void StaticGenericDo(T1 val, T2 val2) where T1 : IDo where T2 : IDo + { + Debug.WriteLine($">> {nameof(StaticGenericDo)}<{val.GetType()},{val2.GetType()}>"); + + val.Do1(); + val.Do2(); + val2.Do1(); + val2.Do2(); + } + + private static void StaticGenericDoThisAndThat(T1 val, T2 val2) where T1 : ClassDoThis, IDo where T2 : ClassDoThatInt + { + Debug.WriteLine($">> {nameof(StaticGenericDoThisAndThat)}<{val.GetType()},{val2.GetType()}>"); + + val.DoThis1(); + val.DoThis2(); + val2.DoThat1(); + val2.DoThat2(); + } + + public GenericClassTests() + { + Debug.WriteLine("++++++++++++++++++++"); + Debug.WriteLine("++ Generics Tests ++"); + Debug.WriteLine("++++++++++++++++++++"); + Debug.WriteLine(""); + + + var other = new ClassDoString(); + other.Do1(); + other.Do2(); + + var gc1 = new GenericClass(); + gc1.NoGenerics(); + gc1.InstanceGenericDoOne(1); + gc1.InstanceGenericDoTwo(1, "TWO"); + gc1.InstanceGenericDoOneOther(false); + gc1.GenericField = 10; + + var agc1 = new AnotherGenericClass(); + agc1.InstanceGenericDoOne(22); + agc1.InstanceGenericDoTwo(33, false, "NINE"); + agc1.InstanceGenericDoOneOther(true, 44); + agc1.GenericField = 11; + agc1.AnotherGenericField = false; + + var gc2 = new GenericClass(); + gc2.InstanceGenericDoOne("ONE"); + gc2.InstanceGenericDoTwo("ONE", "TWO"); + gc2.InstanceGenericDoOneOther(33.33); + gc2.GenericField = "TEN"; + + StaticGenericDo(new ClassDoInt(), new ClassDoString()); + + StaticGenericDo(new ClassDoString(), new ClassDoInt()); + + StaticGenericDoThisAndThat(new ClassDoThis(), new ClassDoThatInt()); + + StaticGenericDoThisAndThat(new ClassDoThisAndThat(), new ClassDoThatInt()); + } + } +} diff --git a/MetadataProcessor.Tests/TestNFApp/IOneClassOverAll.cs b/MetadataProcessor.Tests/TestNFApp/IOneClassOverAll.cs index a98a434e..77978300 100644 --- a/MetadataProcessor.Tests/TestNFApp/IOneClassOverAll.cs +++ b/MetadataProcessor.Tests/TestNFApp/IOneClassOverAll.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace TestNFApp { diff --git a/MetadataProcessor.Tests/TestNFApp/IgnoreAttribute.cs b/MetadataProcessor.Tests/TestNFApp/IgnoreAttribute.cs index 80c8a647..5d665022 100644 --- a/MetadataProcessor.Tests/TestNFApp/IgnoreAttribute.cs +++ b/MetadataProcessor.Tests/TestNFApp/IgnoreAttribute.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; diff --git a/MetadataProcessor.Tests/TestNFApp/MaxAttribute.cs b/MetadataProcessor.Tests/TestNFApp/MaxAttribute.cs index fa7c230c..5c50389c 100644 --- a/MetadataProcessor.Tests/TestNFApp/MaxAttribute.cs +++ b/MetadataProcessor.Tests/TestNFApp/MaxAttribute.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; @@ -11,7 +9,7 @@ public class MaxAttribute : Attribute { private readonly uint _max; - public uint Max => _max; + public uint Max => _max; public MaxAttribute(uint m) { diff --git a/MetadataProcessor.Tests/TestNFApp/MyAttribute.cs b/MetadataProcessor.Tests/TestNFApp/MyAttribute.cs index dc4aa410..0069eec8 100644 --- a/MetadataProcessor.Tests/TestNFApp/MyAttribute.cs +++ b/MetadataProcessor.Tests/TestNFApp/MyAttribute.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; diff --git a/MetadataProcessor.Tests/TestNFApp/MyClass1.cs b/MetadataProcessor.Tests/TestNFApp/MyClass1.cs index 2e905909..388cdab0 100644 --- a/MetadataProcessor.Tests/TestNFApp/MyClass1.cs +++ b/MetadataProcessor.Tests/TestNFApp/MyClass1.cs @@ -1,17 +1,19 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using TestNFClassLibrary; namespace TestNFApp { // Define a class that has the custom attribute associated with one of its members. [Attribute2] [Attribute4] + [Attribute1OnAnotherAssembly] public class MyClass1 { [Attribute1] [Attribute3] + [Attribute2OnAnotherAssembly] public void MyMethod1(int i) { return; diff --git a/MetadataProcessor.Tests/TestNFApp/OneClassOverAll.cs b/MetadataProcessor.Tests/TestNFApp/OneClassOverAll.cs index 227ca6b1..d348e77e 100644 --- a/MetadataProcessor.Tests/TestNFApp/OneClassOverAll.cs +++ b/MetadataProcessor.Tests/TestNFApp/OneClassOverAll.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; @@ -64,7 +62,7 @@ public void DummyMethodWithUglyParams(ref int p5, byte[] p6, OneClassOverAll p7, public int UglyAdd(int left, int right) { int ret = 0; - + try { ret = left + right; diff --git a/MetadataProcessor.Tests/TestNFApp/Program.cs b/MetadataProcessor.Tests/TestNFApp/Program.cs index f512a956..a135f8e9 100644 --- a/MetadataProcessor.Tests/TestNFApp/Program.cs +++ b/MetadataProcessor.Tests/TestNFApp/Program.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics; @@ -17,7 +15,13 @@ public static void Main() { Console.WriteLine("Starting TestNFApp"); - //////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// + // referenced class + Debug.WriteLine("++++++++++++++++++++++++++++"); + Debug.WriteLine("++ Referenced class tests ++"); + Debug.WriteLine("++++++++++++++++++++++++++++"); + Debug.WriteLine(""); + // instantiating a class on another assembly ClassOnAnotherAssembly anotherClass = new ClassOnAnotherAssembly(); @@ -34,7 +38,7 @@ public static void Main() ////////////////////////////// // accessing property on class - dummyMirror1 = anotherClass.DummyProperty; + _ = anotherClass.DummyProperty; Console.WriteLine($"Accessed property on class: {dummyMirror1}"); @@ -73,6 +77,10 @@ public static void Main() break; } + /////////////////////////////////////////////////////////////////// + // Generics Tests + _ = new GenericClassTests(); + // null attributes tests Console.WriteLine("Null attributes tests"); _ = new ClassWithNullAttribs(); @@ -80,10 +88,21 @@ public static void Main() Console.WriteLine("Exiting TestNFApp"); } + private static void MiscelaneousTests() + { + var type = typeof(short[]); + if (type.FullName != "System.Int16[]") + { + throw new Exception($"Type name is wrong. Got '{type.FullName}' should be System.Int16[]"); + } + } + public static void ReflectionTests() { - Console.WriteLine(""); - Console.WriteLine("+++Starting ReflectionTests"); + Debug.WriteLine("++++++++++++++++++++++"); + Debug.WriteLine("++ Reflection tests ++"); + Debug.WriteLine("++++++++++++++++++++++"); + Debug.WriteLine(""); // Get the type of MyClass1. Type myType = typeof(MyClass1); @@ -107,17 +126,17 @@ public static void ReflectionTests() // Get the methods associated with MyClass1. MemberInfo[] myMethods = myType.GetMethods(); - - //Console.WriteLine(""); - //Console.WriteLine($"'{myType.Name}' type has '{myMethods.Length}' methods"); + + Debug.WriteLine(""); + Debug.WriteLine($"'{myType.Name}' type has '{myMethods.Length}' methods"); // Display the attributes for each of the methods of MyClass1. for (int i = 0; i < myMethods.Length; i++) { string methodName = myMethods[i].Name; - //Console.WriteLine(""); - //Console.WriteLine($"Getting custom attributes for '{methodName}'"); + Debug.WriteLine(""); + Debug.WriteLine($"Getting custom attributes for '{methodName}'"); myAttributes = myMethods[i].GetCustomAttributes(true); @@ -184,12 +203,12 @@ public static void ReflectionTests() Console.WriteLine($"MaxAttribute value is: 0x{attMax.Max.ToString("X8")}"); AuthorAttribute attAuthor = (AuthorAttribute)myFieldAttributes[1]; - Console.WriteLine(""); - Console.WriteLine($"AuthorAttribute value is: '{attAuthor.Author}'"); + Debug.WriteLine(""); + Debug.WriteLine($"AuthorAttribute value is: '{attAuthor.Author}'"); - Console.WriteLine(""); - Console.WriteLine("+++ReflectionTests completed"); - Console.WriteLine(""); + Debug.WriteLine(""); + Debug.WriteLine("+++ReflectionTests completed"); + Debug.WriteLine(""); } } } diff --git a/MetadataProcessor.Tests/TestNFApp/Properties/AssemblyInfo.cs b/MetadataProcessor.Tests/TestNFApp/Properties/AssemblyInfo.cs index 0a617ec9..47fa9106 100644 --- a/MetadataProcessor.Tests/TestNFApp/Properties/AssemblyInfo.cs +++ b/MetadataProcessor.Tests/TestNFApp/Properties/AssemblyInfo.cs @@ -1,5 +1,7 @@ -using System.Reflection; -using System.Runtime.CompilerServices; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/MetadataProcessor.Tests/TestNFApp/TestEnumInAnotherAssembly.cs b/MetadataProcessor.Tests/TestNFApp/TestEnumInAnotherAssembly.cs index 1f1fc49e..ca65ae18 100644 --- a/MetadataProcessor.Tests/TestNFApp/TestEnumInAnotherAssembly.cs +++ b/MetadataProcessor.Tests/TestNFApp/TestEnumInAnotherAssembly.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace System.IO { @@ -10,11 +8,23 @@ public class TestEnumInAnotherAssembly public void CallTestEnumInAnotherAssembly() { // This test checks if MDP can minimize the assembly using an enum that is defined in another assembly - // and the class calling it is in a different assembly BUT in the same namespace. - var ioException = new IOException( + // as a nested type + IOException.IOExceptionErrorCode dummyEnum = IOException.IOExceptionErrorCode.DirectoryNotFound; + + _ = new IOException( string.Empty, - (int)IOException.IOExceptionErrorCode.DirectoryNotFound); + (int)dummyEnum); + + // This test checks if MDP can minimize the assembly using an enum that is defined in another assembly + Base64FormattingOptions formattingOptions = Base64FormattingOptions.InsertLineBreaks; + + byte[] testBytes = new byte[] { 0x01, 0x03, 0x05, 0x07, 0x09 }; + + _ = Convert.ToBase64String( + testBytes, + 0, + testBytes.Length, + formattingOptions); } } - } diff --git a/MetadataProcessor.Tests/TestNFApp/TestNFApp.nfproj b/MetadataProcessor.Tests/TestNFApp/TestNFApp.nfproj index 6d66b685..10f82e28 100644 --- a/MetadataProcessor.Tests/TestNFApp/TestNFApp.nfproj +++ b/MetadataProcessor.Tests/TestNFApp/TestNFApp.nfproj @@ -30,6 +30,7 @@ + diff --git a/MetadataProcessor.Tests/TestNFApp/TestingDelegates.cs b/MetadataProcessor.Tests/TestNFApp/TestingDelegates.cs index 8f432977..f7848ea0 100644 --- a/MetadataProcessor.Tests/TestNFApp/TestingDelegates.cs +++ b/MetadataProcessor.Tests/TestNFApp/TestingDelegates.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; diff --git a/MetadataProcessor.Tests/TestNFApp/TestingDestructors.cs b/MetadataProcessor.Tests/TestNFApp/TestingDestructors.cs index dd34d0d5..37a9b3e2 100644 --- a/MetadataProcessor.Tests/TestNFApp/TestingDestructors.cs +++ b/MetadataProcessor.Tests/TestNFApp/TestingDestructors.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System; @@ -44,7 +42,7 @@ public class DestructorsTestClass { // Calling Destructor for Test Class 3 intI = 2; - + Console.WriteLine("Calling Destructor for Test Class 3"); } @@ -103,7 +101,7 @@ public class DestructorsTestAnotherClass : DestructorsTestAnotherClassBase public static bool TestMethod() { DestructorsTestAnotherClass mc = new DestructorsTestAnotherClass(); - + mc = null; // should be calling GC @@ -111,15 +109,15 @@ public static bool TestMethod() int sleepTime = 5000; int slept = 0; - + while (intI != 8 && slept < sleepTime) { System.Threading.Thread.Sleep(10); slept += 10; } - + Console.WriteLine($"Thread has slept for {slept}"); - + if (intI == 8) { return true; diff --git a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/AttributesOnAnotherAssembly.cs b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/AttributesOnAnotherAssembly.cs new file mode 100644 index 00000000..36f816a1 --- /dev/null +++ b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/AttributesOnAnotherAssembly.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace TestNFClassLibrary +{ + [AttributeUsage(AttributeTargets.All)] + public class Attribute1OnAnotherAssemblyAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.All)] + public class Attribute2OnAnotherAssemblyAttribute : Attribute + { + } +} diff --git a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/ClassOnAnotherAssembly.cs b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/ClassOnAnotherAssembly.cs index b2eec0ef..9d040b09 100644 --- a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/ClassOnAnotherAssembly.cs +++ b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/ClassOnAnotherAssembly.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace TestNFClassLibrary { diff --git a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/ClassWithNativeImplementation.cs b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/ClassWithNativeImplementation.cs index 5a0311de..3977c24c 100644 --- a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/ClassWithNativeImplementation.cs +++ b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/ClassWithNativeImplementation.cs @@ -1,12 +1,14 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// this class should be added only for unit tests in MDP +#if MDP_UNIT_TESTS_BUILD using System.Runtime.CompilerServices; namespace TestNFClassLibrary { + public class ClassWithNativeImplementation { private static int _staticField; @@ -33,3 +35,5 @@ public void ManagedMethod2() public static extern void NativeMethod2(); } } + +#endif diff --git a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmAClassWithAnEnum.cs b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmAClassWithAnEnum.cs index 4a45c107..936b155e 100644 --- a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmAClassWithAnEnum.cs +++ b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmAClassWithAnEnum.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace TestNFClassLibrary { diff --git a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmATypeToExclude.cs b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmATypeToExclude.cs index ac9e7e71..61663044 100644 --- a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmATypeToExclude.cs +++ b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmATypeToExclude.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. namespace TestNFClassLibrary { diff --git a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmAlsoATypeToExclude.cs b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmAlsoATypeToExclude.cs index 0d9ec2cc..b32a648e 100644 --- a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmAlsoATypeToExclude.cs +++ b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmAlsoATypeToExclude.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; diff --git a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmAnEnumToExclude.cs b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmAnEnumToExclude.cs index 00da52f4..947fa2c9 100644 --- a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmAnEnumToExclude.cs +++ b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/IAmAnEnumToExclude.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; diff --git a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/Properties/AssemblyInfo.cs b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/Properties/AssemblyInfo.cs index 0a0b1cd5..98cef7e3 100644 --- a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/Properties/AssemblyInfo.cs +++ b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/Properties/AssemblyInfo.cs @@ -1,10 +1,7 @@ -// -// Copyright (c) .NET Foundation and Contributors -// See LICENSE file in the project root for full license information. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -36,9 +33,3 @@ // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("11.22.33.44")] [assembly: AssemblyFileVersion("11.22.33.44")] - -///////////////////////////////////////////////////////////////// -// This attribute is mandatory when building Interop libraries // -// update this whenever the native assembly signature changes // -[assembly: AssemblyNativeVersion("0.0.0.0")] -///////////////////////////////////////////////////////////////// diff --git a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/TestNFClassLibrary.nfproj b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/TestNFClassLibrary.nfproj index 7ddd2bd5..3966ae0e 100644 --- a/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/TestNFClassLibrary.nfproj +++ b/MetadataProcessor.Tests/TestNFClassLibrary/TestNFClassLibrary/TestNFClassLibrary.nfproj @@ -18,6 +18,7 @@ + diff --git a/MetadataProcessor.Tests/TestObjectHelper.cs b/MetadataProcessor.Tests/TestObjectHelper.cs index e2301fd6..1c66ff16 100644 --- a/MetadataProcessor.Tests/TestObjectHelper.cs +++ b/MetadataProcessor.Tests/TestObjectHelper.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection; +using System.Runtime.CompilerServices; using System.Text; using Mono.Cecil; @@ -15,7 +15,7 @@ namespace nanoFramework.Tools.MetadataProcessor.Tests { public static class TestObjectHelper { - private const string _varNameForLocalNanoCLRInstancePath = "MDP_TEST_NANOCLR_INSTANCE_PATH"; + private const string _varNameForLocalNanoCLRInstancePath = "NF_MDP_NANOCLR_INSTANCE_PATH"; private static string _testExecutionLocation; private static string _testNFAppLocation; @@ -29,7 +29,7 @@ public static nanoTablesContext GetTestNFAppNanoTablesContext() { nanoTablesContext ret = null; - var assemblyDefinition = GetTestNFAppAssemblyDefinition(); + var assemblyDefinition = GetTestNFAppAssemblyDefinitionWithLoadHints(); ret = new nanoTablesContext( assemblyDefinition, @@ -65,7 +65,7 @@ public static string TestExecutionLocation { if (string.IsNullOrEmpty(_testExecutionLocation)) { - _testExecutionLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + _testExecutionLocation = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); if (_testExecutionLocation.Contains("Debug")) { @@ -214,7 +214,9 @@ public static AssemblyDefinition GetTestNFAppAssemblyDefinition() { AssemblyDefinition ret = null; - ret = AssemblyDefinition.ReadAssembly(TestNFAppFullPath); + ret = AssemblyDefinition.ReadAssembly( + TestNFAppFullPath, + new ReaderParameters { AssemblyResolver = ProvideLoadHints() }); return ret; } @@ -237,7 +239,9 @@ public static AssemblyDefinition GetTestNFClassLibraryDefinition() { AssemblyDefinition ret = null; - ret = AssemblyDefinition.ReadAssembly(TestNFClassLibFullPath); + ret = AssemblyDefinition.ReadAssembly( + TestNFClassLibFullPath, + new ReaderParameters { AssemblyResolver = ProvideLoadHints() }); return ret; } @@ -358,7 +362,7 @@ public static Stream GetResourceStream(string resourceName) Stream ret = null; - var thisAssembly = Assembly.GetExecutingAssembly(); + var thisAssembly = System.Reflection.Assembly.GetExecutingAssembly(); ret = thisAssembly.GetManifestResourceStream(String.Concat(thisAssembly.GetName().Name, ".", resourceName)); @@ -485,6 +489,14 @@ internal static MethodDefinition GetMethodDefinition( // no need to check if path exists as this validation is performed by nanoclr public static string NanoClrLocalInstance => Environment.GetEnvironmentVariable( _varNameForLocalNanoCLRInstancePath, - EnvironmentVariableTarget.User); + EnvironmentVariableTarget.Process); + + private static DefaultAssemblyResolver ProvideLoadHints() + { + var resolver = new DefaultAssemblyResolver(); + resolver.AddSearchDirectory(TestExecutionLocation); + + return resolver; + } } } diff --git a/MetadataProcessor.Tests/TestPreprocessedFiles.cs b/MetadataProcessor.Tests/TestPreprocessedFiles.cs index ef0a3814..8c037e0d 100644 --- a/MetadataProcessor.Tests/TestPreprocessedFiles.cs +++ b/MetadataProcessor.Tests/TestPreprocessedFiles.cs @@ -1,11 +1,5 @@ -//using System; -//using System.Collections.Generic; -//using System.IO; -//using System.Linq; -//using System.Xml; -//using System.Xml.Xsl; -//using Microsoft.VisualStudio.TestTools.UnitTesting; -//using Mono.Cecil; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. //namespace nanoFramework.Tools.MetadataProcessor.Tests //{ @@ -498,7 +492,7 @@ // "Microsoft.SPOT.Native", "Microsoft.SPOT.TinyCore", "Microsoft.SPOT.Hardware.Usb", // "Microsoft.SPOT.Hardware"); // } - + // [TestMethod] // public void WeakDelegatesTest() // { diff --git a/MetadataProcessor.Tests/mscorlib b/MetadataProcessor.Tests/mscorlib index 981cb43f..6abe4b8f 160000 --- a/MetadataProcessor.Tests/mscorlib +++ b/MetadataProcessor.Tests/mscorlib @@ -1 +1 @@ -Subproject commit 981cb43f79461cf719b3dc718ab636c51abb26e1 +Subproject commit 6abe4b8f267ecf8c57cbc06be3ae113dc943ba78 diff --git a/README.md b/README.md index 046ea956..a265424e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![#yourfirstpr](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](https://github.com/nanoframework/Home/blob/main/CONTRIBUTING.md) [![Build Status](https://dev.azure.com/nanoframework/metadata-processor/_apis/build/status/nanoframework.metadata-processor?branchName=develop)](https://dev.azure.com/nanoframework/metadata-processor/_build/latest?definitionId=43&branchName=develop) [![Discord](https://img.shields.io/discord/478725473862549535.svg)](https://discord.gg/gCyBu8T) +[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![#yourfirstpr](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](https://github.com/nanoframework/Home/blob/main/CONTRIBUTING.md) [![Build Status](https://dev.azure.com/nanoframework/metadata-processor/_apis/build/status/nanoframework.metadata-processor?branchName=develop)](https://dev.azure.com/nanoframework/metadata-processor/_build/latest?definitionId=43&branchName=develop) [![Discord](https://img.shields.io/discord/478725473862549535.svg)](https://discord.gg/gCyBu8T) ![nanoFramework logo](https://raw.githubusercontent.com/nanoframework/Home/main/resources/logo/nanoFramework-repo-logo.png) @@ -43,6 +43,17 @@ When adding a project to the solution the following points have to be kept in mi 1. This flag disables "nodeReuse", this is needed as a custom MsBuildTask is used which also gets rebuilt. "NodeReuse" keeps instances of MsBuild running which interferes with the rebuilding of the custom MsBuildTask. +### Code sync between MDP, native code and other tools + +There are several code snippets, structures and details that are shared between the metadata processor, the native code and other tools. These need to be kept in sync. +For those that need to be keep in sync with native code, there is a tag `` in a comment before the relevant code snippet. +For sync with Visual Studio extension, the tag `` is used. +For sync with the debugger, the tag `` is used. + +### Miscellaneous + +If there is a need to override the nanoCLR DLL to be used in the virtual device set the environment variable `NF_MDP_NANOCLR_INSTANCE_PATH` to the path of the DLL. + ## Feedback and documentation For documentation, providing feedback, issues and finding out how to contribute please refer to the [Home repo](https://github.com/nanoframework/Home). diff --git a/azure-pipelines-templates/check-nf-interpreter-to-test.yml b/azure-pipelines-templates/check-nf-interpreter-to-test.yml new file mode 100644 index 00000000..eb8e3fcb --- /dev/null +++ b/azure-pipelines-templates/check-nf-interpreter-to-test.yml @@ -0,0 +1,74 @@ +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. + +steps: + - task: PowerShell@2 + displayName: Check nf-interpreter to test + condition: ne(variables['System.PullRequest.PullRequestNumber'], '') + inputs: + failOnStderr: false + targetType: "inline" + script: | + + # compute authorization header in format "AUTHORIZATION: basic 'encoded token'" + # 'encoded token' is the Base64 of the string "nfbot:personal-token" + $auth = "basic $([System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("nfbot:$(GitHubToken)")))" + + # find PR + "Getting PR #$env:System_PullRequest_PullRequestNumber details..." | Write-Host -ForegroundColor White -NoNewline + $pr = Invoke-WebRequest "https://api.github.com/repos/$env:Build_Repository_Name/pulls/$env:System_PullRequest_PullRequestNumber" | ConvertFrom-Json + + if($($pr.number) -eq "$env:System_PullRequest_PullRequestNumber") + { + 'OK' | Write-Host -ForegroundColor Green + } + + # grab PR commit message + $prCommitMessage = $($pr.body) + + # look for test prompt in PR commit message + # pattern is "[tested against nanoclr buildId NNN]" + + if($prCommitMessage -match "\[tested against nanoclr buildId (\d+)\]") + { + $buildId = $matches[1] + "AZDO build ID found: $buildId" | Write-Host -ForegroundColor White + + echo "##vso[task.setvariable variable=NFINTERPRETER_BUILDID]$buildId" + } + else + { + "No build ID found" | Write-Host -ForegroundColor Red + } + env: + GITHUB_TOKEN: $(GitHubToken) + + - task: DownloadPipelineArtifact@2 + condition: >- + and( + eq(variables['DownloadNanoClrPreview'], true), + ne(variables['NFINTERPRETER_BUILDID'], '') + ) + displayName: Download nanoCLR preview + inputs: + buildType: specific + project: 'nf-interpreter' + definition: '34' + buildVersionToDownload: specific + allowFailedBuilds: true + pipelineId: $(NFINTERPRETER_BUILDID) + artifactName: 'nanoclr_cli' + targetPath: '$(Pipeline.Workspace)/nanoclr' + + - task: PowerShell@2 + condition: >- + and( + succeeded(), + eq(variables['DownloadNanoClrPreview'], true), + ne(variables['NFINTERPRETER_BUILDID'], '') + ) + displayName: Set nanoCLR preview path + inputs: + targetType: 'inline' + script: | + Write-Host "##vso[task.setvariable variable=NF_MDP_NANOCLR_INSTANCE_PATH]$(Pipeline.Workspace)/nanoclr/nanoFramework.nanoCLR.dll" diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 56cb76dd..05686fd2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -49,7 +49,7 @@ variables: jobs: ############################## -- job: Get_Build_Flags +- job: Build_Prep pool: vmImage: 'windows-latest' @@ -63,10 +63,36 @@ jobs: # default to false $update = $false + $downloadPreview = $false - if($env:Build_Reason -eq 'PullRequest') + if($env:System_PullRequest_PullRequestNumber -ne $null) { - # PR build, nothing interesting in commit message + # PR build + # compute authorization header in format "AUTHORIZATION: basic 'encoded token'" + # 'encoded token' is the Base64 of the string "nfbot:personal-token" + $auth = "basic $([System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("nfbot:$(GitHubToken)")))" + + # find PR + "Getting PR #$env:System_PullRequest_PullRequestNumber details..." | Write-Host -ForegroundColor White -NoNewline + $pr = Invoke-WebRequest "https://api.github.com/repos/$env:Build_Repository_Name/pulls/$env:System_PullRequest_PullRequestNumber" | ConvertFrom-Json + + if($($pr.number) -eq "$env:System_PullRequest_PullRequestNumber") + { + 'OK' | Write-Host -ForegroundColor Green + } + + # grab PR commit message + $prCommitMessage = $($pr.body) + + # debug output + # echo "=====`r`n$($prCommitMessage)`r`n=====" + + # check if should download nanoCLR to run unit tests + if($prCommitMessage -match "\[tested against nanoclr buildId (\d+)\]") + { + Write-Host "##[command] **Download preview nanoCLR for unit tests**" + $downloadPreview = $true + } } else { @@ -103,10 +129,11 @@ jobs: } } - # set variable to foward to jobs + # set variables to forward to jobs echo "##vso[task.setvariable variable=RUN_UPDATE_DEPENDENTS;isOutput=true]$update" + echo "##vso[task.setvariable variable=DOWNLOAD_PREVIEW_NANOCLR;isOutput=true]$downloadPreview" name: GetPRLabels - displayName: Check build labels + displayName: Check build conditions ############################## # build MDP @@ -118,7 +145,7 @@ jobs: ) dependsOn: - - Get_Build_Flags + - Build_Prep pool: vmImage: 'windows-latest' @@ -133,6 +160,8 @@ jobs: value: 'nanoFramework.Tools.MetadataProcessor.sln' - name: NF_MDP_MSBUILDTASK_PATH value: '$(System.DefaultWorkingDirectory)/MetadataProcessor.MsBuildTask/bin/Release/net472' + - name: DownloadNanoClrPreview + value: $[ dependencies.Build_Prep.outputs['GetPRLabels.DOWNLOAD_PREVIEW_NANOCLR'] ] steps: @@ -151,7 +180,7 @@ jobs: git config --global user.name "nfbot" displayName: Setup git identity - - template: azure-pipelines-templates/install-nuget.yml@templates + - template: azure-pipelines-templates/install-nuget.yml@templates - task: InstallNanoMSBuildComponents@1 condition: ne( variables['StartReleaseCandidate'], true ) @@ -159,13 +188,15 @@ jobs: env: GITHUB_TOKEN: $(GitHubToken) + - template: azure-pipelines-templates/check-nf-interpreter-to-test.yml + - task: NuGetCommand@2 displayName: NuGet restore inputs: restoreSolution: '$(solution)' feedsToUse: config nugetConfigPath: 'NuGet.config' - + - task: VSBuild@1 inputs: solution: '$(solution)' @@ -188,7 +219,11 @@ jobs: versionSelector: latestStable - task: VSTest@2 - condition: succeeded() + condition: >- + and( + succeeded(), + ne(variables['System.PullRequest.PullRequestNumber'], '') + ) displayName: 'Running tests' inputs: testSelector: 'testAssemblies' @@ -205,7 +240,7 @@ jobs: configuration: '$(BuildConfiguration)' diagnosticsEnabled: true vsTestVersion: toolsInstaller - codeCoverageEnabled: true + codeCoverageEnabled: true - task: CopyFiles@1 condition: failed() @@ -252,15 +287,15 @@ jobs: sourceFolder: $(Build.SourcesDirectory) Contents: | **\bin\Release\nanoFramework.Tools.MetaDataProcessor.exe - **\bin\Release\nanoFramework.Tools.MetadataProcessor.MsBuildTask.dll + **\bin\Release\net472\nanoFramework.Tools.MetadataProcessor.MsBuildTask.dll TargetFolder: '$(Build.ArtifactStagingDirectory)' flattenFolders: true - # set cloud build vars again as they've been overriten by the tests run + # set cloud build vars again as they've been overwritten by the tests run - script: nbgv cloud -a -c condition: succeeded() displayName: Set build number - + - task: PowerShell@2 condition: succeeded() displayName: Save cloud build number @@ -292,7 +327,7 @@ jobs: command: custom custom: tool arguments: install --tool-path . sign --version 0.9.1-beta.24170.3 - + - pwsh: | .\sign code azure-key-vault ` "**/*.nupkg" ` @@ -312,7 +347,7 @@ jobs: succeeded(), eq(variables['System.PullRequest.PullRequestId'], '') ) - + # publish artifacts (only possible if this is not a PR originated on a fork) - task: PublishPipelineArtifact@1 displayName: Publish deployables artifacts @@ -371,11 +406,12 @@ jobs: condition: >- or( startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), - eq(variables['UPDATE_DEPENDENTS'], 'true') + eq(variables['UPDATE_DEPENDENTS'], 'true'), + eq(dependencies.Build_Prep.outputs['GetPRLabels.RUN_UPDATE_DEPENDENTS'], 'true') ) dependsOn: - - Get_Build_Flags + - Build_Prep - Build_MDP pool: @@ -388,7 +424,7 @@ jobs: # update dependents # use this to make sure nuget package is published - - template: azure-pipelines-templates/update-dependents.yml@templates + - template: azure-pipelines-templates/update-dependents.yml@templates parameters: packageName: '$(nugetPackageName)' repositoriesToUpdate: @@ -418,7 +454,7 @@ jobs: fetchDepth: 1 # step from template @ nf-tools repo - - template: azure-pipelines-templates/discord-webhook.yml@templates + - template: azure-pipelines-templates/discord-webhook.yml@templates parameters: status: 'failure' webhookUrl: '$(DiscordWebhook)' diff --git a/nanoFramework.Tools.MetadataProcessor.sln b/nanoFramework.Tools.MetadataProcessor.sln index 9cee60c5..4c3afb9e 100644 --- a/nanoFramework.Tools.MetadataProcessor.sln +++ b/nanoFramework.Tools.MetadataProcessor.sln @@ -10,6 +10,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BFDB4F1F-D22B-4BDE-AA52-AD2EA3EDBBFF}" ProjectSection(SolutionItems) = preProject NuGet.Config = NuGet.Config + README.md = README.md version.json = version.json EndProjectSection EndProject diff --git a/version.json b/version.json index 75430b42..f536ade2 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "3.0", + "version": "4.0-preview.{height}", "release": { "branchName" : "release-v{version}", "versionIncrement" : "build",