Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

JIT: More type equality opts #14317

Merged
merged 2 commits into from
Oct 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 2 additions & 0 deletions src/ToolBox/superpmi/superpmi-shared/lwmlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
66 changes: 66 additions & 0 deletions src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
12 changes: 11 additions & 1 deletion src/ToolBox/superpmi/superpmi-shared/methodcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,14 @@ class MethodContext
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);
Expand Down Expand Up @@ -1257,7 +1265,7 @@ class MethodContext
};

// ********************* Please keep this up-to-date to ease adding more ***************
// Highest packet number: 162
// Highest packet number: 164
// *************************************************************************************
enum mcPackets
{
Expand All @@ -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,
Expand Down
20 changes: 20 additions & 0 deletions src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
16 changes: 16 additions & 0 deletions src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
14 changes: 14 additions & 0 deletions src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
16 changes: 16 additions & 0 deletions src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
33 changes: 27 additions & 6 deletions src/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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}
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another possibility here is:

Incongruent,
Unknown,
Congruent,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In particular the usage of May is confusing as it represents the lack of knowledge.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to mention this when we were chatting offline: these names match the ones used a in similar .NetNative extension of the jit interface. So am going to keep them as is...

};

//
// This interface is logically split into sections for each class of information
// (ICorMethodInfo, ICorModuleInfo, etc.). This split used to exist physically as well
Expand Down Expand Up @@ -2492,6 +2499,20 @@ class ICorStaticInfo
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,
Expand Down
3 changes: 3 additions & 0 deletions src/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2119,6 +2119,8 @@ class Compiler

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

Expand Down Expand Up @@ -9769,6 +9771,7 @@ class GenTreeVisitor
case GT_RETURN:
case GT_RETFILT:
case GT_PHI:
case GT_RUNTIMELOOKUP:
{
GenTreeUnOp* const unOp = node->AsUnOp();
if (unOp->gtOp1 != nullptr)
Expand Down
17 changes: 17 additions & 0 deletions src/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading