Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3631,7 +3631,8 @@ class Compiler

GenTree* impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken);

GenTree* impImportStaticReadOnlyField(uint8_t* buffer, int bufferSize, var_types valueType);
GenTree* impImportStaticReadOnlyField(CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE ownerCls);
GenTree* impImportCnsTreeFromBuffer(uint8_t* buffer, var_types valueType);

GenTree* impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedToken,
CORINFO_ACCESS_FLAGS access,
Expand Down
124 changes: 107 additions & 17 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4135,11 +4135,110 @@ GenTree* Compiler::impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken)
return node;
}

GenTree* Compiler::impImportStaticReadOnlyField(uint8_t* buffer, int bufferSize, var_types valueType)
//------------------------------------------------------------------------
// impImportStaticReadOnlyField: Tries to import 'static readonly' field
// as a constant if the host type is statically initialized.
//
// Arguments:
// field - 'static readonly' field
// ownerCls - class handle of the type the given field defined in
//
// Return Value:
// The tree representing the constant value of the statically initialized
// readonly tree.
//
GenTree* Compiler::impImportStaticReadOnlyField(CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE ownerCls)
{
// We plan to support larger values (for structs), for now let's keep it 64 bit
assert(bufferSize == sizeof(INT64));
if (!opts.OptimizationEnabled())
{
return nullptr;
}

CORINFO_CLASS_HANDLE fieldClsHnd;
var_types fieldType = JITtype2varType(info.compCompHnd->getFieldType(field, &fieldClsHnd, ownerCls));

const int bufferSize = sizeof(uint64_t);
uint8_t buffer[bufferSize] = {0};
if (varTypeIsIntegral(fieldType) || varTypeIsFloating(fieldType) || (fieldType == TYP_REF))
{
assert(bufferSize >= genTypeSize(fieldType));
if (info.compCompHnd->getReadonlyStaticFieldValue(field, buffer, genTypeSize(fieldType)))
{
GenTree* cnsValue = impImportCnsTreeFromBuffer(buffer, fieldType);
if (cnsValue != nullptr)
{
return cnsValue;
}
}
}
else if (fieldType == TYP_STRUCT)
{

if (info.compCompHnd->getClassNumInstanceFields(fieldClsHnd) != 1)
{
// Only single-field structs are supported here to avoid potential regressions where
// Metadata-driven struct promotion leads to regressions.
return nullptr;
}

CORINFO_FIELD_HANDLE innerField = info.compCompHnd->getFieldInClass(fieldClsHnd, 0);
CORINFO_CLASS_HANDLE innerFieldClsHnd;
var_types fieldVarType =
JITtype2varType(info.compCompHnd->getFieldType(innerField, &innerFieldClsHnd, fieldClsHnd));

// Technically, we can support frozen gc refs here and maybe floating point in future
if (!varTypeIsIntegral(fieldVarType))
{
return nullptr;
}

unsigned totalSize = info.compCompHnd->getClassSize(fieldClsHnd);
unsigned fldOffset = info.compCompHnd->getFieldOffset(innerField);

if ((fldOffset != 0) || (totalSize != info.compCompHnd->getClassSize(fieldClsHnd)) || (totalSize == 0))
{
// The field is expected to be of the exact size as the struct with 0 offset
return nullptr;
}

const int bufferSize = TARGET_POINTER_SIZE;
uint8_t buffer[bufferSize] = {0};

if ((totalSize > bufferSize) || !info.compCompHnd->getReadonlyStaticFieldValue(field, buffer, totalSize))
{
return nullptr;
}

unsigned structTempNum = lvaGrabTemp(true DEBUGARG("folding static ro fld struct"));
lvaSetStruct(structTempNum, fieldClsHnd, false);

GenTree* constValTree = impImportCnsTreeFromBuffer(buffer, fieldVarType);
assert(constValTree != nullptr);

GenTreeLclFld* fieldTree = gtNewLclFldNode(structTempNum, fieldVarType, fldOffset);
GenTree* fieldAsgTree = gtNewAssignNode(fieldTree, constValTree);
impAppendTree(fieldAsgTree, CHECK_SPILL_NONE, impCurStmtDI);

JITDUMP("Folding 'static readonly %s' field to an ASG(LCL, CNS) node\n", eeGetClassName(fieldClsHnd));

return impCreateLocalNode(structTempNum DEBUGARG(0));
}
return nullptr;
}

//------------------------------------------------------------------------
// impImportCnsTreeFromBuffer: read value of the given type from the
// given buffer to create a tree representing that constant.
//
// Arguments:
// buffer - array of bytes representing the value
// valueType - type of the value
//
// Return Value:
// The tree representing the constant from the given buffer
//
GenTree* Compiler::impImportCnsTreeFromBuffer(uint8_t* buffer, var_types valueType)
{
GenTree* tree = nullptr;
switch (valueType)
{
Expand Down Expand Up @@ -9489,21 +9588,12 @@ void Compiler::impImportBlockCode(BasicBlock* block)
// Replace static read-only fields with constant if possible
if ((aflags & CORINFO_ACCESS_GET) && (fieldInfo.fieldFlags & CORINFO_FLG_FIELD_FINAL))
{
const int bufferSize = sizeof(uint64_t);
uint8_t buffer[bufferSize] = {0};
if (varTypeIsIntegral(lclTyp) || varTypeIsFloating(lclTyp) || (lclTyp == TYP_REF))
GenTree* newTree = impImportStaticReadOnlyField(resolvedToken.hField, resolvedToken.hClass);

if (newTree != nullptr)
{
assert(bufferSize >= genTypeSize(lclTyp));
if (info.compCompHnd->getReadonlyStaticFieldValue(resolvedToken.hField, buffer,
genTypeSize(lclTyp)))
{
GenTree* cnsValue = impImportStaticReadOnlyField(buffer, bufferSize, lclTyp);
if (cnsValue != nullptr)
{
op1 = cnsValue;
goto FIELD_DONE;
}
}
op1 = newTree;
goto FIELD_DONE;
}
}
FALLTHROUGH;
Expand Down