@@ -233,9 +233,8 @@ var_types Compiler::impImportCall(OPCODE opcode,
233
233
234
234
const bool isTailCall = canTailCall && (tailCallFlags != 0);
235
235
236
- call =
237
- impIntrinsic(newobjThis, clsHnd, methHnd, sig, mflags, pResolvedToken->token, isReadonlyCall,
238
- isTailCall, pConstrainedResolvedToken, callInfo->thisTransform, &ni, &isSpecialIntrinsic);
236
+ call = impIntrinsic(newobjThis, clsHnd, methHnd, sig, mflags, pResolvedToken, isReadonlyCall, isTailCall,
237
+ pConstrainedResolvedToken, callInfo->thisTransform, &ni, &isSpecialIntrinsic);
239
238
240
239
if (compDonotInline())
241
240
{
@@ -2301,7 +2300,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
2301
2300
CORINFO_METHOD_HANDLE method,
2302
2301
CORINFO_SIG_INFO* sig,
2303
2302
unsigned methodFlags,
2304
- int memberRef ,
2303
+ CORINFO_RESOLVED_TOKEN* pResolvedToken ,
2305
2304
bool readonlyCall,
2306
2305
bool tailCall,
2307
2306
CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
@@ -2312,6 +2311,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
2312
2311
bool mustExpand = false;
2313
2312
bool isSpecial = false;
2314
2313
const bool isIntrinsic = (methodFlags & CORINFO_FLG_INTRINSIC) != 0;
2314
+ int memberRef = pResolvedToken->token;
2315
2315
2316
2316
NamedIntrinsic ni = lookupNamedIntrinsic(method);
2317
2317
@@ -2455,7 +2455,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
2455
2455
{
2456
2456
assert(ni > NI_SRCS_UNSAFE_START);
2457
2457
assert(!mustExpand);
2458
- return impSRCSUnsafeIntrinsic(ni, clsHnd, method, sig);
2458
+ return impSRCSUnsafeIntrinsic(ni, clsHnd, method, sig, pResolvedToken );
2459
2459
}
2460
2460
else
2461
2461
{
@@ -3909,10 +3909,11 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
3909
3909
return retNode;
3910
3910
}
3911
3911
3912
- GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic,
3913
- CORINFO_CLASS_HANDLE clsHnd,
3914
- CORINFO_METHOD_HANDLE method,
3915
- CORINFO_SIG_INFO* sig)
3912
+ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic,
3913
+ CORINFO_CLASS_HANDLE clsHnd,
3914
+ CORINFO_METHOD_HANDLE method,
3915
+ CORINFO_SIG_INFO* sig,
3916
+ CORINFO_RESOLVED_TOKEN* pResolvedToken)
3916
3917
{
3917
3918
// NextCallRetAddr requires a CALL, so return nullptr.
3918
3919
if (info.compHasNextCallRetAddr)
@@ -3991,6 +3992,37 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic,
3991
3992
{
3992
3993
assert((sig->sigInst.methInstCount == 1) || (sig->sigInst.methInstCount == 2));
3993
3994
3995
+ if (sig->sigInst.methInstCount == 1)
3996
+ {
3997
+ CORINFO_SIG_INFO exactSig;
3998
+ info.compCompHnd->getMethodSig(pResolvedToken->hMethod, &exactSig);
3999
+ const CORINFO_CLASS_HANDLE inst = exactSig.sigInst.methInst[0];
4000
+ assert(inst != nullptr);
4001
+
4002
+ GenTree* op = impPopStack().val;
4003
+ assert(op->TypeIs(TYP_REF));
4004
+
4005
+ JITDUMP("Expanding Unsafe.As<%s>(...)\n", eeGetClassName(inst));
4006
+
4007
+ bool isExact, isNonNull;
4008
+ CORINFO_CLASS_HANDLE oldClass = gtGetClassHandle(op, &isExact, &isNonNull);
4009
+ if ((oldClass != NO_CLASS_HANDLE) &&
4010
+ ((oldClass == inst) || !info.compCompHnd->isMoreSpecificType(oldClass, inst)))
4011
+ {
4012
+ JITDUMP("Unsafe.As: Keep using old '%s' type\n", eeGetClassName(oldClass));
4013
+ return op;
4014
+ }
4015
+
4016
+ // In order to change the class handle of the object we need to spill it to a temp
4017
+ // and update class info for that temp.
4018
+ unsigned localNum = lvaGrabTemp(true DEBUGARG("updating class info"));
4019
+ impAssignTempGen(localNum, op, CHECK_SPILL_ALL);
4020
+
4021
+ // NOTE: we still can't say for sure that it is the exact type of the argument
4022
+ lvaSetClass(localNum, inst, /*isExact*/ false);
4023
+ return gtNewLclvNode(localNum, TYP_REF);
4024
+ }
4025
+
3994
4026
// ldarg.0
3995
4027
// ret
3996
4028
0 commit comments