summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h8
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/lwmlist.h2
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp66
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/methodcontext.h12
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp20
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp16
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp14
-rw-r--r--src/ToolBox/superpmi/superpmi/icorjitinfo.cpp16
-rw-r--r--src/inc/corinfo.h33
-rw-r--r--src/jit/compiler.h3
-rw-r--r--src/jit/compiler.hpp17
-rw-r--r--src/jit/gentree.cpp96
-rw-r--r--src/jit/gentree.h56
-rw-r--r--src/jit/gtlist.h2
-rw-r--r--src/jit/gtstructs.h1
-rw-r--r--src/jit/importer.cpp42
-rw-r--r--src/jit/morph.cpp3
-rw-r--r--src/vm/jitinterface.cpp69
-rw-r--r--src/vm/jitinterface.h14
-rw-r--r--src/zap/zapinfo.cpp10
-rw-r--r--src/zap/zapinfo.h3
21 files changed, 482 insertions, 21 deletions
diff --git a/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h b/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
index 29baaa8a39..aae6cd8e58 100644
--- a/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
+++ b/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
@@ -428,6 +428,14 @@ BOOL canCast(CORINFO_CLASS_HANDLE child, // subtype (extends parent)
// TRUE if cls1 and cls2 are considered equivalent types.
BOOL areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+// See if a cast from fromClass to toClass will succeed, fail, or needs
+// to be resolved at runtime.
+TypeCompareState compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass);
+
+// See if types represented by cls1 and cls2 compare equal, not
+// equal, or the comparison needs to be resolved at runtime.
+TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
diff --git a/src/ToolBox/superpmi/superpmi-shared/lwmlist.h b/src/ToolBox/superpmi/superpmi-shared/lwmlist.h
index 21f7906510..1bca259a6f 100644
--- a/src/ToolBox/superpmi/superpmi-shared/lwmlist.h
+++ b/src/ToolBox/superpmi/superpmi-shared/lwmlist.h
@@ -31,6 +31,8 @@ LWM(CanInlineTypeCheckWithObjectVTable, DWORDLONG, DWORD)
LWM(CanSkipMethodVerification, DLD, DWORD)
LWM(CanTailCall, Agnostic_CanTailCall, DWORD)
LWM(CheckMethodModifier, Agnostic_CheckMethodModifier, DWORD)
+LWM(CompareTypesForCast, DLDL, DWORD)
+LWM(CompareTypesForEquality, DLDL, DWORD)
LWM(CompileMethod, DWORD, Agnostic_CompileMethod)
LWM(ConstructStringLiteral, DLD, DLD)
LWM(EmbedClassHandle, DWORDLONG, DLDL)
diff --git a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
index 0bf288d196..c3ae9d3a52 100644
--- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
@@ -5288,6 +5288,72 @@ BOOL MethodContext::repAreTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLA
return value;
}
+void MethodContext::recCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass, TypeCompareState result)
+{
+ if (CompareTypesForCast == nullptr)
+ CompareTypesForCast = new LightWeightMap<DLDL, DWORD>();
+
+ DLDL key;
+ ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+
+ key.A = (DWORDLONG)fromClass;
+ key.B = (DWORDLONG)toClass;
+
+ CompareTypesForCast->Add(key, (DWORD)result);
+}
+void MethodContext::dmpCompareTypesForCast(DLDL key, DWORD value)
+{
+ printf("CompareTypesForCast key fromClas=%016llX, toClass=%016llx, result=%d", key.A, key.B, value);
+}
+TypeCompareState MethodContext::repCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass)
+{
+ DLDL key;
+ ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+
+ key.A = (DWORDLONG)fromClass;
+ key.B = (DWORDLONG)toClass;
+
+ AssertCodeMsg(CompareTypesForCast->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llX %016llX",
+ (DWORDLONG)fromClass, (DWORDLONG)toClass);
+ TypeCompareState value = (TypeCompareState)CompareTypesForCast->Get(key);
+ return value;
+}
+
+void MethodContext::recCompareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, TypeCompareState result)
+{
+ if (CompareTypesForEquality == nullptr)
+ CompareTypesForEquality = new LightWeightMap<DLDL, DWORD>();
+
+ DLDL key;
+ ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+
+ key.A = (DWORDLONG)cls1;
+ key.B = (DWORDLONG)cls2;
+
+ CompareTypesForEquality->Add(key, (DWORD)result);
+}
+void MethodContext::dmpCompareTypesForEquality(DLDL key, DWORD value)
+{
+ printf("CompareTypesForEquality key cls1=%016llX, cls2=%016llx, result=%d", key.A, key.B, value);
+}
+TypeCompareState MethodContext::repCompareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ DLDL key;
+ ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+
+ key.A = (DWORDLONG)cls1;
+ key.B = (DWORDLONG)cls2;
+
+ AssertCodeMsg(CompareTypesForEquality->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llX %016llX",
+ (DWORDLONG)cls1, (DWORDLONG)cls2);
+ TypeCompareState value = (TypeCompareState)CompareTypesForEquality->Get(key);
+ return value;
+}
+
void MethodContext::recFindNameOfToken(
CORINFO_MODULE_HANDLE module, mdToken metaTOK, char* szFQName, size_t FQNameCapacity, size_t result)
{
diff --git a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
index 52515733d3..9cc8f02ff0 100644
--- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
+++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
@@ -1176,6 +1176,14 @@ public:
void dmpAreTypesEquivalent(DLDL key, DWORD value);
BOOL repAreTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+ void recCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass, TypeCompareState result);
+ void dmpCompareTypesForCast(DLDL key, DWORD value);
+ TypeCompareState repCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass);
+
+ void recCompareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, TypeCompareState result);
+ void dmpCompareTypesForEquality(DLDL key, DWORD value);
+ TypeCompareState repCompareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+
void recFindNameOfToken(
CORINFO_MODULE_HANDLE module, mdToken metaTOK, char* szFQName, size_t FQNameCapacity, size_t result);
void dmpFindNameOfToken(DLD key, DLD value);
@@ -1257,7 +1265,7 @@ private:
};
// ********************* Please keep this up-to-date to ease adding more ***************
-// Highest packet number: 162
+// Highest packet number: 164
// *************************************************************************************
enum mcPackets
{
@@ -1279,6 +1287,8 @@ enum mcPackets
Packet_CheckMethodModifier = 142, // retired as 13 on 2013/07/04
Retired3 = 14,
Retired5 = 141, // retired as 14 on 2013/07/03
+ Packet_CompareTypesForCast = 163, // Added 10/4/17
+ Packet_CompareTypesForEquality = 164, // Added 10/4/17
Packet_CompileMethod = 143, // retired as 141 on 2013/07/09
Packet_ConstructStringLiteral = 15,
Packet_EmbedClassHandle = 16,
diff --git a/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
index 6051de8840..af3e8c94de 100644
--- a/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
@@ -889,6 +889,26 @@ BOOL interceptor_ICJI::areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLA
return temp;
}
+// See if a cast from fromClass to toClass will succeed, fail, or needs
+// to be resolved at runtime.
+TypeCompareState interceptor_ICJI::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass)
+{
+ mc->cr->AddCall("compareTypesForCast");
+ TypeCompareState temp = original_ICorJitInfo->compareTypesForCast(fromClass, toClass);
+ mc->recCompareTypesForCast(fromClass, toClass, temp);
+ return temp;
+}
+
+// See if types represented by cls1 and cls2 compare equal, not
+// equal, or the comparison needs to be resolved at runtime.
+TypeCompareState interceptor_ICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ mc->cr->AddCall("compareTypesForEquality");
+ TypeCompareState temp = original_ICorJitInfo->compareTypesForEquality(cls1, cls2);
+ mc->recCompareTypesForEquality(cls1, cls2, temp);
+ return temp;
+}
+
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
{
diff --git a/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
index 17da100dac..dd047e83a7 100644
--- a/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
@@ -703,6 +703,22 @@ BOOL interceptor_ICJI::areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLA
return original_ICorJitInfo->areTypesEquivalent(cls1, cls2);
}
+// See if a cast from fromClass to toClass will succeed, fail, or needs
+// to be resolved at runtime.
+TypeCompareState interceptor_ICJI::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass)
+{
+ mcs->AddCall("compareTypesForCast");
+ return original_ICorJitInfo->compareTypesForCast(fromClass, toClass);
+}
+
+// See if types represented by cls1 and cls2 compare equal, not
+// equal, or the comparison needs to be resolved at runtime.
+TypeCompareState interceptor_ICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ mcs->AddCall("compareTypesForEquality");
+ return original_ICorJitInfo->compareTypesForEquality(cls1, cls2);
+}
+
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
{
diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
index df4cfcfbcd..cc384f31a0 100644
--- a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
@@ -629,6 +629,20 @@ BOOL interceptor_ICJI::areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLA
return original_ICorJitInfo->areTypesEquivalent(cls1, cls2);
}
+// See if a cast from fromClass to toClass will succeed, fail, or needs
+// to be resolved at runtime.
+TypeCompareState interceptor_ICJI::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass)
+{
+ return original_ICorJitInfo->compareTypesForCast(fromClass, toClass);
+}
+
+// See if types represented by cls1 and cls2 compare equal, not
+// equal, or the comparison needs to be resolved at runtime.
+TypeCompareState interceptor_ICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ return original_ICorJitInfo->compareTypesForEquality(cls1, cls2);
+}
+
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
{
diff --git a/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
index 7c119b86dd..e16903b9e1 100644
--- a/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
@@ -760,6 +760,22 @@ BOOL MyICJI::areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE
return jitInstance->mc->repAreTypesEquivalent(cls1, cls2);
}
+// See if a cast from fromClass to toClass will succeed, fail, or needs
+// to be resolved at runtime.
+TypeCompareState MyICJI::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass)
+{
+ jitInstance->mc->cr->AddCall("compareTypesForCast");
+ return jitInstance->mc->repCompareTypesForCast(fromClass, toClass);
+}
+
+// See if types represented by cls1 and cls2 compare equal, not
+// equal, or the comparison needs to be resolved at runtime.
+TypeCompareState MyICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ jitInstance->mc->cr->AddCall("compareTypesForEquality");
+ return jitInstance->mc->repCompareTypesForEquality(cls1, cls2);
+}
+
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE MyICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
{
diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h
index b03f0456ac..dc3d22fa9f 100644
--- a/src/inc/corinfo.h
+++ b/src/inc/corinfo.h
@@ -213,12 +213,11 @@ TODO: Talk about initializing strutures before use
#define SELECTANY extern __declspec(selectany)
#endif
-// {CFEC7B89-D5FF-4A67-823A-EF99FE0286F4}
-SELECTANY const GUID JITEEVersionIdentifier = {
- 0xcfec7b89,
- 0xd5ff,
- 0x4a67,
- { 0x82, 0x3a, 0xef, 0x99, 0xfe, 0x2, 0x86, 0xf4 }
+SELECTANY const GUID JITEEVersionIdentifier = { /* 8f51c68e-d515-425c-9e04-97e4a8148b07 */
+ 0x8f51c68e,
+ 0xd515,
+ 0x425c,
+ {0x9e, 0x04, 0x97, 0xe4, 0xa8, 0x14, 0x8b, 0x07}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1955,6 +1954,14 @@ typedef SIZE_T GSCookie;
const int MAX_EnC_HANDLER_NESTING_LEVEL = 6;
+// Results from type comparison queries
+enum class TypeCompareState
+{
+ MustNot = -1, // types are not equal
+ May = 0, // types may be equal (must test at runtime)
+ Must = 1, // type are equal
+};
+
//
// This interface is logically split into sections for each class of information
// (ICorMethodInfo, ICorModuleInfo, etc.). This split used to exist physically as well
@@ -2492,6 +2499,20 @@ public:
CORINFO_CLASS_HANDLE cls2
) = 0;
+ // See if a cast from fromClass to toClass will succeed, fail, or needs
+ // to be resolved at runtime.
+ virtual TypeCompareState compareTypesForCast(
+ CORINFO_CLASS_HANDLE fromClass,
+ CORINFO_CLASS_HANDLE toClass
+ ) = 0;
+
+ // See if types represented by cls1 and cls2 compare equal, not
+ // equal, or the comparison needs to be resolved at runtime.
+ virtual TypeCompareState compareTypesForEquality(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2
+ ) = 0;
+
// returns is the intersection of cls1 and cls2.
virtual CORINFO_CLASS_HANDLE mergeClasses(
CORINFO_CLASS_HANDLE cls1,
diff --git a/src/jit/compiler.h b/src/jit/compiler.h
index cd65c25b86..0e8b4c2135 100644
--- a/src/jit/compiler.h
+++ b/src/jit/compiler.h
@@ -2119,6 +2119,8 @@ public:
GenTreePtr gtNewAllocObjNode(unsigned int helper, CORINFO_CLASS_HANDLE clsHnd, var_types type, GenTreePtr op1);
+ GenTree* gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* lookupTree);
+
//------------------------------------------------------------------------
// Other GenTree functions
@@ -9769,6 +9771,7 @@ public:
case GT_RETURN:
case GT_RETFILT:
case GT_PHI:
+ case GT_RUNTIMELOOKUP:
{
GenTreeUnOp* const unOp = node->AsUnOp();
if (unOp->gtOp1 != nullptr)
diff --git a/src/jit/compiler.hpp b/src/jit/compiler.hpp
index 4a90760ce2..f357e6f5c8 100644
--- a/src/jit/compiler.hpp
+++ b/src/jit/compiler.hpp
@@ -1169,6 +1169,23 @@ inline GenTreePtr Compiler::gtNewAllocObjNode(unsigned int helper,
return node;
}
+//------------------------------------------------------------------------
+// gtNewRuntimeLookup: Helper to create a runtime lookup node
+//
+// Arguments:
+// hnd - generic handle being looked up
+// hndTyp - type of the generic handle
+// tree - tree for the lookup
+//
+// Return Value:
+// New GenTreeRuntimeLookup node.
+inline GenTree* Compiler::gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* tree)
+{
+ assert(tree != nullptr);
+ GenTree* node = new (this, GT_RUNTIMELOOKUP) GenTreeRuntimeLookup(hnd, hndTyp, tree);
+ return node;
+}
+
/*****************************************************************************/
inline GenTreePtr Compiler::gtNewCodeRef(BasicBlock* block)
diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp
index c095507f81..5ca06a0e51 100644
--- a/src/jit/gentree.cpp
+++ b/src/jit/gentree.cpp
@@ -1901,6 +1901,12 @@ AGAIN:
reinterpret_cast<uintptr_t>(tree->gtAllocObj.gtAllocObjClsHnd)));
hash = genTreeHashAdd(hash, tree->gtAllocObj.gtNewHelper);
break;
+ case GT_RUNTIMELOOKUP:
+ hash =
+ genTreeHashAdd(hash,
+ static_cast<unsigned>(reinterpret_cast<uintptr_t>(tree->gtRuntimeLookup.gtHnd)));
+ break;
+
case GT_OBJ:
hash =
genTreeHashAdd(hash, static_cast<unsigned>(reinterpret_cast<uintptr_t>(tree->gtObj.gtClass)));
@@ -5441,6 +5447,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use)
case GT_BLK:
case GT_BOX:
case GT_ALLOCOBJ:
+ case GT_RUNTIMELOOKUP:
case GT_INIT_VAL:
case GT_JTRUE:
case GT_SWITCH:
@@ -7522,6 +7529,15 @@ GenTreePtr Compiler::gtCloneExpr(
}
break;
+ case GT_RUNTIMELOOKUP:
+ {
+ GenTreeRuntimeLookup* asRuntimeLookup = tree->AsRuntimeLookup();
+
+ copy = new (this, GT_RUNTIMELOOKUP)
+ GenTreeRuntimeLookup(asRuntimeLookup->gtHnd, asRuntimeLookup->gtHndType, asRuntimeLookup->gtOp1);
+ }
+ break;
+
case GT_ARR_LENGTH:
copy = gtNewArrLen(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtArrLen.ArrLenOffset());
break;
@@ -8841,6 +8857,7 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node)
case GT_BLK:
case GT_BOX:
case GT_ALLOCOBJ:
+ case GT_RUNTIMELOOKUP:
case GT_INIT_VAL:
case GT_JTRUE:
case GT_SWITCH:
@@ -10077,6 +10094,31 @@ void Compiler::gtDispNode(GenTreePtr tree, IndentStack* indentStack, __in __in_z
{
printf(" => [clsHnd=%08X]", dspPtr(tree->gtArgPlace.gtArgPlaceClsHnd));
}
+
+ if (tree->gtOper == GT_RUNTIMELOOKUP)
+ {
+#ifdef _TARGET_64BIT_
+ printf(" 0x%llx", dspPtr(tree->gtRuntimeLookup.gtHnd));
+#else
+ printf(" 0x%x", dspPtr(tree->gtRuntimeLookup.gtHnd));
+#endif
+
+ switch (tree->gtRuntimeLookup.gtHndType)
+ {
+ case CORINFO_HANDLETYPE_CLASS:
+ printf(" class");
+ break;
+ case CORINFO_HANDLETYPE_METHOD:
+ printf(" method");
+ break;
+ case CORINFO_HANDLETYPE_FIELD:
+ printf(" field");
+ break;
+ default:
+ printf(" unknown");
+ break;
+ }
+ }
}
// for tracking down problems in reguse prediction or liveness tracking
@@ -12368,6 +12410,55 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree)
}
}
+ // If the inputs to the type from handle operations are now
+ // either known class handles or runtime lookups, ask the VM
+ // if it knows the outcome of the equality comparison.
+ CORINFO_CLASS_HANDLE cls1Hnd = nullptr;
+ CORINFO_CLASS_HANDLE cls2Hnd = nullptr;
+ unsigned runtimeLookupCount = 0;
+
+ if ((op1ClassFromHandle->OperGet() == GT_CNS_INT) && op1ClassFromHandle->IsIconHandle(GTF_ICON_CLASS_HDL))
+ {
+ cls1Hnd = (CORINFO_CLASS_HANDLE)op1ClassFromHandle->gtIntCon.gtCompileTimeHandle;
+ }
+ else if (op1ClassFromHandle->OperGet() == GT_RUNTIMELOOKUP)
+ {
+ cls1Hnd = op1ClassFromHandle->AsRuntimeLookup()->GetClassHandle();
+ runtimeLookupCount++;
+ }
+
+ if ((op2ClassFromHandle->OperGet() == GT_CNS_INT) && op2ClassFromHandle->IsIconHandle(GTF_ICON_CLASS_HDL))
+ {
+ cls2Hnd = (CORINFO_CLASS_HANDLE)op2ClassFromHandle->gtIntCon.gtCompileTimeHandle;
+ }
+ else if (op2ClassFromHandle->OperGet() == GT_RUNTIMELOOKUP)
+ {
+ cls2Hnd = op2ClassFromHandle->AsRuntimeLookup()->GetClassHandle();
+ runtimeLookupCount++;
+ }
+
+ if ((cls1Hnd != nullptr) && (cls2Hnd != nullptr))
+ {
+ TypeCompareState s = info.compCompHnd->compareTypesForEquality(cls1Hnd, cls2Hnd);
+
+ if (s != TypeCompareState::May)
+ {
+ // Type comparison result is known.
+ const bool typesAreEqual = (s == TypeCompareState::Must);
+ const bool operatorIsEQ = (oper == GT_EQ);
+ const int compareResult = operatorIsEQ ^ typesAreEqual ? 0 : 1;
+ JITDUMP("Runtime reports comparison is known at jit time: %u\n", compareResult);
+ GenTree* result = gtNewIconNode(compareResult);
+
+ // The runtime lookups are now dead code, so we may not
+ // need the generic context kept alive either.
+ assert(lvaGenericsContextUseCount >= runtimeLookupCount);
+ lvaGenericsContextUseCount -= runtimeLookupCount;
+ return result;
+ }
+ }
+
+ // We can't answer definitively at jit time, but can still simplfy the comparison.
GenTree* compare = gtNewOperNode(oper, TYP_INT, op1ClassFromHandle, op2ClassFromHandle);
// Drop any now-irrelvant flags
@@ -13213,6 +13304,11 @@ GenTreePtr Compiler::gtFoldExprConst(GenTreePtr tree)
return tree;
}
+ if (tree->gtOper == GT_RUNTIMELOOKUP)
+ {
+ return tree;
+ }
+
if (kind & GTK_UNOP)
{
assert(op1->OperKind() & GTK_CONST);
diff --git a/src/jit/gentree.h b/src/jit/gentree.h
index e8803e0e1d..60d9080dc6 100644
--- a/src/jit/gentree.h
+++ b/src/jit/gentree.h
@@ -5649,6 +5649,62 @@ struct GenTreeAllocObj final : public GenTreeUnOp
#endif
};
+// Represents GT_RUNTIMELOOKUP node
+
+struct GenTreeRuntimeLookup final : public GenTreeUnOp
+{
+ CORINFO_GENERIC_HANDLE gtHnd;
+ CorInfoGenericHandleType gtHndType;
+
+ GenTreeRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* tree)
+ : GenTreeUnOp(GT_RUNTIMELOOKUP, tree->gtType, tree DEBUGARG(/*largeNode*/ FALSE)), gtHnd(hnd), gtHndType(hndTyp)
+ {
+ assert(hnd != nullptr);
+ }
+#if DEBUGGABLE_GENTREE
+ GenTreeRuntimeLookup() : GenTreeUnOp()
+ {
+ }
+#endif
+
+ // Return reference to the actual tree that does the lookup
+ GenTree*& Lookup()
+ {
+ return gtOp1;
+ }
+
+ bool IsClassHandle() const
+ {
+ return gtHndType == CORINFO_HANDLETYPE_CLASS;
+ }
+ bool IsMethodHandle() const
+ {
+ return gtHndType == CORINFO_HANDLETYPE_METHOD;
+ }
+ bool IsFieldHandle() const
+ {
+ return gtHndType == CORINFO_HANDLETYPE_FIELD;
+ }
+
+ // Note these operations describe the handle that is input to the
+ // lookup, not the handle produced by the lookup.
+ CORINFO_CLASS_HANDLE GetClassHandle() const
+ {
+ assert(IsClassHandle());
+ return (CORINFO_CLASS_HANDLE)gtHnd;
+ }
+ CORINFO_METHOD_HANDLE GetMethodHandle() const
+ {
+ assert(IsMethodHandle());
+ return (CORINFO_METHOD_HANDLE)gtHnd;
+ }
+ CORINFO_FIELD_HANDLE GetFieldHandle() const
+ {
+ assert(IsMethodHandle());
+ return (CORINFO_FIELD_HANDLE)gtHnd;
+ }
+};
+
// Represents a GT_JCC or GT_SETCC node.
struct GenTreeCC final : public GenTree
diff --git a/src/jit/gtlist.h b/src/jit/gtlist.h
index 939f00c334..9ba21a36c8 100644
--- a/src/jit/gtlist.h
+++ b/src/jit/gtlist.h
@@ -99,6 +99,8 @@ GTNODE(ALLOCOBJ , GenTreeAllocObj ,0,GTK_UNOP|GTK_EXOP) // objec
GTNODE(INIT_VAL , GenTreeOp ,0,GTK_UNOP) // Initialization value for an initBlk
+GTNODE(RUNTIMELOOKUP , GenTreeRuntimeLookup, 0,GTK_UNOP|GTK_EXOP) // Runtime handle lookup
+
//-----------------------------------------------------------------------------
// Binary operators (2 operands):
//-----------------------------------------------------------------------------
diff --git a/src/jit/gtstructs.h b/src/jit/gtstructs.h
index 853ccebe9f..02143b49e2 100644
--- a/src/jit/gtstructs.h
+++ b/src/jit/gtstructs.h
@@ -105,6 +105,7 @@ GTSTRUCT_1(PhysReg , GT_PHYSREG)
GTSTRUCT_1(SIMD , GT_SIMD)
#endif // FEATURE_SIMD
GTSTRUCT_1(AllocObj , GT_ALLOCOBJ)
+GTSTRUCT_1(RuntimeLookup, GT_RUNTIMELOOKUP)
GTSTRUCT_2(CC , GT_JCC, GT_SETCC)
#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
#ifdef ARM_SOFTFP
diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
index 7331007621..332abbf1c7 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -1742,8 +1742,17 @@ GenTreePtr Compiler::impTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
}
}
- return impLookupToTree(pResolvedToken, &embedInfo.lookup, gtTokenToIconFlags(pResolvedToken->token),
- embedInfo.compileTimeHandle);
+ // Generate the full lookup tree. May be null if we're abandoning an inline attempt.
+ GenTree* result = impLookupToTree(pResolvedToken, &embedInfo.lookup, gtTokenToIconFlags(pResolvedToken->token),
+ embedInfo.compileTimeHandle);
+
+ // If we have a result and it requires runtime lookup, wrap it in a runtime lookup node.
+ if ((result != nullptr) && embedInfo.lookup.lookupKind.needsRuntimeLookup)
+ {
+ result = gtNewRuntimeLookup(embedInfo.compileTimeHandle, embedInfo.handleType, result);
+ }
+
+ return result;
}
GenTreePtr Compiler::impLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
@@ -14652,20 +14661,25 @@ void Compiler::impImportBlockCode(BasicBlock* block)
// Look ahead for unbox.any
if (codeAddr + (sz + 1 + sizeof(mdToken)) <= codeEndp && codeAddr[sz] == CEE_UNBOX_ANY)
{
- DWORD classAttribs = info.compCompHnd->getClassAttribs(resolvedToken.hClass);
- if (!(classAttribs & CORINFO_FLG_SHAREDINST))
- {
- CORINFO_RESOLVED_TOKEN unboxResolvedToken;
+ CORINFO_RESOLVED_TOKEN unboxResolvedToken;
- impResolveToken(codeAddr + (sz + 1), &unboxResolvedToken, CORINFO_TOKENKIND_Class);
+ impResolveToken(codeAddr + (sz + 1), &unboxResolvedToken, CORINFO_TOKENKIND_Class);
- if (unboxResolvedToken.hClass == resolvedToken.hClass)
- {
- JITDUMP("\n Importing BOX; UNBOX.ANY as NOP\n");
- // Skip the next unbox.any instruction
- sz += sizeof(mdToken) + 1;
- break;
- }
+ // See if token types a equal.
+ const TypeCompareState compare =
+ info.compCompHnd->compareTypesForEquality(unboxResolvedToken.hClass, resolvedToken.hClass);
+
+ // If so, box/unbox.any is a nop.
+ if (compare == TypeCompareState::Must)
+ {
+ JITDUMP("\n Importing BOX; UNBOX.ANY as NOP\n");
+ // Skip the next unbox.any instruction
+ sz += sizeof(mdToken) + 1;
+ break;
+ }
+ else
+ {
+ assert(unboxResolvedToken.hClass != resolvedToken.hClass);
}
}
diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp
index 1bdb2e5716..c4337b6e23 100644
--- a/src/jit/morph.cpp
+++ b/src/jit/morph.cpp
@@ -11990,6 +11990,9 @@ GenTreePtr Compiler::fgMorphSmpOp(GenTreePtr tree, MorphAddrContext* mac)
break;
+ case GT_RUNTIMELOOKUP:
+ return fgMorphTree(op1);
+
#ifdef _TARGET_ARM_
case GT_INTRINSIC:
if (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Round)
diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp
index aa41064198..5a5ff05cd6 100644
--- a/src/vm/jitinterface.cpp
+++ b/src/vm/jitinterface.cpp
@@ -4585,6 +4585,75 @@ BOOL CEEInfo::areTypesEquivalent(
}
/*********************************************************************/
+// See if a cast from fromClass to toClass will succeed, fail, or needs
+// to be resolved at runtime.
+TypeCompareState CEEInfo::compareTypesForCast(
+ CORINFO_CLASS_HANDLE fromClass,
+ CORINFO_CLASS_HANDLE toClass)
+{
+ // Stub for now
+ return TypeCompareState::May;
+}
+
+/*********************************************************************/
+// See if types represented by cls1 and cls2 compare equal, not
+// equal, or the comparison needs to be resolved at runtime.
+TypeCompareState CEEInfo::compareTypesForEquality(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2)
+{
+ CONTRACTL {
+ SO_TOLERANT;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ } CONTRACTL_END;
+
+ TypeCompareState result = TypeCompareState::May;
+
+ JIT_TO_EE_TRANSITION();
+
+ TypeHandle hnd1 = (TypeHandle) cls1;
+ TypeHandle hnd2 = (TypeHandle) cls2;
+
+ // If neither type is a canonical subtype, type handle comparison suffices
+ if (!hnd1.IsCanonicalSubtype() && !hnd2.IsCanonicalSubtype())
+ {
+ result = (hnd1 == hnd2 ? TypeCompareState::Must : TypeCompareState::MustNot);
+ }
+ // If either or both types are canonical subtypes, we can sometimes prove inequality.
+ else
+ {
+ // If either is a value type then the types cannot
+ // be equal unless the type defs are the same.
+ if (hnd1.IsValueType() || hnd2.IsValueType())
+ {
+ if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
+ {
+ result = TypeCompareState::MustNot;
+ }
+ }
+ // If we have two ref types that are not __Canon, then the
+ // types cannot be equal unless the type defs are the same.
+ else
+ {
+ TypeHandle canonHnd = TypeHandle(g_pCanonMethodTableClass);
+ if ((hnd1 != canonHnd) && (hnd2 != canonHnd))
+ {
+ if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
+ {
+ result = TypeCompareState::MustNot;
+ }
+ }
+ }
+ }
+
+ EE_TO_JIT_TRANSITION();
+
+ return result;
+}
+
+/*********************************************************************/
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE CEEInfo::mergeClasses(
CORINFO_CLASS_HANDLE cls1,
diff --git a/src/vm/jitinterface.h b/src/vm/jitinterface.h
index 56394e3016..aa140b00a0 100644
--- a/src/vm/jitinterface.h
+++ b/src/vm/jitinterface.h
@@ -562,6 +562,20 @@ public:
CORINFO_CLASS_HANDLE cls2
);
+ // See if a cast from fromClass to toClass will succeed, fail, or needs
+ // to be resolved at runtime.
+ TypeCompareState compareTypesForCast(
+ CORINFO_CLASS_HANDLE fromClass,
+ CORINFO_CLASS_HANDLE toClass
+ );
+
+ // See if types represented by cls1 and cls2 compare equal, not
+ // equal, or the comparison needs to be resolved at runtime.
+ TypeCompareState compareTypesForEquality(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2
+ );
+
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE mergeClasses(
CORINFO_CLASS_HANDLE cls1,
diff --git a/src/zap/zapinfo.cpp b/src/zap/zapinfo.cpp
index 01d3a3b7cc..4007f678ae 100644
--- a/src/zap/zapinfo.cpp
+++ b/src/zap/zapinfo.cpp
@@ -3107,6 +3107,16 @@ BOOL ZapInfo::areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE
return m_pEEJitInfo->areTypesEquivalent(cls1, cls2);
}
+TypeCompareState ZapInfo::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass)
+{
+ return m_pEEJitInfo->compareTypesForCast(fromClass, toClass);
+}
+
+TypeCompareState ZapInfo::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ return m_pEEJitInfo->compareTypesForEquality(cls1, cls2);
+}
+
CORINFO_CLASS_HANDLE ZapInfo::mergeClasses(
CORINFO_CLASS_HANDLE cls1,
CORINFO_CLASS_HANDLE cls2)
diff --git a/src/zap/zapinfo.h b/src/zap/zapinfo.h
index 5bb86dd88a..f401cbaf9d 100644
--- a/src/zap/zapinfo.h
+++ b/src/zap/zapinfo.h
@@ -573,6 +573,9 @@ public:
CorInfoType getTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls);
BOOL canCast(CORINFO_CLASS_HANDLE child, CORINFO_CLASS_HANDLE parent);
BOOL areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+ TypeCompareState compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass);
+ TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+
CORINFO_CLASS_HANDLE mergeClasses(CORINFO_CLASS_HANDLE cls1,
CORINFO_CLASS_HANDLE cls2);
BOOL shouldEnforceCallvirtRestriction(CORINFO_MODULE_HANDLE scope);