From 7b0dcef1ebe306f8163277ed04f3891e5e789ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Sat, 20 Feb 2016 12:13:48 +0100 Subject: [PATCH] Use full class constructor runner Fixes #288. --- .../DependencyAnalysis/NodeFactory.cs | 4 +-- .../src/Compiler/TypeInitialization.cs | 4 ++- .../Runtime/Augments/RuntimeAugments.cs | 2 +- .../ClassConstructorRunner.cs | 26 +++++++++++++++---- .../CompilerServices/RuntimeHelpers.cs | 2 +- .../StaticClassConstructionContext.cs | 23 +--------------- 6 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs index 493bc17d81c..9f7e3569e2e 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs @@ -326,8 +326,8 @@ public ISymbolNode MethodEntrypoint(MethodDesc method) } private static readonly string[][] s_helperEntrypointNames = new string[][] { - new string[] { "System.Runtime.CompilerServices", "CctorHelper", "CheckStaticClassConstructionReturnGCStaticBase" }, - new string[] { "System.Runtime.CompilerServices", "CctorHelper", "CheckStaticClassConstructionReturnNonGCStaticBase" } + new string[] { "System.Runtime.CompilerServices", "ClassConstructorRunner", "CheckStaticClassConstructionReturnGCStaticBase" }, + new string[] { "System.Runtime.CompilerServices", "ClassConstructorRunner", "CheckStaticClassConstructionReturnNonGCStaticBase" } }; private ISymbolNode[] _helperEntrypointSymbols; diff --git a/src/ILCompiler.Compiler/src/Compiler/TypeInitialization.cs b/src/ILCompiler.Compiler/src/Compiler/TypeInitialization.cs index 80dbfd7ae2d..552bf452fb5 100644 --- a/src/ILCompiler.Compiler/src/Compiler/TypeInitialization.cs +++ b/src/ILCompiler.Compiler/src/Compiler/TypeInitialization.cs @@ -37,7 +37,9 @@ public bool HasEagerStaticConstructor(TypeDesc type) private static bool HasEagerConstructorAttribute(TypeDesc type) { MetadataType mdType = type as MetadataType; - return mdType != null && mdType.HasCustomAttribute("System.Runtime.CompilerServices", "EagerOrderedStaticConstructorAttribute"); + return mdType != null && ( + mdType.HasCustomAttribute("System.Runtime.CompilerServices", "EagerOrderedStaticConstructorAttribute") + || mdType.HasCustomAttribute("System.Runtime.CompilerServices", "EagerStaticClassConstructionAttribute")); } } } diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs index f0a7926ef85..188bf7b3a1f 100644 --- a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs +++ b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs @@ -308,7 +308,7 @@ public static object CallDynamicInvokeMethod(object thisPtr, IntPtr methodToCall public unsafe static void EnsureClassConstructorRun(IntPtr staticClassConstructionContext) { StaticClassConstructionContext* context = (StaticClassConstructionContext*)staticClassConstructionContext; - ClassConstructorRunner.EnsureClassConstructorRun(null, context); + ClassConstructorRunner.EnsureClassConstructorRun(context); } public static bool GetMdArrayRankTypeHandleIfSupported(int rank, out RuntimeTypeHandle mdArrayTypeHandle) diff --git a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs index 436d2030b5b..79974fcb76c 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs @@ -30,10 +30,28 @@ internal static partial class ClassConstructorRunner // // No attempt is made to detect or break deadlocks due to other synchronization mechanisms. //============================================================================================================== -#if !CORERT // CORERT-TODO: Use full cctor helper +#if !CORERT [RuntimeExport("CheckStaticClassConstruction")] -#endif public static unsafe void* EnsureClassConstructorRun(void* returnValue, StaticClassConstructionContext* pContext) + { + EnsureClassConstructorRun(pContext); + return returnValue; + } +#else + private unsafe static object CheckStaticClassConstructionReturnGCStaticBase(StaticClassConstructionContext* context, object gcStaticBase) + { + EnsureClassConstructorRun(context); + return gcStaticBase; + } + + private unsafe static IntPtr CheckStaticClassConstructionReturnNonGCStaticBase(StaticClassConstructionContext* context, IntPtr nonGcStaticBase) + { + EnsureClassConstructorRun(context); + return nonGcStaticBase; + } +#endif + + public static unsafe void EnsureClassConstructorRun(StaticClassConstructionContext* pContext) { IntPtr pfnCctor = pContext->cctorMethodAddress; NoisyLog("EnsureClassConstructorRun, cctor={0}, thread={1}", pfnCctor, CurrentManagedThreadId); @@ -43,7 +61,7 @@ internal static partial class ClassConstructorRunner if (pContext->initialized == 1) { NoisyLog("Cctor already run, cctor={0}, thread={1}", pfnCctor, CurrentManagedThreadId); - return returnValue; + return; } CctorHandle cctor = Cctor.GetCctor(pContext); @@ -109,8 +127,6 @@ internal static partial class ClassConstructorRunner Cctor.Release(cctor); } NoisyLog("EnsureClassConstructorRun complete, cctor={0}, thread={1}", pfnCctor, CurrentManagedThreadId); - - return returnValue; } //========================================================================================================= diff --git a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index d8a1d122fdd..39e196b8ef6 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -34,7 +34,7 @@ public static void RunClassConstructor(RuntimeTypeHandle type) return; unsafe { - ClassConstructorRunner.EnsureClassConstructorRun(null, (StaticClassConstructionContext*)pStaticClassConstructionContext); + ClassConstructorRunner.EnsureClassConstructorRun((StaticClassConstructionContext*)pStaticClassConstructionContext); } } diff --git a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticClassConstructionContext.cs b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticClassConstructionContext.cs index 6c7b4ca7c8e..0c4a1315da1 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticClassConstructionContext.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticClassConstructionContext.cs @@ -29,8 +29,7 @@ public struct StaticClassConstructionContext public volatile int initialized; } -#if CORERT - // CORERT-TODO: Use full cctor helper instead +#if false [McgIntrinsics] internal sealed class CctorHelper { @@ -101,26 +100,6 @@ private static unsafe void CheckStaticClassConstruction(ref StaticClassConstruct } } - private static object CheckStaticClassConstructionReturnGCStaticBase(ref StaticClassConstructionContext context, object gcStaticBase) - { - // CORERT-TODO: Early out if initializer was set to anything. The runner doesn't handle recursion and assumes it's access from - // a different thread and deadlocks itself. CoreRT will cause recursion for things like trying to get a static - // base from the CCtor (which means that pretty much all cctors will deadlock). - if (context.initialized == 0) - CheckStaticClassConstruction(ref context); - return gcStaticBase; - } - - private static IntPtr CheckStaticClassConstructionReturnNonGCStaticBase(ref StaticClassConstructionContext context, IntPtr nonGcStaticBase) - { - // CORERT-TODO: Early out if initializer was set to anything. The runner doesn't handle recursion and assumes it's access from - // a different thread and deadlocks itself. CoreRT will cause recursion for things like trying to get a static - // base from the CCtor (which means that pretty much all cctors will deadlock). - if (context.initialized == 0) - CheckStaticClassConstruction(ref context); - return nonGcStaticBase; - } - // Intrinsic to call the cctor given a pointer to the code (this method's body is ignored and replaced // with a calli during compilation). The transform doesn't handle non-generic versions yet (i.e. // functions that are void).