From 7f356580ef111f3c6f2e6e47b05f8fdd97b78e4f Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Tue, 9 May 2023 23:42:29 +0200 Subject: [PATCH] JIT: Update class for Unsafe.As<>() (#85954) --- src/coreclr/jit/compiler.h | 7 ++-- src/coreclr/jit/importer.cpp | 2 +- src/coreclr/jit/importercalls.cpp | 50 +++++++++++++++++++---- src/coreclr/jit/importervectorization.cpp | 10 ++--- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 4d4fb2b5fcfab..22533f9571556 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3923,7 +3923,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, @@ -3945,7 +3945,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, @@ -4028,7 +4029,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); diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 29297a6b46d6c..0e02df0c33e67 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -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()); } diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index a20c8ba266eb9..9917845b3cddf 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -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()) { @@ -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, @@ -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); @@ -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 { @@ -3909,10 +3909,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) @@ -3991,6 +3992,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 diff --git a/src/coreclr/jit/importervectorization.cpp b/src/coreclr/jit/importervectorization.cpp index 141073b158e27..a70143fac22fa 100644 --- a/src/coreclr/jit/importervectorization.cpp +++ b/src/coreclr/jit/importervectorization.cpp @@ -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); } @@ -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); }