Skip to content

Commit

Permalink
JIT: Import string.Empty as "" (#64530)
Browse files Browse the repository at this point in the history
Co-authored-by: Jakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>
  • Loading branch information
EgorBo and jakobbotsch authored Feb 3, 2022
1 parent e836ce5 commit 59662ad
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 9 deletions.
10 changes: 8 additions & 2 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5793,6 +5793,12 @@ GenTree* Compiler::gtNewStringLiteralNode(InfoAccessType iat, void* pValue)
//
GenTreeIntCon* Compiler::gtNewStringLiteralLength(GenTreeStrCon* node)
{
if (node->IsStringEmptyField())
{
JITDUMP("Folded String.Empty.Length to 0\n");
return gtNewIconNode(0);
}

int length = -1;
const char16_t* str = info.compCompHnd->getStringLiteral(node->gtScpHnd, node->gtSconCPX, &length);
if (length >= 0)
Expand All @@ -5802,11 +5808,11 @@ GenTreeIntCon* Compiler::gtNewStringLiteralLength(GenTreeStrCon* node)
// str can be NULL for dynamic context
if (str != nullptr)
{
JITDUMP("String '\"%ws\".Length' is '%d'\n", str, length)
JITDUMP("Folded '\"%ws\".Length' to '%d'\n", str, length)
}
else
{
JITDUMP("String 'CNS_STR.Length' is '%d'\n", length)
JITDUMP("Folded 'CNS_STR.Length' to '%d'\n", length)
}
return iconNode;
}
Expand Down
8 changes: 8 additions & 0 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -3240,11 +3240,19 @@ struct GenTreeDblCon : public GenTree

/* gtStrCon -- string constant (GT_CNS_STR) */

#define EMPTY_STRING_SCON (unsigned)-1

struct GenTreeStrCon : public GenTree
{
unsigned gtSconCPX;
CORINFO_MODULE_HANDLE gtScpHnd;

// Returns true if this GT_CNS_STR was imported for String.Empty field
bool IsStringEmptyField()
{
return gtSconCPX == EMPTY_STRING_SCON && gtScpHnd == nullptr;
}

// Because this node can come from an inlined method we need to
// have the scope handle, since it will become a helper call.
GenTreeStrCon(unsigned sconCPX, CORINFO_MODULE_HANDLE mod DEBUGARG(bool largeNode = false))
Expand Down
5 changes: 2 additions & 3 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15073,9 +15073,8 @@ void Compiler::impImportBlockCode(BasicBlock* block)
{
assert(aflags & CORINFO_ACCESS_GET);

LPVOID pValue;
InfoAccessType iat = info.compCompHnd->emptyStringLiteral(&pValue);
op1 = gtNewStringLiteralNode(iat, pValue);
// Import String.Empty as "" (GT_CNS_STR with a fake SconCPX = 0)
op1 = gtNewSconNode(EMPTY_STRING_SCON, nullptr);
goto FIELD_DONE;
}
break;
Expand Down
13 changes: 11 additions & 2 deletions src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5184,7 +5184,9 @@ GenTree* Compiler::fgMorphArrayIndex(GenTree* tree)
noway_assert(elemTyp != TYP_STRUCT || elemStructType != nullptr);

// Fold "cns_str"[cns_index] to ushort constant
if (opts.OptimizationEnabled() && asIndex->Arr()->OperIs(GT_CNS_STR) && asIndex->Index()->IsIntCnsFitsInI32())
// NOTE: don't do it for empty string, the operation will fail anyway
if (opts.OptimizationEnabled() && asIndex->Arr()->OperIs(GT_CNS_STR) &&
!asIndex->Arr()->AsStrCon()->IsStringEmptyField() && asIndex->Index()->IsIntCnsFitsInI32())
{
const int cnsIndex = static_cast<int>(asIndex->Index()->AsIntConCommon()->IconValue());
if (cnsIndex >= 0)
Expand Down Expand Up @@ -9433,11 +9435,18 @@ GenTree* Compiler::fgMorphConst(GenTree* tree)

tree->gtFlags &= ~(GTF_ALL_EFFECT | GTF_REVERSE_OPS);

if (tree->OperGet() != GT_CNS_STR)
if (!tree->OperIs(GT_CNS_STR))
{
return tree;
}

if (tree->AsStrCon()->IsStringEmptyField())
{
LPVOID pValue;
InfoAccessType iat = info.compCompHnd->emptyStringLiteral(&pValue);
return fgMorphTree(gtNewStringLiteralNode(iat, pValue));
}

// TODO-CQ: Do this for compCurBB->isRunRarely(). Doing that currently will
// guarantee slow performance for that block. Instead cache the return value
// of CORINFO_HELP_STRCNS and go to cache first giving reasonable perf.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -748,8 +748,17 @@ private bool canTailCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUC
private InfoAccessType constructStringLiteral(CORINFO_MODULE_STRUCT_* module, mdToken metaTok, ref void* ppValue)
{
MethodIL methodIL = (MethodIL)HandleToObject((IntPtr)module);
object literal = methodIL.GetObject((int)metaTok);
ISymbolNode stringObject = _compilation.NodeFactory.SerializedStringObject((string)literal);

ISymbolNode stringObject;
if (metaTok == (mdToken)CorConstants.CorTokenType.mdtString)
{
stringObject = _compilation.NodeFactory.SerializedStringObject("");
}
else
{
object literal = methodIL.GetObject((int)metaTok);
stringObject = _compilation.NodeFactory.SerializedStringObject((string)literal);
}
ppValue = (void*)ObjectToHandle(stringObject);
return stringObject.RepresentsIndirectionCell ? InfoAccessType.IAT_PVALUE : InfoAccessType.IAT_VALUE;
}
Expand Down

0 comments on commit 59662ad

Please sign in to comment.