Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -3212,6 +3212,7 @@ class ICorDynamicInfo : public ICorStaticInfo
CORINFO_FIELD_HANDLE field,
uint8_t *buffer,
int bufferSize,
int valueOffset = 0,
bool ignoreMovableObjects = true
) = 0;

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/inc/icorjitinfoimpl_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ bool getReadonlyStaticFieldValue(
CORINFO_FIELD_HANDLE field,
uint8_t* buffer,
int bufferSize,
int valueOffset,
bool ignoreMovableObjects) override;

CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(
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 = { /* da097b39-7f43-458a-990a-0b65406d5ff3 */
0xda097b39,
0x7f43,
0x458a,
{0x99, 0xa, 0xb, 0x65, 0x40, 0x6d, 0x5f, 0xf3}
constexpr GUID JITEEVersionIdentifier = { /* 0330a175-dd05-4760-840f-a1a4c47284d3 */
0x330a175,
0xdd05,
0x4760,
{0x84, 0xf, 0xa1, 0xa4, 0xc4, 0x72, 0x84, 0xd3}
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1488,10 +1488,11 @@ bool WrapICorJitInfo::getReadonlyStaticFieldValue(
CORINFO_FIELD_HANDLE field,
uint8_t* buffer,
int bufferSize,
int valueOffset,
bool ignoreMovableObjects)
{
API_ENTER(getReadonlyStaticFieldValue);
bool temp = wrapHnd->getReadonlyStaticFieldValue(field, buffer, bufferSize, ignoreMovableObjects);
bool temp = wrapHnd->getReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects);
API_LEAVE(getReadonlyStaticFieldValue);
return temp;
}
Expand Down
19 changes: 16 additions & 3 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3335,7 +3335,8 @@ GenTree* Compiler::optConstantAssertionProp(AssertionDsc* curAssertion,
return nullptr;
}

GenTree* newTree = tree;
GenTree* newTree = tree;
bool propagateType = false;

// Update 'newTree' with the new value from our table
// Typically newTree == tree and we are updating the node in place
Expand Down Expand Up @@ -3364,9 +3365,16 @@ GenTree* Compiler::optConstantAssertionProp(AssertionDsc* curAssertion,
case O2K_CONST_INT:

// Don't propagate handles if we need to report relocs.
if (opts.compReloc && curAssertion->op2.HasIconFlag())
if (opts.compReloc && curAssertion->op2.HasIconFlag() && curAssertion->op2.u1.iconVal != 0)
{
return nullptr;
if (curAssertion->op2.GetIconFlag() == GTF_ICON_STATIC_HDL)
{
propagateType = true;
}
else
{
return nullptr;
}
}

// We assume that we do not try to do assertion prop on mismatched
Expand Down Expand Up @@ -3394,6 +3402,11 @@ GenTree* Compiler::optConstantAssertionProp(AssertionDsc* curAssertion,
// Conservatively don't allow propagation of ICON TYP_REF into BYREF
return nullptr;
}
propagateType = true;
}

if (propagateType)
{
newTree->ChangeType(tree->TypeGet());
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1107,7 +1107,11 @@ bool CodeGen::genCreateAddrMode(
if (op2->IsIntCnsFitsInI32() && (op2->gtType != TYP_REF) && FitsIn<INT32>(cns + op2->AsIntConCommon()->IconValue()))
{
// We should not be building address modes out of non-foldable constants
assert(op2->AsIntConCommon()->ImmedValCanBeFolded(compiler, addr->OperGet()));
if (!op2->AsIntConCommon()->ImmedValCanBeFolded(compiler, addr->OperGet()))
{
assert(compiler->opts.compReloc);
return false;
}

/* We're adding a constant */

Expand Down
148 changes: 146 additions & 2 deletions src/coreclr/jit/valuenum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2113,7 +2113,7 @@ ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN)
{
uint8_t buffer[TARGET_POINTER_SIZE] = {0};
if (m_pComp->info.compCompHnd->getReadonlyStaticFieldValue(field, buffer,
TARGET_POINTER_SIZE, false))
TARGET_POINTER_SIZE, 0, false))
{
// In case of 64bit jit emitting 32bit codegen this handle will be 64bit
// value holding 32bit handle with upper half zeroed (hence, "= NULL").
Expand Down Expand Up @@ -8494,6 +8494,55 @@ void Compiler::fgValueNumberSsaVarDef(GenTreeLclVarCommon* lcl)
}
}

//----------------------------------------------------------------------------------
// fgGetStaticFieldSeqAndAddress: Try to obtain a constant address with a FieldSeq from the
// given tree. It can be either INT_CNS or e.g. ADD(INT_CNS, ADD(INT_CNS, INT_CNS))
// tree where only one of the constants is expected to have a field sequence.
//
// Arguments:
// tree - tree node to inspect
// pAddress - [Out] resulting address with all offsets combined
// pFseq - [Out] field sequence
//
// Return Value:
// true if the given tree is a static field address
//
static bool fgGetStaticFieldSeqAndAddress(GenTree* tree, ssize_t* pAddress, FieldSeq** pFseq)
{
ssize_t val = 0;
// Accumulate final offset
while (tree->OperIs(GT_ADD))
{
GenTree* op1 = tree->gtGetOp1();
GenTree* op2 = tree->gtGetOp2();
if (op1->IsCnsIntOrI() && (op1->AsIntCon()->gtFieldSeq == nullptr))
{
val += op1->AsIntCon()->IconValue();
tree = op2;
}
else if (op2->IsCnsIntOrI() && (op2->AsIntCon()->gtFieldSeq == nullptr))
{
val += op2->AsIntCon()->IconValue();
tree = op1;
}
else
{
// We only inspect constants and additions
return false;
}
}

// Base address is expected to be static field's address
if ((tree->IsCnsIntOrI()) && (tree->AsIntCon()->gtFieldSeq != nullptr) &&
(tree->AsIntCon()->gtFieldSeq->GetKind() == FieldSeq::FieldKind::SimpleStaticKnownAddress))
{
*pFseq = tree->AsIntCon()->gtFieldSeq;
*pAddress = tree->AsIntCon()->IconValue() + val;
return true;
}
return false;
}

//----------------------------------------------------------------------------------
// fgValueNumberConstLoad: Try to detect const_immutable_array[cns_index] tree
// and apply a constant VN representing given element at cns_index in that array.
Expand All @@ -8506,9 +8555,104 @@ void Compiler::fgValueNumberSsaVarDef(GenTreeLclVarCommon* lcl)
//
bool Compiler::fgValueNumberConstLoad(GenTreeIndir* tree)
{
if (!tree->gtVNPair.BothEqual())
{
return false;
}

// First, let's check if we can detect RVA[const_index] pattern to fold, e.g.:
//
// static ReadOnlySpan<sbyte> RVA => new sbyte[] { -100, 100 }
//
// sbyte GetVal() => RVA[1]; // fold to '100'
//
ssize_t address = 0;
FieldSeq* fieldSeq = nullptr;
if (fgGetStaticFieldSeqAndAddress(tree->gtGetOp1(), &address, &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);
if ((fieldHandle != nullptr) && (size > 0) && (size <= maxElementSize) && ((size_t)byteOffset < INT_MAX))
{
uint8_t buffer[maxElementSize] = {0};
if (info.compCompHnd->getReadonlyStaticFieldValue(fieldHandle, (uint8_t*)&buffer, size, (int)byteOffset))
{
// For now we only support these primitives, we can extend this list to FP, SIMD and structs in future.
switch (tree->TypeGet())
{
#define READ_VALUE(typ) \
typ val = 0; \
memcpy(&val, buffer, sizeof(typ));

case TYP_BOOL:
case TYP_UBYTE:
{
READ_VALUE(uint8_t);
tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val));
return true;
}
case TYP_BYTE:
{
READ_VALUE(int8_t);
tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val));
return true;
}
case TYP_SHORT:
{
READ_VALUE(int16_t);
tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val));
return true;
}
case TYP_USHORT:
{
READ_VALUE(uint16_t);
tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val));
return true;
}
case TYP_INT:
{
READ_VALUE(int32_t);
tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val));
return true;
}
case TYP_UINT:
{
READ_VALUE(uint32_t);
tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val));
return true;
}
case TYP_LONG:
{
READ_VALUE(int64_t);
tree->gtVNPair.SetBoth(vnStore->VNForLongCon(val));
return true;
}
case TYP_ULONG:
{
READ_VALUE(uint64_t);
tree->gtVNPair.SetBoth(vnStore->VNForLongCon(val));
return true;
}
default:
break;
}
}
}
}

