Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Commit

Permalink
Use full class constructor runner
Browse files Browse the repository at this point in the history
Fixes #288.
  • Loading branch information
MichalStrehovsky committed Feb 20, 2016
1 parent 73337fb commit 00fcf1a
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ protected override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bo
else
{
// We need to trigger the cctor before returning the base
// TODO: Inline the fast path ("class constructor already ran, nothing to do")
encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeCctorContextSymbol(target));
encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.TypeNonGCStaticsSymbol(target));
encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase));
Expand All @@ -111,6 +112,7 @@ protected override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bo
else
{
// We need to trigger the cctor before returning the base
// TODO: Inline the fast path ("class constructor already ran, nothing to do")
encoder.EmitLEAQ(encoder.TargetRegister.Arg0, factory.TypeCctorContextSymbol(target));
encoder.EmitLEAQ(encoder.TargetRegister.Arg1, factory.TypeGCStaticsSymbol(target));
AddrMode loadFromRdx = new AddrMode(encoder.TargetRegister.Arg1, null, 0, 0, AddrModeSize.Int64);
Expand Down
4 changes: 3 additions & 1 deletion src/ILCompiler.Compiler/src/Compiler/TypeInitialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
public static unsafe void* CheckStaticClassConstruction(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(void* returnValue, StaticClassConstructionContext* pContext)

public static unsafe void EnsureClassConstructorRun(StaticClassConstructionContext* pContext)
{
IntPtr pfnCctor = pContext->cctorMethodAddress;
NoisyLog("EnsureClassConstructorRun, cctor={0}, thread={1}", pfnCctor, CurrentManagedThreadId);
Expand All @@ -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);
Expand Down Expand Up @@ -109,8 +127,6 @@ internal static partial class ClassConstructorRunner
Cctor.Release(cctor);
}
NoisyLog("EnsureClassConstructorRun complete, cctor={0}, thread={1}", pfnCctor, CurrentManagedThreadId);

return returnValue;
}

//=========================================================================================================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static void RunClassConstructor(RuntimeTypeHandle type)
return;
unsafe
{
ClassConstructorRunner.EnsureClassConstructorRun(null, (StaticClassConstructionContext*)pStaticClassConstructionContext);
ClassConstructorRunner.EnsureClassConstructorRun((StaticClassConstructionContext*)pStaticClassConstructionContext);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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).
Expand Down

0 comments on commit 00fcf1a

Please sign in to comment.