Skip to content

Commit d04703b

Browse files
authored
Don't give up on folding obj.GetType if obj can be null (#129371)
This PR: * in vn when we call `gtGetClassHandle` to fold `obj.GetType()` into a constant (on VN level) we shouldn't give up if `gtGetClassHandle` is unsure about `obj` being never null * `gtGetClassHandle` now calls `fgAddrCouldBeNull` and `vnStore->IsKnownNonNull` for its `isNonNull` out param. Example: ```cs string _fld; Type Foo() => _fld.GetType(); ``` Was: ```asm ; Method Proga:Foo():System.Type:this (FullOpts) sub rsp, 40 mov rcx, gword ptr [rcx+0x08] call [System.Object:GetType():System.Type:this] nop add rsp, 40 ret ``` Now: ```asm ; Method Proga:Foo():System.Type:this (FullOpts) mov eax, dword ptr [rcx+0x08] ;; nullcheck mov rax, 0x2BC495400E0 ; 'System.String' ret ``` [diffs](MihuBot/runtime-utils#1978)
1 parent 0080389 commit d04703b

2 files changed

Lines changed: 24 additions & 3 deletions

File tree

src/coreclr/jit/gentree.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21022,6 +21022,18 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b
2102221022
}
2102321023
}
2102421024

21025+
if ((objClass != NO_CLASS_HANDLE) && !*pIsNonNull)
21026+
{
21027+
// NOTE: We probably want to incorporate vnStore->IsKnownNonNull into fgAddrCouldBeNull,
21028+
// but that would make fgAddrCouldBeNull's behavior phase-dependent, whereas it is
21029+
// actively used in various diagnostic asserts (e.g., checking for no extra flags on a tree).
21030+
if (!fgAddrCouldBeNull(tree) ||
21031+
((vnStore != nullptr) && vnStore->IsKnownNonNull(optConservativeNormalVN(tree))))
21032+
{
21033+
*pIsNonNull = true;
21034+
}
21035+
}
21036+
2102521037
return objClass;
2102621038
}
2102721039

src/coreclr/jit/valuenum.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13707,13 +13707,22 @@ void Compiler::fgValueNumberIntrinsic(GenTree* tree)
1370713707
bool isExact = false;
1370813708
bool isNonNull = false;
1370913709
CORINFO_CLASS_HANDLE cls = gtGetClassHandle(tree->gtGetOp1(), &isExact, &isNonNull);
13710-
if ((cls != NO_CLASS_HANDLE) && isExact && isNonNull)
13710+
if ((cls != NO_CLASS_HANDLE) && isExact)
1371113711
{
1371213712
CORINFO_OBJECT_HANDLE typeObj = info.compCompHnd->getRuntimeTypePointer(cls);
1371313713
if (typeObj != nullptr)
1371413714
{
13715-
ValueNum handleVN = vnStore->VNForHandle((ssize_t)typeObj, GTF_ICON_OBJ_HDL);
13716-
intrinsic->gtVNPair = vnStore->VNPWithExc(ValueNumPair(handleVN, handleVN), arg0VNPx);
13715+
ValueNum handleVN = vnStore->VNForHandle((ssize_t)typeObj, GTF_ICON_OBJ_HDL);
13716+
ValueNumPair excSet = arg0VNPx;
13717+
if (!isNonNull)
13718+
{
13719+
// We know the exact type, but not that obj is non-null, so obj.GetType() may still
13720+
// throw a NullReferenceException. Fold the (non-exceptional) result to the exact
13721+
// runtime type handle while preserving the null check in the exception set - otherwise
13722+
// the constant value would suppress the NRE (see fgValueNumberAddExceptionSetForIndirection).
13723+
excSet = vnStore->VNPExcSetUnion(excSet, fgValueNumberIndirNullCheckExceptions(tree->gtGetOp1()));
13724+
}
13725+
intrinsic->gtVNPair = vnStore->VNPWithExc(ValueNumPair(handleVN, handleVN), excSet);
1371713726
return;
1371813727
}
1371913728
}

0 commit comments

Comments
 (0)