Skip to content

Commit

Permalink
Move getFieldInfo to CorInfoImpl.ReadyToRun (#32159)
Browse files Browse the repository at this point in the history
  • Loading branch information
trylek committed Feb 12, 2020
1 parent 659aec4 commit 8c10a98
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 215 deletions.
215 changes: 0 additions & 215 deletions src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2061,221 +2061,6 @@ private CORINFO_FIELD_ACCESSOR getFieldIntrinsic(FieldDesc field)
return (CORINFO_FIELD_ACCESSOR)(-1);
}

private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult)
{
#if DEBUG
// In debug, write some bogus data to the struct to ensure we have filled everything
// properly.
MemoryHelper.FillMemory((byte*)pResult, 0xcc, Marshal.SizeOf<CORINFO_FIELD_INFO>());
#endif

Debug.Assert(((int)flags & ((int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_GET |
(int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_SET |
(int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_ADDRESS |
(int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_INIT_ARRAY)) != 0);

var field = HandleToObject(pResolvedToken.hField);
#if READYTORUN
MethodDesc callerMethod = HandleToObject(callerHandle);

if (field.Offset.IsIndeterminate)
throw new RequiresRuntimeJitException(field);
#endif

CORINFO_FIELD_ACCESSOR fieldAccessor;
CORINFO_FIELD_FLAGS fieldFlags = (CORINFO_FIELD_FLAGS)0;
uint fieldOffset = (field.IsStatic && field.HasRva ? 0xBAADF00D : (uint)field.Offset.AsInt);

if (field.IsStatic)
{
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_STATIC;

#if READYTORUN
if (field.FieldType.IsValueType && field.HasGCStaticBase && !field.HasRva)
{
// statics of struct types are stored as implicitly boxed in CoreCLR i.e.
// we need to modify field access flags appropriately
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_STATIC_IN_HEAP;
}
#endif

if (field.HasRva)
{
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_UNMANAGED;

// TODO: Handle the case when the RVA is in the TLS range
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_RVA_ADDRESS;

// We are not going through a helper. The constructor has to be triggered explicitly.
#if READYTORUN
if (!IsClassPreInited(field.OwningType))
#else
if (_compilation.HasLazyStaticConstructor(field.OwningType))
#endif
{
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_INITCLASS;
}
}
else if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
// The JIT wants to know how to access a static field on a generic type. We need a runtime lookup.
#if READYTORUN
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER;
if (field.IsThreadStatic)
{
pResult->helper = (field.HasGCStaticBase ?
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE);
}
else
{
pResult->helper = (field.HasGCStaticBase ?
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE);
}
#else
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_READYTORUN_HELPER;
pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE;

// Don't try to compute the runtime lookup if we're inlining. The JIT is going to abort the inlining
// attempt anyway.
MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext);
if (contextMethod == MethodBeingCompiled)
{
FieldDesc runtimeDeterminedField = (FieldDesc)GetRuntimeDeterminedObjectForToken(ref pResolvedToken);

ReadyToRunHelperId helperId;

// Find out what kind of base do we need to look up.
if (field.IsThreadStatic)
{
helperId = ReadyToRunHelperId.GetThreadStaticBase;
}
else if (field.HasGCStaticBase)
{
helperId = ReadyToRunHelperId.GetGCStaticBase;
}
else
{
helperId = ReadyToRunHelperId.GetNonGCStaticBase;
}

// What generic context do we look up the base from.
ISymbolNode helper;
if (contextMethod.AcquiresInstMethodTableFromThis() || contextMethod.RequiresInstMethodTableArg())
{
helper = _compilation.NodeFactory.ReadyToRunHelperFromTypeLookup(
helperId, runtimeDeterminedField.OwningType, contextMethod.OwningType);
}
else
{
Debug.Assert(contextMethod.RequiresInstMethodDescArg());
helper = _compilation.NodeFactory.ReadyToRunHelperFromDictionaryLookup(
helperId, runtimeDeterminedField.OwningType, contextMethod);
}

pResult->fieldLookup = CreateConstLookupToSymbol(helper);
}
#endif // READYTORUN
}
else
{
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE;

ReadyToRunHelperId helperId = ReadyToRunHelperId.Invalid;
CORINFO_FIELD_ACCESSOR intrinsicAccessor;
if (field.IsIntrinsic &&
(flags & CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_GET) != 0 &&
(intrinsicAccessor = getFieldIntrinsic(field)) != (CORINFO_FIELD_ACCESSOR)(-1))
{
fieldAccessor = intrinsicAccessor;
}
else if (field.IsThreadStatic)
{
#if READYTORUN
if (field.HasGCStaticBase)
{
helperId = ReadyToRunHelperId.GetThreadStaticBase;
}
else
{
helperId = ReadyToRunHelperId.GetThreadNonGcStaticBase;
}
#else
helperId = ReadyToRunHelperId.GetThreadStaticBase;
#endif
}
else
{
helperId = field.HasGCStaticBase ?
ReadyToRunHelperId.GetGCStaticBase :
ReadyToRunHelperId.GetNonGCStaticBase;

//
// Currently, we only do this optimization for regular statics, but it
// looks like it may be permissible to do this optimization for
// thread statics as well.
//
if ((flags & CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_ADDRESS) != 0 &&
(fieldAccessor != CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_TLS))
{
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_SAFESTATIC_BYREF_RETURN;
}
}

#if READYTORUN
if (!_compilation.NodeFactory.CompilationModuleGroup.VersionsWithType(field.OwningType) &&
fieldAccessor == CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER)
{
PreventRecursiveFieldInlinesOutsideVersionBubble(field, callerMethod);

// Static fields outside of the version bubble need to be accessed using the ENCODE_FIELD_ADDRESS
// helper in accordance with ZapInfo::getFieldInfo in CoreCLR.
pResult->fieldLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.FieldAddress(field));

pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE;

fieldFlags &= ~CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_STATIC_IN_HEAP; // The dynamic helper takes care of the unboxing
fieldOffset = 0;
}
else
#endif

if (helperId != ReadyToRunHelperId.Invalid)
{
pResult->fieldLookup = CreateConstLookupToSymbol(
#if READYTORUN
_compilation.SymbolNodeFactory.CreateReadyToRunHelper(helperId, field.OwningType)
#else
_compilation.NodeFactory.ReadyToRunHelper(helperId, field.OwningType)
#endif
);
}
}
}
else
{
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INSTANCE;
}

if (field.IsInitOnly)
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_FINAL;

pResult->fieldAccessor = fieldAccessor;
pResult->fieldFlags = fieldFlags;
pResult->fieldType = getFieldType(pResolvedToken.hField, &pResult->structType, pResolvedToken.hClass);
pResult->accessAllowed = CorInfoIsAccessAllowedResult.CORINFO_ACCESS_ALLOWED;
pResult->offset = fieldOffset;

#if READYTORUN
EncodeFieldBaseOffset(field, pResult, callerMethod);
#endif

// TODO: We need to implement access checks for fields and methods. See JitInterface.cpp in mrtjit
// and STS::AccessCheck::CanAccess.
}

private bool isFieldStatic(CORINFO_FIELD_STRUCT_* fldHnd)
{
return HandleToObject(fldHnd).IsStatic;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,155 @@ private bool IsGenericTooDeeplyNested(Instantiation instantiation)
return IsGenericTooDeeplyNested(instantiation, 0);
}

private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult)
{
#if DEBUG
// In debug, write some bogus data to the struct to ensure we have filled everything
// properly.
MemoryHelper.FillMemory((byte*)pResult, 0xcc, Marshal.SizeOf<CORINFO_FIELD_INFO>());
#endif

Debug.Assert(((int)flags & ((int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_GET |
(int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_SET |
(int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_ADDRESS |
(int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_INIT_ARRAY)) != 0);

var field = HandleToObject(pResolvedToken.hField);
MethodDesc callerMethod = HandleToObject(callerHandle);

if (field.Offset.IsIndeterminate)
throw new RequiresRuntimeJitException(field);

CORINFO_FIELD_ACCESSOR fieldAccessor;
CORINFO_FIELD_FLAGS fieldFlags = (CORINFO_FIELD_FLAGS)0;
uint fieldOffset = (field.IsStatic && field.HasRva ? 0xBAADF00D : (uint)field.Offset.AsInt);

if (field.IsStatic)
{
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_STATIC;

if (field.FieldType.IsValueType && field.HasGCStaticBase && !field.HasRva)
{
// statics of struct types are stored as implicitly boxed in CoreCLR i.e.
// we need to modify field access flags appropriately
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_STATIC_IN_HEAP;
}

if (field.HasRva)
{
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_UNMANAGED;

// TODO: Handle the case when the RVA is in the TLS range
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_RVA_ADDRESS;

// We are not going through a helper. The constructor has to be triggered explicitly.
if (!IsClassPreInited(field.OwningType))
{
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_INITCLASS;
}
}
else if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
// The JIT wants to know how to access a static field on a generic type. We need a runtime lookup.
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER;
if (field.IsThreadStatic)
{
pResult->helper = (field.HasGCStaticBase ?
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE :
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE);
}
else
{
pResult->helper = (field.HasGCStaticBase ?
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCSTATIC_BASE :
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE);
}
}
else
{
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE;

ReadyToRunHelperId helperId = ReadyToRunHelperId.Invalid;
CORINFO_FIELD_ACCESSOR intrinsicAccessor;
if (field.IsIntrinsic &&
(flags & CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_GET) != 0 &&
(intrinsicAccessor = getFieldIntrinsic(field)) != (CORINFO_FIELD_ACCESSOR)(-1))
{
fieldAccessor = intrinsicAccessor;
}
else if (field.IsThreadStatic)
{
if (field.HasGCStaticBase)
{
helperId = ReadyToRunHelperId.GetThreadStaticBase;
}
else
{
helperId = ReadyToRunHelperId.GetThreadNonGcStaticBase;
}
}
else
{
helperId = field.HasGCStaticBase ?
ReadyToRunHelperId.GetGCStaticBase :
ReadyToRunHelperId.GetNonGCStaticBase;

//
// Currently, we only do this optimization for regular statics, but it
// looks like it may be permissible to do this optimization for
// thread statics as well.
//
if ((flags & CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_ADDRESS) != 0 &&
(fieldAccessor != CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_TLS))
{
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_SAFESTATIC_BYREF_RETURN;
}
}

if (!_compilation.NodeFactory.CompilationModuleGroup.VersionsWithType(field.OwningType) &&
fieldAccessor == CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER)
{
PreventRecursiveFieldInlinesOutsideVersionBubble(field, callerMethod);

// Static fields outside of the version bubble need to be accessed using the ENCODE_FIELD_ADDRESS
// helper in accordance with ZapInfo::getFieldInfo in CoreCLR.
pResult->fieldLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.FieldAddress(field));

pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE;

fieldFlags &= ~CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_STATIC_IN_HEAP; // The dynamic helper takes care of the unboxing
fieldOffset = 0;
}
else
if (helperId != ReadyToRunHelperId.Invalid)
{
pResult->fieldLookup = CreateConstLookupToSymbol(
_compilation.SymbolNodeFactory.CreateReadyToRunHelper(helperId, field.OwningType)
);
}
}
}
else
{
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INSTANCE;
}

if (field.IsInitOnly)
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_FINAL;

pResult->fieldAccessor = fieldAccessor;
pResult->fieldFlags = fieldFlags;
pResult->fieldType = getFieldType(pResolvedToken.hField, &pResult->structType, pResolvedToken.hClass);
pResult->accessAllowed = CorInfoIsAccessAllowedResult.CORINFO_ACCESS_ALLOWED;
pResult->offset = fieldOffset;

EncodeFieldBaseOffset(field, pResult, callerMethod);

// TODO: We need to implement access checks for fields and methods. See JitInterface.cpp in mrtjit
// and STS::AccessCheck::CanAccess.
}

private void ceeInfoGetCallInfo(
ref CORINFO_RESOLVED_TOKEN pResolvedToken,
CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
Expand Down

0 comments on commit 8c10a98

Please sign in to comment.