// Throughput check, the logic below is only for USHORT (char)
if (!tree->TypeIs(TYP_USHORT))
{
return false;
}

ValueNum addrVN = tree->gtGetOp1()->gtVNPair.GetLiberal();
VNFuncApp funcApp;
if (!tree->TypeIs(TYP_USHORT) || !tree->gtVNPair.BothEqual() || !vnStore->GetVNFunc(addrVN, &funcApp))
if (!vnStore->GetVNFunc(addrVN, &funcApp))
{
return false;
}
Expand Down
20 changes: 20 additions & 0 deletions src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4079,5 +4079,25 @@ private bool notifyInstructionSetUsage(InstructionSet instructionSet, bool suppo
return supportEnabled ? _compilation.InstructionSetSupport.IsInstructionSetSupported(instructionSet) : false;
}
#endif

private static bool TryReadRvaFieldData(FieldDesc field, byte* buffer, int bufferSize, int valueOffset)
{
Debug.Assert(buffer != null);
Debug.Assert(bufferSize > 0);
Debug.Assert(valueOffset >= 0);
Debug.Assert(field.IsStatic);
Debug.Assert(field.HasRva);

if (!field.IsThreadStatic && field.IsInitOnly && field is EcmaField ecmaField)
{
ReadOnlySpan<byte> rvaData = ecmaField.GetFieldRvaData();
if (rvaData.Length >= bufferSize && valueOffset <= rvaData.Length - bufferSize)
{
rvaData.Slice(valueOffset, bufferSize).CopyTo(new Span<byte>(buffer, bufferSize));
return true;
}
}
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2244,12 +2244,12 @@ private static uint _getClassDomainID(IntPtr thisHandle, IntPtr* ppException, CO
}

[UnmanagedCallersOnly]
private static byte _getReadonlyStaticFieldValue(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, byte ignoreMovableObjects)
private static byte _getReadonlyStaticFieldValue(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, byte ignoreMovableObjects)
{
var _this = GetThis(thisHandle);
try
{
return _this.getReadonlyStaticFieldValue(field, buffer, bufferSize, ignoreMovableObjects != 0) ? (byte)1 : (byte)0;
return _this.getReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects != 0) ? (byte)1 : (byte)0;
}
catch (Exception ex)
{
Expand Down Expand Up @@ -2838,7 +2838,7 @@ private static IntPtr GetUnmanagedCallbacks()
callbacks[148] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isRIDClassDomainID;
callbacks[149] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, uint>)&_getClassDomainID;
callbacks[150] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, void*>)&_getFieldAddress;
callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, int, byte, byte>)&_getReadonlyStaticFieldValue;
callbacks[151] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, int, int, byte, byte>)&_getReadonlyStaticFieldValue;
callbacks[152] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass;
callbacks[153] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, IntPtr>)&_getVarArgsHandle;
callbacks[154] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetVarArgsHandle;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ FUNCTIONS
bool isRIDClassDomainID(CORINFO_CLASS_HANDLE cls);
unsigned getClassDomainID (CORINFO_CLASS_HANDLE cls, void **ppIndirection);
void* getFieldAddress(CORINFO_FIELD_HANDLE field, VOIDSTARSTAR ppIndirection);
bool getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t *buffer, int bufferSize, bool ignoreMovableObjects);
bool getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t *buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects);
CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, BoolStar pIsSpeculative);
CORINFO_VARARGS_HANDLE getVarArgsHandle(CORINFO_SIG_INFO *pSig, void **ppIndirection);
bool canGetVarArgsHandle(CORINFO_SIG_INFO *pSig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2998,8 +2998,16 @@ private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses
return 0;
}

private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize, bool ignoreMovableObjects)
private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects)
{
Debug.Assert(fieldHandle != null);
FieldDesc field = HandleToObject(fieldHandle);

Comment thread
EgorBo marked this conversation as resolved.
// For crossgen2 we only support RVA fields
if (_compilation.NodeFactory.CompilationModuleGroup.VersionsWithType(field.OwningType) && field.HasRva)
{
return TryReadRvaFieldData(field, buffer, bufferSize, valueOffset);
}
return false;
Comment thread
EgorBo marked this conversation as resolved.
}

Expand Down
Loading