From 1d0cb2900f48dc3dbd9cf3d54852e808a9335f01 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sun, 27 Feb 2022 00:04:14 +0300 Subject: [PATCH 1/7] Use pgo data for isinst/castclass --- src/coreclr/jit/compiler.h | 2 +- src/coreclr/jit/importer.cpp | 64 +++++++++++++++++++++++++++++------- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 2a40b8e84598b..84e30ce479e1d 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4597,7 +4597,7 @@ class Compiler CORINFO_LOOKUP_KIND* pGenericLookupKind = nullptr); bool impIsCastHelperEligibleForClassProbe(GenTree* tree); - bool impIsCastHelperMayHaveProfileData(GenTree* tree); + bool impIsCastHelperMayHaveProfileData(CorInfoHelpFunc helper); GenTree* impCastClassOrIsInstToTree( GenTree* op1, GenTree* op2, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isCastClass, IL_OFFSET ilOffset); diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 3e84db2f91290..2d01125d0bc89 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -2141,21 +2141,17 @@ bool Compiler::impIsCastHelperEligibleForClassProbe(GenTree* tree) // Returns: // true if the tree is a cast helper with potential profile data // -bool Compiler::impIsCastHelperMayHaveProfileData(GenTree* tree) +bool Compiler::impIsCastHelperMayHaveProfileData(CorInfoHelpFunc helper) { - if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT) || (JitConfig.JitCastProfiling() != 1)) + if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT)) { return false; } - if (tree->IsCall() && tree->AsCall()->gtCallType == CT_HELPER) + if ((helper == CORINFO_HELP_ISINSTANCEOFINTERFACE) || (helper == CORINFO_HELP_ISINSTANCEOFCLASS) || + (helper == CORINFO_HELP_CHKCASTCLASS) || (helper == CORINFO_HELP_CHKCASTINTERFACE)) { - const CorInfoHelpFunc helper = eeGetHelperNum(tree->AsCall()->gtCallMethHnd); - if ((helper == CORINFO_HELP_ISINSTANCEOFINTERFACE) || (helper == CORINFO_HELP_ISINSTANCEOFCLASS) || - (helper == CORINFO_HELP_CHKCASTCLASS) || (helper == CORINFO_HELP_CHKCASTINTERFACE)) - { - return true; - } + return true; } return false; } @@ -11561,8 +11557,11 @@ GenTree* Compiler::impCastClassOrIsInstToTree( // Pessimistically assume the jit cannot expand this as an inline test bool canExpandInline = false; + bool partialExpand = false; const CorInfoHelpFunc helper = info.compCompHnd->getCastingHelper(pResolvedToken, isCastClass); + GenTree* exactCls = nullptr; + // Legality check. // // Not all classclass/isinst operations can be inline expanded. @@ -11582,6 +11581,42 @@ GenTree* Compiler::impCastClassOrIsInstToTree( canExpandInline = impIsClassExact(pResolvedToken->hClass); } } + + if (impIsCastHelperMayHaveProfileData(helper)) + { + LikelyClassRecord likelyClass[1]; // multiple guesses aren't yet supported + if (getLikelyClasses(likelyClass, 1, fgPgoSchema, fgPgoSchemaCount, fgPgoData, ilOffset) > 0) + { + assert(likelyClass != nullptr); + CORINFO_CLASS_HANDLE likelyCls = likelyClass->clsHandle; + + if ((likelyCls != NO_CLASS_HANDLE) && + (likelyClass->likelihood > (UINT32)JitConfig.JitGuardedDevirtualizationChainLikelihood())) + { + if (isCastClass && canExpandInline && likelyCls == pResolvedToken->hClass) + { + // likelyClass is the same as declared - castclass is going to use the latter + // as a fast path anyway so do nothing here. + } + else if ((info.compCompHnd->compareTypesForEquality(likelyCls, likelyCls) == + TypeCompareState::Must) && + (info.compCompHnd->compareTypesForCast(likelyCls, pResolvedToken->hClass) == + TypeCompareState::Must)) + { + const UINT32 attrs = info.compCompHnd->getClassAttribs(likelyCls); + assert((attrs & (CORINFO_FLG_INTERFACE | CORINFO_FLG_ABSTRACT)) == 0); + JITDUMP("Adding \"is %s (%X)\" check as a fast path for %s using PGO data.\n", + eeGetClassName(likelyCls), likelyCls, isCastClass ? "castclass" : "isinst"); + + canExpandInline = true; + partialExpand = true; + exactCls = gtNewIconEmbClsHndNode(likelyCls); + + printf("!!! EGOR::::::::: %s -> %s\n", info.compMethodName, eeGetClassName(likelyCls)); + } + } + } + } } const bool expandInline = canExpandInline && shouldExpandInline; @@ -11633,13 +11668,13 @@ GenTree* Compiler::impCastClassOrIsInstToTree( // GenTree* op2Var = op2; - if (isCastClass) + if (isCastClass && !partialExpand) { op2Var = fgInsertCommaFormTemp(&op2); lvaTable[op2Var->AsLclVarCommon()->GetLclNum()].lvIsCSE = true; } temp = gtNewMethodTableLookup(temp); - condMT = gtNewOperNode(GT_NE, TYP_INT, temp, op2); + condMT = gtNewOperNode(GT_NE, TYP_INT, temp, exactCls != nullptr ? exactCls : op2); GenTree* condNull; // @@ -11664,7 +11699,12 @@ GenTree* Compiler::impCastClassOrIsInstToTree( // const CorInfoHelpFunc specialHelper = CORINFO_HELP_CHKCASTCLASS_SPECIAL; - condTrue = gtNewHelperCallNode(specialHelper, TYP_REF, gtNewCallArgs(op2Var, gtClone(op1))); + condTrue = + gtNewHelperCallNode(specialHelper, TYP_REF, gtNewCallArgs(partialExpand ? op2 : op2Var, gtClone(op1))); + } + else if (partialExpand) + { + condTrue = gtNewHelperCallNode(helper, TYP_REF, gtNewCallArgs(op2, gtClone(op1))); } else { From 1d25f00adcb06adebb1fed6e9cf3408eec46f918 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sun, 27 Feb 2022 01:04:03 +0300 Subject: [PATCH 2/7] Clean up --- src/coreclr/jit/importer.cpp | 24 ++++++++---------------- src/coreclr/jit/jitconfigvalues.h | 2 +- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 2d01125d0bc89..240b4c404de6b 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -11582,6 +11582,7 @@ GenTree* Compiler::impCastClassOrIsInstToTree( } } + // Check if this cast helper have some profile data if (impIsCastHelperMayHaveProfileData(helper)) { LikelyClassRecord likelyClass[1]; // multiple guesses aren't yet supported @@ -11593,26 +11594,17 @@ GenTree* Compiler::impCastClassOrIsInstToTree( if ((likelyCls != NO_CLASS_HANDLE) && (likelyClass->likelihood > (UINT32)JitConfig.JitGuardedDevirtualizationChainLikelihood())) { - if (isCastClass && canExpandInline && likelyCls == pResolvedToken->hClass) + if ((info.compCompHnd->compareTypesForCast(likelyCls, pResolvedToken->hClass) == + TypeCompareState::Must)) { - // likelyClass is the same as declared - castclass is going to use the latter - // as a fast path anyway so do nothing here. - } - else if ((info.compCompHnd->compareTypesForEquality(likelyCls, likelyCls) == - TypeCompareState::Must) && - (info.compCompHnd->compareTypesForCast(likelyCls, pResolvedToken->hClass) == - TypeCompareState::Must)) - { - const UINT32 attrs = info.compCompHnd->getClassAttribs(likelyCls); - assert((attrs & (CORINFO_FLG_INTERFACE | CORINFO_FLG_ABSTRACT)) == 0); + assert((info.compCompHnd->getClassAttribs(likelyCls) & + (CORINFO_FLG_INTERFACE | CORINFO_FLG_ABSTRACT)) == 0); JITDUMP("Adding \"is %s (%X)\" check as a fast path for %s using PGO data.\n", - eeGetClassName(likelyCls), likelyCls, isCastClass ? "castclass" : "isinst"); + eeGetClassName(likelyCls), likelyCls, isCastClass ? "castclass" : "isinst"); canExpandInline = true; - partialExpand = true; - exactCls = gtNewIconEmbClsHndNode(likelyCls); - - printf("!!! EGOR::::::::: %s -> %s\n", info.compMethodName, eeGetClassName(likelyCls)); + partialExpand = true; + exactCls = gtNewIconEmbClsHndNode(likelyCls); } } } diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index 051fcc4affd33..b7f4384166ecc 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -486,7 +486,7 @@ CONFIG_STRING(JitEnablePatchpointRange, W("JitEnablePatchpointRange")) // Profile instrumentation options CONFIG_INTEGER(JitMinimalJitProfiling, W("JitMinimalJitProfiling"), 1) CONFIG_INTEGER(JitMinimalPrejitProfiling, W("JitMinimalPrejitProfiling"), 0) -CONFIG_INTEGER(JitCastProfiling, W("JitCastProfiling"), 0) // Profile castclass and isinst +CONFIG_INTEGER(JitCastProfiling, W("JitCastProfiling"), 1) // CI test, will disable it back CONFIG_INTEGER(JitClassProfiling, W("JitClassProfiling"), 1) // Profile virtual and interface calls CONFIG_INTEGER(JitEdgeProfiling, W("JitEdgeProfiling"), 1) // Profile edges instead of blocks CONFIG_INTEGER(JitCollect64BitCounts, W("JitCollect64BitCounts"), 0) // Collect counts as 64-bit values. From eaceff1cc5a65fe1e01742eaec1bd7011d0ccdea Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sun, 27 Feb 2022 01:45:32 +0300 Subject: [PATCH 3/7] formatting --- src/coreclr/jit/jitconfigvalues.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index b7f4384166ecc..ea86590b110c1 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -486,7 +486,7 @@ CONFIG_STRING(JitEnablePatchpointRange, W("JitEnablePatchpointRange")) // Profile instrumentation options CONFIG_INTEGER(JitMinimalJitProfiling, W("JitMinimalJitProfiling"), 1) CONFIG_INTEGER(JitMinimalPrejitProfiling, W("JitMinimalPrejitProfiling"), 0) -CONFIG_INTEGER(JitCastProfiling, W("JitCastProfiling"), 1) // CI test, will disable it back +CONFIG_INTEGER(JitCastProfiling, W("JitCastProfiling"), 1) // CI test, will disable it back CONFIG_INTEGER(JitClassProfiling, W("JitClassProfiling"), 1) // Profile virtual and interface calls CONFIG_INTEGER(JitEdgeProfiling, W("JitEdgeProfiling"), 1) // Profile edges instead of blocks CONFIG_INTEGER(JitCollect64BitCounts, W("JitCollect64BitCounts"), 0) // Collect counts as 64-bit values. From 1d0a7235ff6ad5fc689a2ca05eca83ce755a9173 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 16 Mar 2022 20:31:53 +0300 Subject: [PATCH 4/7] Add tests --- src/coreclr/jit/importer.cpp | 46 +++- src/coreclr/jit/jitconfigvalues.h | 6 +- .../ProfileCastClassAndIsInst.cs | 214 ++++++++++++++++++ .../ProfileCastClassAndIsInst.csproj | 23 ++ .../ProfileCastClassAndIsInst_random1.csproj | 25 ++ .../ProfileCastClassAndIsInst_random2.csproj | 25 ++ .../ProfileCastClassAndIsInst_random3.csproj | 25 ++ 7 files changed, 356 insertions(+), 8 deletions(-) create mode 100644 src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst.cs create mode 100644 src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst.csproj create mode 100644 src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random1.csproj create mode 100644 src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random2.csproj create mode 100644 src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random3.csproj diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 1f27fc567067b..5b122b6fae3ef 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -2114,7 +2114,7 @@ GenTree* Compiler::impReadyToRunLookupToTree(CORINFO_CONST_LOOKUP* pLookup, // bool Compiler::impIsCastHelperEligibleForClassProbe(GenTree* tree) { - if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR) || (JitConfig.JitCastProfiling() != 1)) + if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR) || (JitConfig.JitProfileCasts() != 1)) { return false; } @@ -2143,6 +2143,11 @@ bool Compiler::impIsCastHelperEligibleForClassProbe(GenTree* tree) // bool Compiler::impIsCastHelperMayHaveProfileData(CorInfoHelpFunc helper) { + if (JitConfig.JitConsumeProfileForCasts() == 0) + { + return false; + } + if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT)) { return false; @@ -11604,7 +11609,7 @@ GenTree* Compiler::impCastClassOrIsInstToTree( // not worth creating an untracked local variable shouldExpandInline = false; } - else if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR) && (JitConfig.JitCastProfiling() == 1)) + else if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR) && (JitConfig.JitProfileCasts() == 1)) { // Optimizations are enabled but we're still instrumenting (including casts) if (isCastClass && !impIsClassExact(pResolvedToken->hClass)) @@ -11645,14 +11650,41 @@ GenTree* Compiler::impCastClassOrIsInstToTree( // Check if this cast helper have some profile data if (impIsCastHelperMayHaveProfileData(helper)) { - LikelyClassRecord likelyClass[1]; // multiple guesses aren't yet supported - if (getLikelyClasses(likelyClass, 1, fgPgoSchema, fgPgoSchemaCount, fgPgoData, ilOffset) > 0) + bool doRandomDevirt = false; + const int maxLikelyClasses = 32; + int likelyClassCount = 0; + LikelyClassRecord likelyClasses[maxLikelyClasses]; +#ifdef DEBUG + // Optional stress mode to pick a random known class, rather than + // the most likely known class. + doRandomDevirt = JitConfig.JitRandomGuardedDevirtualization() != 0; + + if (doRandomDevirt) + { + // Reuse the random inliner's random state. + CLRRandom* const random = + impInlineRoot()->m_inlineStrategy->GetRandom(JitConfig.JitRandomGuardedDevirtualization()); + likelyClasses[0].clsHandle = getRandomClass(fgPgoSchema, fgPgoSchemaCount, fgPgoData, ilOffset, random); + likelyClasses[0].likelihood = 100; + if (likelyClasses[0].clsHandle != NO_CLASS_HANDLE) + { + likelyClassCount = 1; + } + } + else +#endif + { + likelyClassCount = getLikelyClasses(likelyClasses, maxLikelyClasses, fgPgoSchema, fgPgoSchemaCount, + fgPgoData, ilOffset); + } + + if (likelyClassCount > 0) { - assert(likelyClass != nullptr); - CORINFO_CLASS_HANDLE likelyCls = likelyClass->clsHandle; + LikelyClassRecord likelyClass = likelyClasses[0]; + CORINFO_CLASS_HANDLE likelyCls = likelyClass.clsHandle; if ((likelyCls != NO_CLASS_HANDLE) && - (likelyClass->likelihood > (UINT32)JitConfig.JitGuardedDevirtualizationChainLikelihood())) + (likelyClass.likelihood > (UINT32)JitConfig.JitGuardedDevirtualizationChainLikelihood())) { if ((info.compCompHnd->compareTypesForCast(likelyCls, pResolvedToken->hClass) == TypeCompareState::Must)) diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index 6fea4da68164d..a21a342c50632 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -491,7 +491,11 @@ CONFIG_STRING(JitEnablePatchpointRange, W("JitEnablePatchpointRange")) // Profile instrumentation options CONFIG_INTEGER(JitMinimalJitProfiling, W("JitMinimalJitProfiling"), 1) CONFIG_INTEGER(JitMinimalPrejitProfiling, W("JitMinimalPrejitProfiling"), 0) -CONFIG_INTEGER(JitCastProfiling, W("JitCastProfiling"), 1) // CI test, will disable it back + +CONFIG_INTEGER(JitProfileCasts, W("JitProfileCasts"), 1) // Profile castclass/isinst +CONFIG_INTEGER(JitConsumeProfileForCasts, W("JitConsumeProfileForCasts"), 1) // Consume profile data (if any) for + // castclass/isinst + CONFIG_INTEGER(JitClassProfiling, W("JitClassProfiling"), 1) // Profile virtual and interface calls CONFIG_INTEGER(JitEdgeProfiling, W("JitEdgeProfiling"), 1) // Profile edges instead of blocks CONFIG_INTEGER(JitCollect64BitCounts, W("JitCollect64BitCounts"), 0) // Collect counts as 64-bit values. diff --git a/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst.cs b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst.cs new file mode 100644 index 0000000000000..3b48f7d462d16 --- /dev/null +++ b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst.cs @@ -0,0 +1,214 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading; + +public interface IInterface { } +public interface IGenericInterface { } +public class ClassA : IInterface { } +public class ClassB : ClassA { } +public class ClassC { } +public struct GenericStruct : IGenericInterface { } + +public class Program +{ + // 1. Cast to Class + [MethodImpl(MethodImplOptions.NoInlining)] + static ClassA CastToClassA(object o) => (ClassA)o; + + [MethodImpl(MethodImplOptions.NoInlining)] + static GenericStruct CastToGenericStruct(object o) => (GenericStruct)o; + + [MethodImpl(MethodImplOptions.NoInlining)] + static int[] CastToArray(object o) => (int[])o; + + // 2. Is Instance of Class + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool IsClassA(object o) => o is ClassA; + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool IsGenericStruct(object o) => o is GenericStruct; + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool IsArray(object o) => o is int[]; + + // 3. Is Instance of Interface + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool IsIInterface(object o) => o is IInterface; + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool IsGenericInterface(object o) => o is IGenericInterface; + + // 4. Cast to Interface + + [MethodImpl(MethodImplOptions.NoInlining)] + static IInterface CastToIInterface(object o) => (IInterface)o; + + [MethodImpl(MethodImplOptions.NoInlining)] + static IGenericInterface CastToGenericInterface(object o) => (IGenericInterface)o; + + + [MethodImpl(MethodImplOptions.NoInlining)] + static void AssertThrows(Action action, [CallerLineNumber] int line = 0) where T : Exception + { + try + { + action(); + } + catch (T) + { + return; + } + throw new InvalidOperationException("InvalidCastException was expected"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool AssertEquals(T t1, T t2) + { + return EqualityComparer.Default.Equals(t1, t2); + } + + public static int Main() + { + var a = new ClassA(); + var b = new ClassB(); + var c = new ClassC(); + var gsInt = new GenericStruct(); + var gsString = new GenericStruct(); + var arrayOfUInt32 = new uint[100]; + var arrayOfInt32 = new int[100]; + var arrayOfString = new string[100]; + + for (int i = 0; i < 200; i++) + { + AssertEquals(IsArray(arrayOfUInt32), true); + AssertEquals(IsArray(arrayOfInt32), true); + AssertEquals(IsArray(arrayOfString), false); + AssertEquals(IsArray(a), false); + AssertEquals(IsArray(b), false); + AssertEquals(IsArray(c), false); + AssertEquals(IsArray(gsInt), false); + AssertEquals(IsArray(gsString), false); + AssertEquals(IsArray(null), false); + + AssertEquals(IsClassA(arrayOfUInt32), false); + AssertEquals(IsClassA(arrayOfInt32), false); + AssertEquals(IsClassA(arrayOfString), false); + AssertEquals(IsClassA(a), true); + AssertEquals(IsClassA(b), false); + AssertEquals(IsClassA(c), false); + AssertEquals(IsClassA(gsInt), false); + AssertEquals(IsClassA(gsString), false); + AssertEquals(IsClassA(null), false); + + AssertEquals(IsGenericStruct(arrayOfUInt32), false); + AssertEquals(IsGenericStruct(arrayOfInt32), false); + AssertEquals(IsGenericStruct(arrayOfString), false); + AssertEquals(IsGenericStruct(a), true); + AssertEquals(IsGenericStruct(b), false); + AssertEquals(IsGenericStruct(c), false); + AssertEquals(IsGenericStruct(gsInt), false); + AssertEquals(IsGenericStruct(gsString), false); + AssertEquals(IsGenericStruct(arrayOfUInt32), false); + AssertEquals(IsGenericStruct(arrayOfInt32), false); + AssertEquals(IsGenericStruct(arrayOfString), false); + AssertEquals(IsGenericStruct(a), true); + AssertEquals(IsGenericStruct(b), false); + AssertEquals(IsGenericStruct(c), false); + AssertEquals(IsGenericStruct(gsInt), false); + AssertEquals(IsGenericStruct(null), false); + + AssertEquals(IsGenericInterface(arrayOfUInt32), false); + AssertEquals(IsGenericInterface(arrayOfInt32), false); + AssertEquals(IsGenericInterface(arrayOfString), false); + AssertEquals(IsGenericInterface(a), true); + AssertEquals(IsGenericInterface(b), false); + AssertEquals(IsGenericInterface(c), false); + AssertEquals(IsGenericInterface(gsInt), false); + AssertEquals(IsGenericInterface(gsString), false); + AssertEquals(IsGenericInterface(arrayOfUInt32), false); + AssertEquals(IsGenericInterface(arrayOfInt32), false); + AssertEquals(IsGenericInterface(arrayOfString), false); + AssertEquals(IsGenericInterface(a), true); + AssertEquals(IsGenericInterface(b), false); + AssertEquals(IsGenericInterface(c), false); + AssertEquals(IsGenericInterface(gsInt), false); + AssertEquals(IsGenericInterface(gsString), false); + AssertEquals(IsGenericInterface(null), false); + + AssertEquals(IsIInterface(arrayOfUInt32), false); + AssertEquals(IsIInterface(arrayOfInt32), false); + AssertEquals(IsIInterface(arrayOfString), false); + AssertEquals(IsIInterface(a), true); + AssertEquals(IsIInterface(b), false); + AssertEquals(IsIInterface(c), false); + AssertEquals(IsIInterface(gsInt), false); + AssertEquals(IsIInterface(gsString), false); + AssertEquals(IsIInterface(null), false); + + AssertThrows(() => CastToClassA(gsInt)); + AssertThrows(() => CastToClassA(gsString)); + AssertThrows(() => CastToClassA(arrayOfUInt32)); + AssertThrows(() => CastToClassA(arrayOfInt32)); + AssertThrows(() => CastToClassA(arrayOfString)); + + AssertThrows(() => CastToArray(a)); + AssertThrows(() => CastToArray(b)); + AssertThrows(() => CastToArray(c)); + AssertThrows(() => CastToArray(gsInt)); + AssertThrows(() => CastToArray(gsString)); + + AssertEquals(CastToIInterface(a), a); + AssertEquals(CastToIInterface(b), b); + AssertThrows(() => CastToIInterface(c)); + AssertThrows(() => CastToIInterface(gsInt)); + AssertThrows(() => CastToIInterface(gsString)); + AssertThrows(() => CastToIInterface(arrayOfUInt32)); + AssertThrows(() => CastToIInterface(arrayOfInt32)); + AssertThrows(() => CastToIInterface(arrayOfString)); + + AssertThrows(() => CastToGenericInterface(a)); + AssertThrows(() => CastToGenericInterface(b)); + AssertThrows(() => CastToGenericInterface(c)); + AssertEquals(CastToGenericInterface(gsInt), gsInt); + AssertThrows(() => CastToGenericInterface(gsString)); + AssertThrows(() => CastToGenericInterface(arrayOfUInt32)); + AssertThrows(() => CastToGenericInterface(arrayOfInt32)); + AssertThrows(() => CastToGenericInterface(arrayOfString)); + AssertThrows(() => CastToGenericInterface(a)); + AssertThrows(() => CastToGenericInterface(b)); + AssertThrows(() => CastToGenericInterface(c)); + AssertThrows(() => CastToGenericInterface(gsInt)); + AssertEquals(CastToGenericInterface(gsString), gsString); + AssertThrows(() => CastToGenericInterface(arrayOfUInt32)); + AssertThrows(() => CastToGenericInterface(arrayOfInt32)); + AssertThrows(() => CastToGenericInterface(arrayOfString)); + + AssertThrows(() => CastToGenericStruct(a)); + AssertThrows(() => CastToGenericStruct(b)); + AssertThrows(() => CastToGenericStruct(c)); + AssertEquals(CastToGenericStruct(gsInt), gsInt); + AssertThrows(() => CastToGenericStruct(gsString)); + AssertThrows(() => CastToGenericStruct(arrayOfUInt32)); + AssertThrows(() => CastToGenericStruct(arrayOfInt32)); + AssertThrows(() => CastToGenericStruct(arrayOfString)); + AssertThrows(() => CastToGenericStruct(a)); + AssertThrows(() => CastToGenericStruct(b)); + AssertThrows(() => CastToGenericStruct(c)); + AssertThrows(() => CastToGenericStruct(gsInt)); + AssertEquals(CastToGenericStruct(gsString), gsString); + AssertThrows(() => CastToGenericStruct(arrayOfUInt32)); + AssertThrows(() => CastToGenericStruct(arrayOfInt32)); + AssertThrows(() => CastToGenericStruct(arrayOfString)); + AssertThrows(() => CastToGenericStruct(null)); + + Thread.Sleep(20); + } + return 100; + } +} diff --git a/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst.csproj b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst.csproj new file mode 100644 index 0000000000000..f584e2fb22c53 --- /dev/null +++ b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst.csproj @@ -0,0 +1,23 @@ + + + Exe + True + + + + + + + \ No newline at end of file diff --git a/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random1.csproj b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random1.csproj new file mode 100644 index 0000000000000..25e7ca356d051 --- /dev/null +++ b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random1.csproj @@ -0,0 +1,25 @@ + + + Exe + True + + + + + + + \ No newline at end of file diff --git a/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random2.csproj b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random2.csproj new file mode 100644 index 0000000000000..4ecfdc5b43f53 --- /dev/null +++ b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random2.csproj @@ -0,0 +1,25 @@ + + + Exe + True + + + + + + + \ No newline at end of file diff --git a/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random3.csproj b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random3.csproj new file mode 100644 index 0000000000000..cd5816a89650e --- /dev/null +++ b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random3.csproj @@ -0,0 +1,25 @@ + + + Exe + True + + + + + + + \ No newline at end of file From cf570db64dbee3870bc261e6037ccc7e99cfcc9c Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Mon, 21 Mar 2022 12:18:53 +0300 Subject: [PATCH 5/7] Update ProfileCastClassAndIsInst_random1.csproj --- .../ProfileCastClassAndIsInst_random1.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random1.csproj b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random1.csproj index 25e7ca356d051..62cbb33acda72 100644 --- a/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random1.csproj +++ b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random1.csproj @@ -20,6 +20,6 @@ ]]> - + - \ No newline at end of file + From d4a83b38e0fa3591f68ab225e4c36e31ec273109 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Mon, 21 Mar 2022 12:19:11 +0300 Subject: [PATCH 6/7] Update ProfileCastClassAndIsInst_random2.csproj --- .../ProfileCastClassAndIsInst_random2.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random2.csproj b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random2.csproj index 4ecfdc5b43f53..b4139f2f1d0b1 100644 --- a/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random2.csproj +++ b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random2.csproj @@ -20,6 +20,6 @@ ]]> - + - \ No newline at end of file + From 52c3d04baf7a64e75ff3d49c6ee0a9e289b3752c Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Mon, 21 Mar 2022 12:19:24 +0300 Subject: [PATCH 7/7] Update ProfileCastClassAndIsInst_random3.csproj --- .../ProfileCastClassAndIsInst_random3.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random3.csproj b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random3.csproj index cd5816a89650e..71e099150b57b 100644 --- a/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random3.csproj +++ b/src/tests/JIT/PGO/ProfileCastClassAndIsInst/ProfileCastClassAndIsInst_random3.csproj @@ -20,6 +20,6 @@ ]]> - + - \ No newline at end of file +