Skip to content

Commit

Permalink
NativeAOT: avoid helper calls for nongc static fields (#79709)
Browse files Browse the repository at this point in the history
Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
  • Loading branch information
EgorBo and SingleAccretion authored Jan 21, 2023
1 parent 7ae5f77 commit e5dcd3c
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 48 deletions.
3 changes: 1 addition & 2 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1685,7 +1685,7 @@ enum CORINFO_FIELD_ACCESSOR
CORINFO_FIELD_STATIC_ADDR_HELPER, // static field accessed using address-of helper (argument is FieldDesc *)
CORINFO_FIELD_STATIC_TLS, // unmanaged TLS access
CORINFO_FIELD_STATIC_READYTORUN_HELPER, // static field access using a runtime lookup helper

CORINFO_FIELD_STATIC_RELOCATABLE, // static field access using relocation (used in AOT)
CORINFO_FIELD_INTRINSIC_ZERO, // intrinsic zero (IntPtr.Zero, UIntPtr.Zero)
CORINFO_FIELD_INTRINSIC_EMPTY_STRING, // intrinsic emptry string (String.Empty)
CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN, // intrinsic BitConverter.IsLittleEndian
Expand All @@ -1698,7 +1698,6 @@ enum CORINFO_FIELD_FLAGS
CORINFO_FLG_FIELD_UNMANAGED = 0x00000002, // RVA field
CORINFO_FLG_FIELD_FINAL = 0x00000004,
CORINFO_FLG_FIELD_STATIC_IN_HEAP = 0x00000008, // See code:#StaticFields. This static field is in the GC heap as a boxed object
CORINFO_FLG_FIELD_SAFESTATIC_BYREF_RETURN = 0x00000010, // Field can be returned safely (has GC heap lifetime)
CORINFO_FLG_FIELD_INITCLASS = 0x00000020, // initClass has to be called before accessing the field
CORINFO_FLG_FIELD_PROTECTED = 0x00000040,
};
Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/inc/jiteeversionguid.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
#define GUID_DEFINED
#endif // !GUID_DEFINED

constexpr GUID JITEEVersionIdentifier = { /* 9c013880-b9b8-4f91-bea4-d4dd4368ab93 */
0x9c013880,
0xb9b8,
0x4f91,
{0xbe, 0xa4, 0xd4, 0xdd, 0x43, 0x68, 0xab, 0x93}
constexpr GUID JITEEVersionIdentifier = { /* 91a3d851-74df-4be2-a270-432a8fab6955 */
0x91a3d851,
0x74df,
0x4be2,
{0xa2, 0x70, 0x43, 0x2a, 0x8f, 0xab, 0x69, 0x55}
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
18 changes: 18 additions & 0 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4235,6 +4235,22 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT
break;
}

case CORINFO_FIELD_STATIC_RELOCATABLE:
{
#ifdef FEATURE_READYTORUN
assert(pFieldInfo->fieldLookup.accessType == InfoAccessType::IAT_VALUE);
assert(fieldKind == FieldSeq::FieldKind::SimpleStatic);
assert(innerFldSeq != nullptr);

GenTree* baseAddr = gtNewIconHandleNode((size_t)pFieldInfo->fieldLookup.addr, GTF_ICON_STATIC_HDL);
GenTree* offset = gtNewIconNode(pFieldInfo->offset, innerFldSeq);
op1 = gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, offset);
#else
unreached();
#endif // FEATURE_READYTORUN
}
break;

