From 8355e3520747132db426db6699149d0cb3b7cddd Mon Sep 17 00:00:00 2001 From: dotnet-bot Date: Thu, 6 Sep 2018 16:46:49 -0700 Subject: ProjectX: Toc exports for runtime import methods Certain runtime import methods should also be exported as a toc entry of the shared library though they are really implemented by native code. The methods are those imported directly from the native code in their own module where the native code is not exported natively through a def/lib file. Below is an example. [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport("*", "RhGetCurrentThunkContext")] internal static extern IntPtr GetCurrentInteropThunkContext(); The issue was exposed by Changeset 1712615 which avoids linking against the native code when compiling an app in multifile mode The changeset is incomplete. The native code is not exported from the shared library in neither way, i.e., in the managed way via toc files, or in the native way via lib files. I'm following the ProjectN way to export those native methods in the managed way. Changes include: 1. Allow exporting certain runtime import methods via Toc files when building the shared library 2. Allow importing those runtime import methods when building an app in multifile mode 3. Expose the CompilationModuleGroup.ImportsMethod API to handle imported methods from MRT but referenced via the shared assembly [tfs-changeset: 1713379] --- .../src/Compiler/CompilationModuleGroup.cs | 4 ++++ .../DependencyAnalysis/RuntimeImportMethodNode.cs | 17 ++++++++++++++++- .../Compiler/DependencyAnalysis/UtcNodeFactory.cs | 17 +++++++++++++---- .../src/Compiler/MethodExtensions.cs | 20 ++++++++++++++++++++ .../src/Compiler/MultiFileCompilationModuleGroup.cs | 5 +++++ .../src/Compiler/SingleFileCompilationModuleGroup.cs | 5 +++++ .../Compiler/SingleMethodCompilationModuleGroup.cs | 5 +++++ 7 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/ILCompiler.Compiler/src/Compiler/CompilationModuleGroup.cs b/src/ILCompiler.Compiler/src/Compiler/CompilationModuleGroup.cs index 92354badb..edc9b076a 100644 --- a/src/ILCompiler.Compiler/src/Compiler/CompilationModuleGroup.cs +++ b/src/ILCompiler.Compiler/src/Compiler/CompilationModuleGroup.cs @@ -38,6 +38,10 @@ namespace ILCompiler /// public abstract bool ContainsMethodDictionary(MethodDesc method); /// + /// If true, "method" is imported from the set of reference assemblies + /// + public abstract bool ImportsMethod(MethodDesc method, bool unboxingStub); + /// /// If true, "type" is exported by the set of input assemblies being compiled /// public abstract ExportForm GetExportTypeForm(TypeDesc type); diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/RuntimeImportMethodNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/RuntimeImportMethodNode.cs index ac7adb740..796ffce38 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/RuntimeImportMethodNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/RuntimeImportMethodNode.cs @@ -10,7 +10,7 @@ namespace ILCompiler.DependencyAnalysis /// /// Represents a method that is imported from the runtime library. /// - public class RuntimeImportMethodNode : ExternSymbolNode, IMethodNode + public class RuntimeImportMethodNode : ExternSymbolNode, IMethodNode, IExportableSymbolNode { private MethodDesc _method; @@ -28,6 +28,21 @@ namespace ILCompiler.DependencyAnalysis } } + public ExportForm GetExportForm(NodeFactory factory) + { + // Force non-fake exports for RuntimeImportMethods that have '*' as their module. ('*' means the method is + // REALLY a reference to the linked in native code) + if (((EcmaMethod)_method).GetRuntimeImportDllName() == "*") + { + ExportForm exportForm = factory.CompilationModuleGroup.GetExportMethodForm(_method, false); + if (exportForm == ExportForm.ByName) + return ExportForm.None; // Method symbols exported by name are naturally handled by the linker + return exportForm; + } + + return ExportForm.None; + } + public override int ClassCode => -1173492615; public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/UtcNodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/UtcNodeFactory.cs index 5a026e34a..80aec11b0 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/UtcNodeFactory.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/UtcNodeFactory.cs @@ -237,12 +237,21 @@ namespace ILCompiler { if (method.HasCustomAttribute("System.Runtime", "RuntimeImportAttribute")) { - return new RuntimeImportMethodNode(method); + RuntimeImportMethodNode runtimeImportMethod = new RuntimeImportMethodNode(method); + + // If the method is imported from either the current module or the runtime, reference it directly + if (CompilationModuleGroup.ContainsMethodBody(method, false)) + return runtimeImportMethod; + // If the method is imported from the runtime but not a managed assembly, reference it directly + else if (!CompilationModuleGroup.ImportsMethod(method, false)) + return runtimeImportMethod; + + // If the method is imported from a managed assembly, reference it via an import cell } - - if (CompilationModuleGroup.ContainsMethodBody(method, false)) + else { - return NonExternMethodSymbol(method, false); + if (CompilationModuleGroup.ContainsMethodBody(method, false)) + return NonExternMethodSymbol(method, false); } return _importedNodeProvider.ImportedMethodCodeNode(this, method, false); diff --git a/src/ILCompiler.Compiler/src/Compiler/MethodExtensions.cs b/src/ILCompiler.Compiler/src/Compiler/MethodExtensions.cs index 4b72c15d8..fd274af78 100644 --- a/src/ILCompiler.Compiler/src/Compiler/MethodExtensions.cs +++ b/src/ILCompiler.Compiler/src/Compiler/MethodExtensions.cs @@ -30,6 +30,26 @@ namespace ILCompiler return null; } + public static string GetRuntimeImportDllName(this EcmaMethod This) + { + var decoded = This.GetDecodedCustomAttribute("System.Runtime", "RuntimeImportAttribute"); + if (decoded == null) + return null; + + var decodedValue = decoded.Value; + + if (decodedValue.FixedArguments.Length == 2) + return (string)decodedValue.FixedArguments[0].Value; + + foreach (var argument in decodedValue.NamedArguments) + { + if (argument.Name == "DllName") + return (string)argument.Value; + } + + return null; + } + public static string GetRuntimeExportName(this EcmaMethod This) { var decoded = This.GetDecodedCustomAttribute("System.Runtime", "RuntimeExportAttribute"); diff --git a/src/ILCompiler.Compiler/src/Compiler/MultiFileCompilationModuleGroup.cs b/src/ILCompiler.Compiler/src/Compiler/MultiFileCompilationModuleGroup.cs index 5afac3563..842ddefad 100644 --- a/src/ILCompiler.Compiler/src/Compiler/MultiFileCompilationModuleGroup.cs +++ b/src/ILCompiler.Compiler/src/Compiler/MultiFileCompilationModuleGroup.cs @@ -58,6 +58,11 @@ namespace ILCompiler return ContainsMethodBody(method, false); } + public sealed override bool ImportsMethod(MethodDesc method, bool unboxingStub) + { + return false; + } + public sealed override ExportForm GetExportTypeForm(TypeDesc type) { return ExportForm.None; diff --git a/src/ILCompiler.Compiler/src/Compiler/SingleFileCompilationModuleGroup.cs b/src/ILCompiler.Compiler/src/Compiler/SingleFileCompilationModuleGroup.cs index a305ad026..90a0043be 100644 --- a/src/ILCompiler.Compiler/src/Compiler/SingleFileCompilationModuleGroup.cs +++ b/src/ILCompiler.Compiler/src/Compiler/SingleFileCompilationModuleGroup.cs @@ -31,6 +31,11 @@ namespace ILCompiler return ContainsMethodBody(method, false); } + public override bool ImportsMethod(MethodDesc method, bool unboxingStub) + { + return false; + } + public override ExportForm GetExportTypeForm(TypeDesc type) { return ExportForm.None; diff --git a/src/ILCompiler.Compiler/src/Compiler/SingleMethodCompilationModuleGroup.cs b/src/ILCompiler.Compiler/src/Compiler/SingleMethodCompilationModuleGroup.cs index 9f734c1e0..9a1435217 100644 --- a/src/ILCompiler.Compiler/src/Compiler/SingleMethodCompilationModuleGroup.cs +++ b/src/ILCompiler.Compiler/src/Compiler/SingleMethodCompilationModuleGroup.cs @@ -50,6 +50,11 @@ namespace ILCompiler return false; } + public override bool ImportsMethod(MethodDesc method, bool unboxingStub) + { + return false; + } + public override ExportForm GetExportTypeForm(TypeDesc type) { return ExportForm.None; -- cgit v1.2.3 From 878be8e120fba51f1a1f4d49b83aff6a1c4e0c79 Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Fri, 7 Sep 2018 16:52:42 -0700 Subject: ToPointerFix - VS debugger needs the ToPointer() methods to inspect a pointer, marking it as DependencyReductionRoot to make sure it is not optimized away. [tfs-changeset: 1713493] --- src/System.Private.CoreLib/shared/System/IntPtr.cs | 3 +++ src/System.Private.CoreLib/shared/System/UIntPtr.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/System.Private.CoreLib/shared/System/IntPtr.cs b/src/System.Private.CoreLib/shared/System/IntPtr.cs index f79334a96..d23742fa7 100644 --- a/src/System.Private.CoreLib/shared/System/IntPtr.cs +++ b/src/System.Private.CoreLib/shared/System/IntPtr.cs @@ -217,6 +217,9 @@ namespace System [CLSCompliant(false)] [Intrinsic] [NonVersionable] +#if PROJECTN + [System.Runtime.CompilerServices.DependencyReductionRootAttribute] +#endif public unsafe void* ToPointer() { return _value; diff --git a/src/System.Private.CoreLib/shared/System/UIntPtr.cs b/src/System.Private.CoreLib/shared/System/UIntPtr.cs index 9534f4f87..c57dd86a7 100644 --- a/src/System.Private.CoreLib/shared/System/UIntPtr.cs +++ b/src/System.Private.CoreLib/shared/System/UIntPtr.cs @@ -208,6 +208,9 @@ namespace System [Intrinsic] [NonVersionable] +#if PROJECTN + [System.Runtime.CompilerServices.DependencyReductionRootAttribute] +#endif public unsafe void* ToPointer() { return _value; -- cgit v1.2.3