// CORINFO_FLG_VALUECLASS, except faster.
BOOL isValueClass(CORINFO_CLASS_HANDLE cls);
+// Decides how the JIT should do the optimization to inline the check for
+// GetTypeFromHandle(handle) == obj.GetType() (for CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE)
+// GetTypeFromHandle(X) == GetTypeFromHandle(Y) (for CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN)
+CorInfoInlineTypeCheck canInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source);
+
// If this method returns true, JIT will do optimization to inline the check for
// GetTypeFromHandle(handle) == obj.GetType()
BOOL canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE cls);
LWM(CanGetCookieForPInvokeCalliSig, CanGetCookieForPInvokeCalliSigValue, DWORD)
LWM(CanGetVarArgsHandle, CanGetVarArgsHandleValue, DWORD)
LWM(CanInline, DLDL, Agnostic_CanInline)
+LWM(CanInlineTypeCheck, DLD, DWORD)
LWM(CanInlineTypeCheckWithObjectVTable, DWORDLONG, DWORD)
LWM(CanSkipMethodVerification, DLD, DWORD)
LWM(CanTailCall, Agnostic_CanTailCall, DWORD)
return (const char*)GetFieldName->GetBuffer(value.A);
}
+void MethodContext::recCanInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source, CorInfoInlineTypeCheck result)
+{
+ if (CanInlineTypeCheck == nullptr)
+ CanInlineTypeCheck = new LightWeightMap<DLD, DWORD>();
+
+ DLD key;
+ ZeroMemory(&key, sizeof(DLD)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+
+ key.A = (DWORDLONG)cls;
+ key.B = (DWORD)source;
+
+ CanInlineTypeCheck->Add(key, (DWORD)result);
+}
+void MethodContext::dmpCanInlineTypeCheck(DLD key, DWORD value)
+{
+ printf("CanInlineTypeCheck key cls-%016llX src-%08X, value res-%u", key.A, key.B, value);
+}
+CorInfoInlineTypeCheck MethodContext::repCanInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source)
+{
+ AssertCodeMsg(CanInlineTypeCheck != nullptr, EXCEPTIONCODE_MC,
+ "No map for CanInlineTypeCheck");
+
+ DLD key;
+ ZeroMemory(&key, sizeof(DLD)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+
+ key.A = (DWORDLONG)cls;
+ key.B = (DWORD)source;
+
+ return (CorInfoInlineTypeCheck)CanInlineTypeCheck->Get(key);
+}
+
void MethodContext::recCanInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE cls, BOOL result)
{
if (CanInlineTypeCheckWithObjectVTable == nullptr)
void dmpGetFieldName(DWORDLONG key, DD value);
const char* repGetFieldName(CORINFO_FIELD_HANDLE ftn, const char** moduleName);
+ void recCanInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source, CorInfoInlineTypeCheck result);
+ void dmpCanInlineTypeCheck(DLD key, DWORD value);
+ CorInfoInlineTypeCheck repCanInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source);
void recCanInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE cls, BOOL result);
void dmpCanInlineTypeCheckWithObjectVTable(DWORDLONG key, DWORD value);
BOOL repCanInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE cls);
};
// ********************* Please keep this up-to-date to ease adding more ***************
-// Highest packet number: 172
+// Highest packet number: 173
// *************************************************************************************
enum mcPackets
{
Packet_CanGetCookieForPInvokeCalliSig = 7,
Packet_CanGetVarArgsHandle = 8,
Packet_CanInline = 9,
+ Packet_CanInlineTypeCheck = 173, // Added 11/15/2018 as a replacement for CanInlineTypeCheckWithObjectVTable
Packet_CanInlineTypeCheckWithObjectVTable = 10,
Packet_CanSkipMethodVerification = 11,
Packet_CanTailCall = 12,
return temp;
}
+// Decides how the JIT should do the optimization to inline the check for
+// GetTypeFromHandle(handle) == obj.GetType() (for CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE)
+// GetTypeFromHandle(X) == GetTypeFromHandle(Y) (for CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN)
+CorInfoInlineTypeCheck interceptor_ICJI::canInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source)
+{
+ mc->cr->AddCall("canInlineTypeCheck");
+ CorInfoInlineTypeCheck temp = original_ICorJitInfo->canInlineTypeCheck(cls, source);
+ mc->recCanInlineTypeCheck(cls, source, temp);
+ return temp;
+}
+
// If this method returns true, JIT will do optimization to inline the check for
// GetTypeFromHandle(handle) == obj.GetType()
BOOL interceptor_ICJI::canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE cls)
return original_ICorJitInfo->isValueClass(cls);
}
+// Decides how the JIT should do the optimization to inline the check for
+// GetTypeFromHandle(handle) == obj.GetType() (for CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE)
+// GetTypeFromHandle(X) == GetTypeFromHandle(Y) (for CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN)
+CorInfoInlineTypeCheck interceptor_ICJI::canInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source)
+{
+ mcs->AddCall("canInlineTypeCheck");
+ return original_ICorJitInfo->canInlineTypeCheck(cls, source);
+}
+
// If this method returns true, JIT will do optimization to inline the check for
// GetTypeFromHandle(handle) == obj.GetType()
BOOL interceptor_ICJI::canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE cls)
return original_ICorJitInfo->isValueClass(cls);
}
+// Decides how the JIT should do the optimization to inline the check for
+// GetTypeFromHandle(handle) == obj.GetType() (for CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE)
+// GetTypeFromHandle(X) == GetTypeFromHandle(Y) (for CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN)
+CorInfoInlineTypeCheck interceptor_ICJI::canInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source)
+{
+ return original_ICorJitInfo->canInlineTypeCheck(cls, source);
+}
+
// If this method returns true, JIT will do optimization to inline the check for
// GetTypeFromHandle(handle) == obj.GetType()
BOOL interceptor_ICJI::canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE cls)
return jitInstance->mc->repIsValueClass(cls);
}
+// Decides how the JIT should do the optimization to inline the check for
+// GetTypeFromHandle(handle) == obj.GetType() (for CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE)
+// GetTypeFromHandle(X) == GetTypeFromHandle(Y) (for CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN)
+CorInfoInlineTypeCheck MyICJI::canInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source)
+{
+ jitInstance->mc->cr->AddCall("canInlineTypeCheck");
+ return jitInstance->mc->repCanInlineTypeCheck(cls, source);
+}
+
// If this method returns true, JIT will do optimization to inline the check for
// GetTypeFromHandle(handle) == obj.GetType()
BOOL MyICJI::canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE cls)
#define SELECTANY extern __declspec(selectany)
#endif
-SELECTANY const GUID JITEEVersionIdentifier = { /* b2da2a6e-72fa-4730-b47c-4c9275e1c5ce */
- 0xb2da2a6e,
- 0x72fa,
- 0x4730,
- {0xb4, 0x7c, 0x4c, 0x92, 0x75, 0xe1, 0xc5, 0xce}
+SELECTANY const GUID JITEEVersionIdentifier = { /* 09F7AAE2-07DF-4433-B8C5-BA864CCABDA3 */
+ 0x9f7aae2,
+ 0x7df,
+ 0x4433,
+ {0xb8, 0xc5, 0xba, 0x86, 0x4c, 0xca, 0xbd, 0xa3}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
CORINFO_HELP_RUNTIMEHANDLE_CLASS, // determine a type/field/method handle at run-time
CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG, // determine a type/field/method handle at run-time, with IBC logging
- // These helpers are required for MDIL backward compatibility only. They are not used by current JITed code.
- CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_OBSOLETE, // Convert from a TypeHandle (native structure pointer) to RuntimeTypeHandle at run-time
- CORINFO_HELP_METHODDESC_TO_RUNTIMEMETHODHANDLE_OBSOLETE, // Convert from a MethodDesc (native structure pointer) to RuntimeMethodHandle at run-time
- CORINFO_HELP_FIELDDESC_TO_RUNTIMEFIELDHANDLE_OBSOLETE, // Convert from a FieldDesc (native structure pointer) to RuntimeFieldHandle at run-time
-
CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, // Convert from a TypeHandle (native structure pointer) to RuntimeType at run-time
CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL, // Convert from a TypeHandle (native structure pointer) to RuntimeType at run-time, the type may be null
CORINFO_HELP_METHODDESC_TO_STUBRUNTIMEMETHOD, // Convert from a MethodDesc (native structure pointer) to RuntimeMethodHandle at run-time
CORINFO_HELP_FIELDDESC_TO_STUBRUNTIMEFIELD, // Convert from a FieldDesc (native structure pointer) to RuntimeFieldHandle at run-time
+ CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE, // Convert from a TypeHandle (native structure pointer) to RuntimeTypeHandle at run-time
+ CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL, // Convert from a TypeHandle (native structure pointer) to RuntimeTypeHandle at run-time, handle might point to a null type
+
+ CORINFO_HELP_ARE_TYPES_EQUIVALENT, // Check whether two TypeHandles (native structure pointers) are equivalent
CORINFO_HELP_VIRTUAL_FUNC_PTR, // look up a virtual method at run-time
//CORINFO_HELP_VIRTUAL_FUNC_PTR_LOG, // look up a virtual method at run-time, with IBC logging
INLINE_SAME_THIS = 0x00000004, // You can inline only if the callee is on the same this reference as caller
};
+enum CorInfoInlineTypeCheck
+{
+ CORINFO_INLINE_TYPECHECK_NONE = 0x00000000, // It's not okay to compare type's vtable with a native type handle
+ CORINFO_INLINE_TYPECHECK_PASS = 0x00000001, // It's okay to compare type's vtable with a native type handle
+ CORINFO_INLINE_TYPECHECK_USE_HELPER = 0x00000002, // Use a specialized helper to compare type's vtable with native type handle
+};
+
+enum CorInfoInlineTypeCheckSource
+{
+ CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE = 0x00000000, // Type handle comes from the vtable
+ CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN = 0x00000001, // Type handle comes from an ldtoken
+};
// If you add more values here, keep it in sync with TailCallTypeMap in ..\vm\ClrEtwAll.man
// and the string enum in CEEInfo::reportTailCallDecision in ..\vm\JITInterface.cpp
// Quick check whether the type is a value class. Returns the same value as getClassAttribs(cls) & CORINFO_FLG_VALUECLASS, except faster.
virtual BOOL isValueClass(CORINFO_CLASS_HANDLE cls) = 0;
+ // Decides how the JIT should do the optimization to inline the check for
+ // GetTypeFromHandle(handle) == obj.GetType() (for CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE)
+ // GetTypeFromHandle(X) == GetTypeFromHandle(Y) (for CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN)
+ virtual CorInfoInlineTypeCheck canInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source) = 0;
+
// If this method returns true, JIT will do optimization to inline the check for
// GetTypeFromHandle(handle) == obj.GetType()
virtual BOOL canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE cls) = 0;
JITHELPER(CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG,JIT_GenericHandleMethodLogging, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_RUNTIMEHANDLE_CLASS, JIT_GenericHandleClass, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG, JIT_GenericHandleClassLogging, CORINFO_HELP_SIG_REG_ONLY)
- JITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_OBSOLETE, NULL, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
- JITHELPER(CORINFO_HELP_METHODDESC_TO_RUNTIMEMETHODHANDLE_OBSOLETE, NULL, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
- JITHELPER(CORINFO_HELP_FIELDDESC_TO_RUNTIMEFIELDHANDLE_OBSOLETE, NULL, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
JITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, JIT_GetRuntimeType, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL, JIT_GetRuntimeType_MaybeNull, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_METHODDESC_TO_STUBRUNTIMEMETHOD, JIT_GetRuntimeMethodStub,CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_FIELDDESC_TO_STUBRUNTIMEFIELD, JIT_GetRuntimeFieldStub, CORINFO_HELP_SIG_REG_ONLY)
+ JITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE, JIT_GetRuntimeType, CORINFO_HELP_SIG_REG_ONLY)
+ JITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL, JIT_GetRuntimeType_MaybeNull, CORINFO_HELP_SIG_REG_ONLY)
+
+ JITHELPER(CORINFO_HELP_ARE_TYPES_EQUIVALENT, NULL, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_VIRTUAL_FUNC_PTR, JIT_VirtualFunctionPointer, CORINFO_HELP_SIG_4_STACK)
//JITHELPER(CORINFO_HELP_VIRTUAL_FUNC_PTR_LOG,JIT_VirtualFunctionPointerLogging)
DEF_CLR_API(getTypeInstantiationArgument)
DEF_CLR_API(appendClassName)
DEF_CLR_API(isValueClass)
+DEF_CLR_API(canInlineTypeCheck)
DEF_CLR_API(canInlineTypeCheckWithObjectVTable)
DEF_CLR_API(getClassAttribs)
DEF_CLR_API(isStructRequiringStackAllocRetBuf)
return temp;
}
+CorInfoInlineTypeCheck canInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source)
+{
+ API_ENTER(canInlineTypeCheck);
+ CorInfoInlineTypeCheck temp = wrapHnd->canInlineTypeCheck(cls, source);
+ API_LEAVE(canInlineTypeCheck);
+ return temp;
+}
+
BOOL WrapICorJitInfo::canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE cls)
{
API_ENTER(canInlineTypeCheckWithObjectVTable);
gtFoldExprConst(GenTree* tree);
GenTree* gtFoldExprSpecial(GenTree* tree);
GenTree* gtFoldExprCompare(GenTree* tree);
+ GenTree* gtCreateHandleCompare(genTreeOps oper,
+ GenTree* op1,
+ GenTree* op2,
+ CorInfoInlineTypeCheck typeCheckInliningResult);
GenTree* gtFoldExprCall(GenTreeCall* call);
GenTree* gtFoldTypeCompare(GenTree* tree);
GenTree* gtFoldTypeEqualityCall(CorInfoIntrinsics methodID, GenTree* op1, GenTree* op2);
TypeProducerKind gtGetTypeProducerKind(GenTree* tree);
bool gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call);
+ bool gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper = nullptr);
bool gtIsActiveCSE_Candidate(GenTree* tree);
#ifdef DEBUG
// For the ones below no extra argument matters for comparison.
case GT_BOX:
+ case GT_RUNTIMELOOKUP:
break;
default:
}
//------------------------------------------------------------------------
+// gtCreateHandleCompare: generate a type handle comparison
+//
+// Arguments:
+// oper -- comparison operation (equal/not equal)
+// op1 -- first operand
+// op2 -- second operand
+// typeCheckInliningResult -- indicates how the comparison should happen
+//
+// Returns:
+// Type comparison tree
+//
+
+GenTree* Compiler::gtCreateHandleCompare(genTreeOps oper,
+ GenTree* op1,
+ GenTree* op2,
+ CorInfoInlineTypeCheck typeCheckInliningResult)
+{
+ // If we can compare pointers directly, just emit the binary operation
+ if (typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_PASS)
+ {
+ return gtNewOperNode(oper, TYP_INT, op1, op2);
+ }
+
+ assert(typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_USE_HELPER);
+
+ // Emit a call to a runtime helper
+ GenTreeArgList* helperArgs = gtNewArgList(op1, op2);
+ GenTree* ret = gtNewHelperCallNode(CORINFO_HELP_ARE_TYPES_EQUIVALENT, TYP_INT, helperArgs);
+ if (oper == GT_EQ)
+ {
+ ret = gtNewOperNode(GT_NE, TYP_INT, ret, gtNewIconNode(0, TYP_INT));
+ }
+ else
+ {
+ assert(oper == GT_NE);
+ ret = gtNewOperNode(GT_EQ, TYP_INT, ret, gtNewIconNode(0, TYP_INT));
+ }
+
+ return ret;
+}
+
+//------------------------------------------------------------------------
// gtFoldTypeCompare: see if a type comparison can be further simplified
//
// Arguments:
// We can't answer the equality comparison definitively at jit
// time, but can still simplfy the comparison.
//
+ // Find out how we can compare the two handles.
+ // NOTE: We're potentially passing NO_CLASS_HANDLE, but the runtime knows what to do with it here.
+ CorInfoInlineTypeCheck inliningKind =
+ info.compCompHnd->canInlineTypeCheck(cls1Hnd, CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN);
+
+ // If the first type needs helper, check the other type: it might be okay with a simple compare.
+ if (inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER)
+ {
+ inliningKind = info.compCompHnd->canInlineTypeCheck(cls2Hnd, CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN);
+ }
+
+ assert(inliningKind == CORINFO_INLINE_TYPECHECK_PASS || inliningKind == CORINFO_INLINE_TYPECHECK_USE_HELPER);
+
// If we successfully tunneled through both operands, compare
// the tunneled values, otherwise compare the original values.
- GenTree* compare = nullptr;
+ GenTree* compare;
if ((op1TunneledHandle != nullptr) && (op2TunneledHandle != nullptr))
{
- compare = gtNewOperNode(oper, TYP_INT, op1TunneledHandle, op2TunneledHandle);
+ compare = gtCreateHandleCompare(oper, op1TunneledHandle, op2TunneledHandle, inliningKind);
}
else
{
- compare = gtNewOperNode(oper, TYP_INT, op1ClassFromHandle, op2ClassFromHandle);
+ compare = gtCreateHandleCompare(oper, op1ClassFromHandle, op2ClassFromHandle, inliningKind);
}
// Drop any now-irrelvant flags
// Ask the VM if this type can be equality tested by a simple method
// table comparison.
- if (!info.compCompHnd->canInlineTypeCheckWithObjectVTable(clsHnd))
+ CorInfoInlineTypeCheck typeCheckInliningResult =
+ info.compCompHnd->canInlineTypeCheck(clsHnd, CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE);
+ if (typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_NONE)
{
return tree;
}
optMethodFlags |= OMF_HAS_VTABLEREF;
// Compare the two method tables
- GenTree* const compare = gtNewOperNode(oper, TYP_INT, objMT, knownMT);
+ GenTree* const compare = gtCreateHandleCompare(oper, objMT, knownMT, typeCheckInliningResult);
// Drop any any now irrelevant flags
compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL);
}
+//------------------------------------------------------------------------
+// gtIsTypeHandleToRuntimeTypeHandleHelperCall -- see if tree is constructing
+// a RuntimeTypeHandle from a handle
+//
+// Arguments:
+// tree - tree to examine
+// pHelper - optional pointer to a variable that receives the type of the helper
+//
+// Return Value:
+// True if so
+
+bool Compiler::gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper)
+{
+ CorInfoHelpFunc helper = CORINFO_HELP_UNDEF;
+
+ if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE))
+ {
+ helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE;
+ }
+ else if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL))
+ {
+ helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL;
+ }
+
+ if (pHelper != nullptr)
+ {
+ *pHelper = helper;
+ }
+
+ return helper != CORINFO_HELP_UNDEF;
+}
+
bool Compiler::gtIsActiveCSE_Candidate(GenTree* tree)
{
return (optValnumCSE_phase && IS_CSE_INDEX(tree->gtCSEnum));
case CORINFO_INTRINSIC_GetTypeFromHandle:
op1 = impStackTop(0).val;
+ CorInfoHelpFunc typeHandleHelper;
if (op1->gtOper == GT_CALL && (op1->gtCall.gtCallType == CT_HELPER) &&
- gtIsTypeHandleToRuntimeTypeHelper(op1->AsCall()))
+ gtIsTypeHandleToRuntimeTypeHandleHelper(op1->AsCall(), &typeHandleHelper))
{
op1 = impPopStack().val;
- // Change call to return RuntimeType directly.
+ // Replace helper with a more specialized helper that returns RuntimeType
+ if (typeHandleHelper == CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE)
+ {
+ typeHandleHelper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE;
+ }
+ else
+ {
+ assert(typeHandleHelper == CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL);
+ typeHandleHelper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL;
+ }
+ assert(op1->gtCall.gtCallArgs->gtOp.gtOp2 == nullptr);
+ op1 = gtNewHelperCallNode(typeHandleHelper, TYP_REF, op1->gtCall.gtCallArgs);
op1->gtType = TYP_REF;
retNode = op1;
}
case CORINFO_INTRINSIC_RTH_GetValueInternal:
op1 = impStackTop(0).val;
if (op1->gtOper == GT_CALL && (op1->gtCall.gtCallType == CT_HELPER) &&
- gtIsTypeHandleToRuntimeTypeHelper(op1->AsCall()))
+ gtIsTypeHandleToRuntimeTypeHandleHelper(op1->AsCall()))
{
// Old tree
// Helper-RuntimeTypeHandle -> TreeToGetNativeTypeHandle
if (call->IsCall())
{
GenTreeCall* callNode = call->AsCall();
- if ((callNode->gtCallType == CT_HELPER) && gtIsTypeHandleToRuntimeTypeHelper(callNode))
+ if ((callNode->gtCallType == CT_HELPER) && (gtIsTypeHandleToRuntimeTypeHelper(callNode) ||
+ gtIsTypeHandleToRuntimeTypeHandleHelper(callNode)))
{
spillStack = false;
}
{
GenTreeArgList* helperArgs = gtNewArgList(op1);
- op1 = gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL, TYP_STRUCT, helperArgs);
+ op1 = gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL, TYP_STRUCT,
+ helperArgs);
// The handle struct is returned in register
op1->gtCall.gtReturnType = GetRuntimeHandleUnderlyingType();
return;
}
- helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE;
+ helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE;
assert(resolvedToken.hClass != nullptr);
if (resolvedToken.hMethod != nullptr)
case CORINFO_HELP_ISINSTANCEOFANY:
case CORINFO_HELP_READYTORUN_ISINSTANCEOF:
case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE:
+ case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE:
isPure = true;
noThrow = true; // These return null for a failing cast
break;
+ case CORINFO_HELP_ARE_TYPES_EQUIVALENT:
+
+ isPure = true;
+ noThrow = true;
+ break;
+
// type casting helpers that throw
case CORINFO_HELP_CHKCASTINTERFACE:
case CORINFO_HELP_CHKCASTARRAY:
vnf = VNF_TypeHandleToRuntimeType;
break;
+ case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE:
+ vnf = VNF_TypeHandleToRuntimeTypeHandle;
+ break;
+
+ case CORINFO_HELP_ARE_TYPES_EQUIVALENT:
+ vnf = VNF_AreTypesEquivalent;
+ break;
+
case CORINFO_HELP_READYTORUN_ISINSTANCEOF:
vnf = VNF_ReadyToRunIsInstanceOf;
break;
ValueNumFuncDef(ReadyToRunCastClass, 2, false, false, false) // Args: 0: Helper stub address, 1: object being cast.
ValueNumFuncDef(ReadyToRunIsInstanceOf, 2, false, false, false) // Args: 0: Helper stub address, 1: object being queried.
ValueNumFuncDef(TypeHandleToRuntimeType, 1, false, false, false) // Args: 0: TypeHandle to translate
+ValueNumFuncDef(TypeHandleToRuntimeTypeHandle, 1, false, false, false) // Args: 0: TypeHandle to translate
+
+ValueNumFuncDef(AreTypesEquivalent, 2, false, false, false) // Args: 0: first TypeHandle, 1: second TypeHandle
ValueNumFuncDef(LdElemA, 3, false, false, false) // Args: 0: array value; 1: index value; 2: type handle of element.
}
/*********************************************************************/
+// Decides how the JIT should do the optimization to inline the check for
+// GetTypeFromHandle(handle) == obj.GetType() (for CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE)
+// GetTypeFromHandle(X) == GetTypeFromHandle(Y) (for CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN)
+//
+// This will enable to use directly the typehandle instead of going through getClassByHandle
+CorInfoInlineTypeCheck CEEInfo::canInlineTypeCheck(CORINFO_CLASS_HANDLE clsHnd, CorInfoInlineTypeCheckSource source)
+{
+ CONTRACTL {
+ SO_TOLERANT;
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_PREEMPTIVE;
+ } CONTRACTL_END;
+
+ CorInfoInlineTypeCheck ret;
+
+ JIT_TO_EE_TRANSITION_LEAF();
+
+ if (source == CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN)
+ {
+ // It's always okay to compare type handles coming from IL tokens
+ ret = CORINFO_INLINE_TYPECHECK_PASS;
+ }
+ else
+ {
+ _ASSERTE(source == CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE);
+ ret = canInlineTypeCheckWithObjectVTable(clsHnd) ?
+ CORINFO_INLINE_TYPECHECK_PASS : CORINFO_INLINE_TYPECHECK_NONE;
+ }
+
+ EE_TO_JIT_TRANSITION_LEAF();
+
+ return(ret);
+}
+
+/*********************************************************************/
// If this method returns true, JIT will do optimization to inline the check for
-// GetClassFromHandle(handle) == obj.GetType()
+// GetTypeFromHandle(handle) == obj.GetType()
//
// This will enable to use directly the typehandle instead of going through getClassByHandle
BOOL CEEInfo::canInlineTypeCheckWithObjectVTable (CORINFO_CLASS_HANDLE clsHnd)
BOOL fFullInst,
BOOL fAssembly);
BOOL isValueClass (CORINFO_CLASS_HANDLE cls);
+ CorInfoInlineTypeCheck canInlineTypeCheck (CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source);
BOOL canInlineTypeCheckWithObjectVTable (CORINFO_CLASS_HANDLE cls);
DWORD getClassAttribs (CORINFO_CLASS_HANDLE cls);
return m_pEEJitInfo->isValueClass(cls);
}
+CorInfoInlineTypeCheck ZapInfo::canInlineTypeCheck (CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source)
+{
+ return m_pEEJitInfo->canInlineTypeCheck(cls, source);
+}
+
BOOL ZapInfo::canInlineTypeCheckWithObjectVTable (CORINFO_CLASS_HANDLE cls)
{
return m_pEEJitInfo->canInlineTypeCheckWithObjectVTable(cls);
BOOL fFullInst,
BOOL fAssembly);
BOOL isValueClass(CORINFO_CLASS_HANDLE clsHnd);
+ CorInfoInlineTypeCheck canInlineTypeCheck(CORINFO_CLASS_HANDLE cls, CorInfoInlineTypeCheckSource source);
BOOL canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE clsHnd);
DWORD getClassAttribs(CORINFO_CLASS_HANDLE cls);
BOOL isStructRequiringStackAllocRetBuf(CORINFO_CLASS_HANDLE cls);