CORINFO_METHOD_HANDLE method,
CORINFO_SIG_INFO* sig,
unsigned methodFlags,
- int memberRef,
+ CORINFO_RESOLVED_TOKEN* pResolvedToken,
bool readonlyCall,
bool tailCall,
CORINFO_RESOLVED_TOKEN* pContstrainedResolvedToken,
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,
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);
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())
{
CORINFO_METHOD_HANDLE method,
CORINFO_SIG_INFO* sig,
unsigned methodFlags,
- int memberRef,
+ CORINFO_RESOLVED_TOKEN* pResolvedToken,
bool readonlyCall,
bool tailCall,
CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
bool mustExpand = false;
bool isSpecial = false;
const bool isIntrinsic = (methodFlags & CORINFO_FLG_INTRINSIC) != 0;
+ int memberRef = pResolvedToken->token;
NamedIntrinsic ni = lookupNamedIntrinsic(method);
{
assert(ni > NI_SRCS_UNSAFE_START);
assert(!mustExpand);
- return impSRCSUnsafeIntrinsic(ni, clsHnd, method, sig);
+ return impSRCSUnsafeIntrinsic(ni, clsHnd, method, sig, pResolvedToken);
}
else
{
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)
{
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
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);
}
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);
}