Skip to content

Commit

Permalink
Add support for dynamic static constructors in runtime (dotnet#5011)
Browse files Browse the repository at this point in the history
  • Loading branch information
tonerdo committed Oct 6, 2020
1 parent d77a0eb commit 54d49bc
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ public void InterpretMethod(ref CallInterceptorArgs callInterceptorArgs)
_callInterceptorArgs = callInterceptorArgs;
ILReader reader = new ILReader(_methodIL.GetILBytes());

if (_method.OwningType.HasStaticConstructor && !_method.IsStaticConstructor)
{
// Method's owning type has a static constructor and we're not trying
// to interpret the static constructor itself. Ensure we've run it
IntPtr cctorContext = TypeLoaderEnvironment.TryGetStaticClassConstructionContext(_method.OwningType.GetRuntimeTypeHandle());
if (cctorContext != IntPtr.Zero)
{
RuntimeAugments.EnsureClassConstructorRun(cctorContext);
}
}

while (reader.HasNext)
{
ILOpcode opcode = reader.ReadILOpcode();
Expand Down Expand Up @@ -2882,12 +2893,6 @@ private void InterpretLoadStaticField(FieldDesc field)
nativeFormatField.Handle,
out FieldAccessMetadata fieldAccessMetadata);

IntPtr cctorContext = TypeLoaderEnvironment.TryGetStaticClassConstructionContext(nativeFormatField.OwningType.GetRuntimeTypeHandle());
if (cctorContext != IntPtr.Zero)
{
RuntimeAugments.EnsureClassConstructorRun(cctorContext);
}

FieldTableFlags fieldFlags = fieldAccessMetadata.Flags & FieldTableFlags.StorageClass;
if (fieldFlags == FieldTableFlags.NonGCStatic)
{
Expand Down Expand Up @@ -3070,13 +3075,6 @@ private void InterpretStoreStaticField(FieldDesc field)
nativeFormatField.Handle,
out FieldAccessMetadata fieldAccessMetadata);


IntPtr cctorContext = TypeLoaderEnvironment.TryGetStaticClassConstructionContext(nativeFormatField.OwningType.GetRuntimeTypeHandle());
if (cctorContext != IntPtr.Zero)
{
RuntimeAugments.EnsureClassConstructorRun(cctorContext);
}

FieldTableFlags fieldFlags = fieldAccessMetadata.Flags & FieldTableFlags.StorageClass;
if (fieldFlags == FieldTableFlags.NonGCStatic)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,7 @@ unsafe private void FinishClassConstructor(TypeDesc type, TypeBuilderState state

if (state.TemplateType == null)
{
if (!type.HasInstantiation)
if (!type.HasInstantiation && !type.RuntimeTypeHandle.IsDynamicType())
{
// Non-Generic ReadyToRun types in their current state already have their static field region setup
// with the class constructor initialized.
Expand Down Expand Up @@ -1336,8 +1336,6 @@ private void FinishRuntimeType(TypeDesc type)

FinishTypeDictionary(type, state);

FinishClassConstructor(type, state);

// For types that were allocated from universal canonical templates, patch their vtables with
// pointers to calling convention conversion thunks
if (state.TemplateType != null && state.TemplateType.IsCanonicalSubtype(CanonicalFormKind.Universal))
Expand Down Expand Up @@ -1564,7 +1562,14 @@ private void FinishTypeAndMethodBuilding()

for (int i = 0; i < _typesThatNeedTypeHandles.Count; i++)
{
_typesThatNeedTypeHandles[i].SetRuntimeTypeHandleUnsafe(_typesThatNeedTypeHandles[i].GetTypeBuilderState().HalfBakedRuntimeTypeHandle);
var typeThatNeedsTypeHandle = _typesThatNeedTypeHandles[i];
var stateOfTypeThatNeedsTypeHandle = typeThatNeedsTypeHandle.GetTypeBuilderState();

typeThatNeedsTypeHandle.SetRuntimeTypeHandleUnsafe(stateOfTypeThatNeedsTypeHandle.HalfBakedRuntimeTypeHandle);

// Finish class constructor only after assigning the RuntimeTypeHandle, that way,
// the MethodEntrypointLookup entry is constructed with the full type information
FinishClassConstructor(typeThatNeedsTypeHandle, stateOfTypeThatNeedsTypeHandle);

TypeLoaderLogger.WriteLine("Successfully Registered type " + _typesThatNeedTypeHandles[i].ToString() + ".");
}
Expand Down

0 comments on commit 54d49bc

Please sign in to comment.