case CORINFO_FIELD_STATIC_READYTORUN_HELPER:
{
#ifdef FEATURE_READYTORUN
Expand Down Expand Up @@ -9260,6 +9276,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
case CORINFO_FIELD_STATIC_RVA_ADDRESS:
case CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER:
case CORINFO_FIELD_STATIC_READYTORUN_HELPER:
case CORINFO_FIELD_STATIC_RELOCATABLE:
op1 = impImportStaticFieldAccess(&resolvedToken, (CORINFO_ACCESS_FLAGS)aflags, &fieldInfo,
lclTyp);
break;
Expand Down Expand Up @@ -9510,6 +9527,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
case CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER:
case CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER:
case CORINFO_FIELD_STATIC_READYTORUN_HELPER:
case CORINFO_FIELD_STATIC_RELOCATABLE:
op1 = impImportStaticFieldAccess(&resolvedToken, (CORINFO_ACCESS_FLAGS)aflags, &fieldInfo,
lclTyp);
break;
Expand Down
43 changes: 27 additions & 16 deletions src/coreclr/jit/valuenum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8536,17 +8536,31 @@ void Compiler::fgValueNumberSsaVarDef(GenTreeLclVarCommon* lcl)
// tree where only one of the constants is expected to have a field sequence.
//
// Arguments:
// vnStore - ValueNumStore object
// tree - tree node to inspect
// pAddress - [Out] resulting address with all offsets combined
// pFseq - [Out] field sequence
// vnStore - ValueNumStore object
// tree - tree node to inspect
// byteOffset - [Out] resulting byte offset
// pFseq - [Out] field sequence
//
// Return Value:
// true if the given tree is a static field address
//
static bool GetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, ssize_t* pAddress, FieldSeq** pFseq)
static bool GetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, ssize_t* byteOffset, FieldSeq** pFseq)
{
ssize_t val = 0;

// Special case for NativeAOT: ADD(ICON_STATIC, CNS_INT) where CNS_INT has field sequence corresponding to field's
// offset
if (tree->OperIs(GT_ADD) && tree->gtGetOp1()->IsIconHandle(GTF_ICON_STATIC_HDL) && tree->gtGetOp2()->IsCnsIntOrI())
{
GenTreeIntCon* cns2 = tree->gtGetOp2()->AsIntCon();
if (cns2->gtFieldSeq != nullptr)
{
*byteOffset = cns2->IconValue() - cns2->gtFieldSeq->GetOffset();
*pFseq = cns2->gtFieldSeq;
return true;
}
}

// Accumulate final offset
while (tree->OperIs(GT_ADD))
{
Expand Down Expand Up @@ -8578,8 +8592,8 @@ static bool GetStaticFieldSeqAndAddress(ValueNumStore* vnStore, GenTree* tree, s
if ((tree->IsCnsIntOrI()) && (tree->AsIntCon()->gtFieldSeq != nullptr) &&
(tree->AsIntCon()->gtFieldSeq->GetKind() == FieldSeq::FieldKind::SimpleStaticKnownAddress))
{
*pFseq = tree->AsIntCon()->gtFieldSeq;
*pAddress = tree->AsIntCon()->IconValue() + val;
*pFseq = tree->AsIntCon()->gtFieldSeq;
*byteOffset = tree->AsIntCon()->IconValue() + val - tree->AsIntCon()->gtFieldSeq->GetOffset();
return true;
}
return false;
Expand Down Expand Up @@ -8608,17 +8622,14 @@ bool Compiler::fgValueNumberConstLoad(GenTreeIndir* tree)
//
// sbyte GetVal() => RVA[1]; // fold to '100'
//
ssize_t address = 0;
FieldSeq* fieldSeq = nullptr;
ssize_t byteOffset = 0;
FieldSeq* fieldSeq = nullptr;
if ((varTypeIsIntegral(tree) || varTypeIsFloating(tree)) &&
GetStaticFieldSeqAndAddress(vnStore, tree->gtGetOp1(), &address, &fieldSeq))
GetStaticFieldSeqAndAddress(vnStore, tree->gtGetOp1(), &byteOffset, &fieldSeq))
{
assert(fieldSeq->GetKind() == FieldSeq::FieldKind::SimpleStaticKnownAddress);
CORINFO_FIELD_HANDLE fieldHandle = fieldSeq->GetFieldHandle();

ssize_t byteOffset = address - fieldSeq->GetOffset();
int size = (int)genTypeSize(tree->TypeGet());
const int maxElementSize = sizeof(int64_t);
CORINFO_FIELD_HANDLE fieldHandle = fieldSeq->GetFieldHandle();
int size = (int)genTypeSize(tree->TypeGet());
const int maxElementSize = sizeof(int64_t);
if ((fieldHandle != nullptr) && (size > 0) && (size <= maxElementSize) && ((size_t)byteOffset < INT_MAX))
{
uint8_t buffer[maxElementSize] = {0};
Expand Down
3 changes: 1 addition & 2 deletions src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1115,7 +1115,7 @@ public enum CORINFO_FIELD_ACCESSOR
CORINFO_FIELD_STATIC_ADDR_HELPER, // static field accessed using address-of helper (argument is FieldDesc *)
CORINFO_FIELD_STATIC_TLS, // unmanaged TLS access
CORINFO_FIELD_STATIC_READYTORUN_HELPER, // static field access using a runtime lookup helper

CORINFO_FIELD_STATIC_RELOCATABLE, // static field access from the data segment
CORINFO_FIELD_INTRINSIC_ZERO, // intrinsic zero (IntPtr.Zero, UIntPtr.Zero)
CORINFO_FIELD_INTRINSIC_EMPTY_STRING, // intrinsic emptry string (String.Empty)
CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN, // intrinsic BitConverter.IsLittleEndian
Expand All @@ -1128,7 +1128,6 @@ public enum CORINFO_FIELD_FLAGS
CORINFO_FLG_FIELD_UNMANAGED = 0x00000002, // RVA field
CORINFO_FLG_FIELD_FINAL = 0x00000004,
CORINFO_FLG_FIELD_STATIC_IN_HEAP = 0x00000008, // See code:#StaticFields. This static field is in the GC heap as a boxed object
CORINFO_FLG_FIELD_SAFESTATIC_BYREF_RETURN = 0x00000010, // Field can be returned safely (has GC heap lifetime)
CORINFO_FLG_FIELD_INITCLASS = 0x00000020, // initClass has to be called before accessing the field
CORINFO_FLG_FIELD_PROTECTED = 0x00000040,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2141,6 +2141,13 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET
pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_THREADSTATIC_BASE;
helperId = ReadyToRunHelperId.GetThreadStaticBase;
}
else if (!_compilation.HasLazyStaticConstructor(field.OwningType) && !field.HasGCStaticBase)
{
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_RELOCATABLE;
ISymbolNode baseAddress = _compilation.NodeFactory.TypeNonGCStaticsSymbol((MetadataType)field.OwningType);
pResult->fieldLookup.accessType = InfoAccessType.IAT_VALUE;
pResult->fieldLookup.addr = (void*)ObjectToHandle(baseAddress);
}
else
{
if (field.HasGCStaticBase)
Expand All @@ -2153,17 +2160,6 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET
pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE;
helperId = 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 (helperId != ReadyToRunHelperId.Invalid)
Expand Down
12 changes: 0 additions & 12 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1576,18 +1576,6 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken,
}
}
}

//
// Currently, we only 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_ADDRESS) &&
!pField->IsThreadStatic() &&
(fieldAccessor != CORINFO_FIELD_STATIC_TLS))
{
fieldFlags |= CORINFO_FLG_FIELD_SAFESTATIC_BYREF_RETURN;
}
}
else
{
Expand Down

0 comments on commit e5dcd3c

Please sign in to comment.