Skip to content

JIT: Update class for Unsafe.As<>() #85954

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
May 9, 2023
7 changes: 4 additions & 3 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3925,7 +3925,7 @@ class Compiler
CORINFO_METHOD_HANDLE method,
CORINFO_SIG_INFO* sig,
unsigned methodFlags,
int memberRef,
CORINFO_RESOLVED_TOKEN* pResolvedToken,
bool readonlyCall,
bool tailCall,
CORINFO_RESOLVED_TOKEN* pContstrainedResolvedToken,
Expand All @@ -3947,7 +3947,8 @@ class Compiler
GenTree* impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic,
CORINFO_CLASS_HANDLE clsHnd,
CORINFO_METHOD_HANDLE method,
CORINFO_SIG_INFO* sig);
CORINFO_SIG_INFO* sig,
CORINFO_RESOLVED_TOKEN* pResolvedToken);

GenTree* impPrimitiveNamedIntrinsic(NamedIntrinsic intrinsic,
CORINFO_CLASS_HANDLE clsHnd,
Expand Down Expand Up @@ -4030,7 +4031,7 @@ class Compiler
Statement* impAppendTree(GenTree* tree, unsigned chkLevel, const DebugInfo& di, bool checkConsumedDebugInfo = true);
void impAssignTempGen(unsigned lclNum,
GenTree* val,
unsigned curLevel = CHECK_SPILL_NONE,
unsigned curLevel,
Statement** pAfterStmt = nullptr,
const DebugInfo& di = DebugInfo(),
BasicBlock* block = nullptr);
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1638,7 +1638,7 @@ GenTree* Compiler::impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken

// Spilling it to a temp improves CQ (mainly in Tier0)
unsigned callLclNum = lvaGrabTemp(true DEBUGARG("spilling helperCall"));
impAssignTempGen(callLclNum, helperCall);
impAssignTempGen(callLclNum, helperCall, CHECK_SPILL_NONE);
return gtNewLclvNode(callLclNum, helperCall->TypeGet());
}

Expand Down
50 changes: 41 additions & 9 deletions src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,8 @@ var_types Compiler::impImportCall(OPCODE opcode,

const bool isTailCall = canTailCall && (tailCallFlags != 0);

call =
impIntrinsic(newobjThis, clsHnd, methHnd, sig, mflags, pResolvedToken->token, isReadonlyCall,
isTailCall, pConstrainedResolvedToken, callInfo->thisTransform, &ni, &isSpecialIntrinsic);
call = impIntrinsic(newobjThis, clsHnd, methHnd, sig, mflags, pResolvedToken, isReadonlyCall, isTailCall,
pConstrainedResolvedToken, callInfo->thisTransform, &ni, &isSpecialIntrinsic);

if (compDonotInline())
{
Expand Down Expand Up @@ -2301,7 +2300,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
CORINFO_METHOD_HANDLE method,
CORINFO_SIG_INFO* sig,
unsigned methodFlags,
int memberRef,
CORINFO_RESOLVED_TOKEN* pResolvedToken,
bool readonlyCall,
bool tailCall,
CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
Expand All @@ -2312,6 +2311,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
bool mustExpand = false;
bool isSpecial = false;
const bool isIntrinsic = (methodFlags & CORINFO_FLG_INTRINSIC) != 0;
int memberRef = pResolvedToken->token;

NamedIntrinsic ni = lookupNamedIntrinsic(method);

Expand Down Expand Up @@ -2455,7 +2455,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
{
assert(ni > NI_SRCS_UNSAFE_START);
assert(!mustExpand);
return impSRCSUnsafeIntrinsic(ni, clsHnd, method, sig);
return impSRCSUnsafeIntrinsic(ni, clsHnd, method, sig, pResolvedToken);
}
else
{
Expand Down Expand Up @@ -3905,10 +3905,11 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
return retNode;
}

GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic,
CORINFO_CLASS_HANDLE clsHnd,
CORINFO_METHOD_HANDLE method,
CORINFO_SIG_INFO* sig)
GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic,
CORINFO_CLASS_HANDLE clsHnd,
CORINFO_METHOD_HANDLE method,
CORINFO_SIG_INFO* sig,
CORINFO_RESOLVED_TOKEN* pResolvedToken)
{
// NextCallRetAddr requires a CALL, so return nullptr.
if (info.compHasNextCallRetAddr)
Expand Down Expand Up @@ -3987,6 +3988,37 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic,
{
assert((sig->sigInst.methInstCount == 1) || (sig->sigInst.methInstCount == 2));

if (sig->sigInst.methInstCount == 1)
{
CORINFO_SIG_INFO exactSig;
info.compCompHnd->getMethodSig(pResolvedToken->hMethod, &exactSig);
const CORINFO_CLASS_HANDLE inst = exactSig.sigInst.methInst[0];
assert(inst != nullptr);

GenTree* op = impPopStack().val;
assert(op->TypeIs(TYP_REF));

JITDUMP("Expanding Unsafe.As<%s>(...)\n", eeGetClassName(inst));

bool isExact, isNonNull;
CORINFO_CLASS_HANDLE oldClass = gtGetClassHandle(op, &isExact, &isNonNull);
if ((oldClass != NO_CLASS_HANDLE) &&
((oldClass == inst) || !info.compCompHnd->isMoreSpecificType(oldClass, inst)))
{
JITDUMP("Unsafe.As: Keep using old '%s' type\n", eeGetClassName(oldClass));
return op;
}

// In order to change the class handle of the object we need to spill it to a temp
// and update class info for that temp.
unsigned localNum = lvaGrabTemp(true DEBUGARG("updating class info"));
impAssignTempGen(localNum, op, CHECK_SPILL_ALL);

// NOTE: we still can't say for sure that it is the exact type of the argument
lvaSetClass(localNum, inst, /*isExact*/ false);
return gtNewLclvNode(localNum, TYP_REF);
}

// ldarg.0
// ret

Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/jit/importervectorization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -645,12 +645,12 @@ GenTree* Compiler::impStringEqualsOrStartsWith(bool startsWith, CORINFO_SIG_INFO
strLenOffset + sizeof(int), cmpMode);
if (unrolled != nullptr)
{
impAssignTempGen(varStrTmp, varStr);
impAssignTempGen(varStrTmp, varStr, CHECK_SPILL_NONE);
if (unrolled->OperIs(GT_QMARK))
{
// QMARK nodes cannot reside on the evaluation stack
unsigned rootTmp = lvaGrabTemp(true DEBUGARG("spilling unroll qmark"));
impAssignTempGen(rootTmp, unrolled);
impAssignTempGen(rootTmp, unrolled, CHECK_SPILL_NONE);
unrolled = gtNewLclvNode(rootTmp, TYP_INT);
}

Expand Down Expand Up @@ -797,13 +797,13 @@ GenTree* Compiler::impSpanEqualsOrStartsWith(bool startsWith, CORINFO_SIG_INFO*
if (unrolled != nullptr)
{
// We succeeded, fill the placeholders:
impAssignTempGen(spanObjRef, impGetStructAddr(spanObj, CHECK_SPILL_NONE, true));
impAssignTempGen(spanDataTmp, spanData);
impAssignTempGen(spanObjRef, impGetStructAddr(spanObj, CHECK_SPILL_NONE, true), CHECK_SPILL_NONE);
impAssignTempGen(spanDataTmp, spanData, CHECK_SPILL_NONE);
if (unrolled->OperIs(GT_QMARK))
{
// QMARK can't be a root node, spill it to a temp
unsigned rootTmp = lvaGrabTemp(true DEBUGARG("spilling unroll qmark"));
impAssignTempGen(rootTmp, unrolled);
impAssignTempGen(rootTmp, unrolled, CHECK_SPILL_NONE);
unrolled = gtNewLclvNode(rootTmp, TYP_INT);
}

Expand Down