READYTORUN_HELPER_GenericGcTlsBase = 0x66,
READYTORUN_HELPER_GenericNonGcTlsBase = 0x67,
READYTORUN_HELPER_VirtualFuncPtr = 0x68,
+ READYTORUN_HELPER_IsInstanceOfException = 0x69,
// Long mul/div/shift ops
READYTORUN_HELPER_LMul = 0xC0,
CORINFO_HELP_CHKCASTCLASS_SPECIAL, // Optimized helper for classes. Assumes that the trivial cases
// has been taken care of by the inlined check
+ CORINFO_HELP_ISINSTANCEOF_EXCEPTION,
+
CORINFO_HELP_BOX, // Fast box helper. Only possible exception is OutOfMemory
CORINFO_HELP_BOX_NULLABLE, // special form of boxing for Nullable<T>
CORINFO_HELP_UNBOX,
#define GUID_DEFINED
#endif // !GUID_DEFINED
-constexpr GUID JITEEVersionIdentifier = { /* 0d853657-7a01-421f-b1b0-d22a8e691441 */
- 0x0d853657,
- 0x7a01,
- 0x421f,
- {0xb1, 0xb0, 0xd2, 0x2a, 0x8e, 0x69, 0x14, 0x41}
+constexpr GUID JITEEVersionIdentifier = { /* 4efa8fe2-8489-4b61-aac9-b4df74af15b7 */
+ 0x4efa8fe2,
+ 0x8489,
+ 0x4b61,
+ {0xaa, 0xc9, 0xb4, 0xdf, 0x74, 0xaf, 0x15, 0xb7}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
DYNAMICJITHELPER(CORINFO_HELP_CHKCASTANY, NULL, CORINFO_HELP_SIG_REG_ONLY)
DYNAMICJITHELPER(CORINFO_HELP_CHKCASTCLASS_SPECIAL, NULL, CORINFO_HELP_SIG_REG_ONLY)
+ JITHELPER(CORINFO_HELP_ISINSTANCEOF_EXCEPTION, JIT_IsInstanceOfException, CORINFO_HELP_SIG_REG_ONLY)
+
DYNAMICJITHELPER(CORINFO_HELP_BOX, JIT_Box, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_BOX_NULLABLE, JIT_Box, CORINFO_HELP_SIG_REG_ONLY)
DYNAMICJITHELPER(CORINFO_HELP_UNBOX, NULL, CORINFO_HELP_SIG_REG_ONLY)
// Keep these in sync with src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs
#define READYTORUN_MAJOR_VERSION 0x0007
-#define READYTORUN_MINOR_VERSION 0x0000
+#define READYTORUN_MINOR_VERSION 0x0001
#define MINIMUM_READYTORUN_MAJOR_VERSION 0x006
READYTORUN_HELPER_GenericGcTlsBase = 0x66,
READYTORUN_HELPER_GenericNonGcTlsBase = 0x67,
READYTORUN_HELPER_VirtualFuncPtr = 0x68,
+ READYTORUN_HELPER_IsInstanceOfException = 0x69,
// Long mul/div/shift ops
READYTORUN_HELPER_LMul = 0xC0,
HELPER(READYTORUN_HELPER_GenericNonGcTlsBase, CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE,)
HELPER(READYTORUN_HELPER_VirtualFuncPtr, CORINFO_HELP_VIRTUAL_FUNC_PTR, )
+HELPER(READYTORUN_HELPER_IsInstanceOfException, CORINFO_HELP_ISINSTANCEOF_EXCEPTION, )
HELPER(READYTORUN_HELPER_LMul, CORINFO_HELP_LMUL, )
HELPER(READYTORUN_HELPER_LMulOfv, CORINFO_HELP_LMUL_OVF, )
bool fgNormalizeEHCase2();
bool fgNormalizeEHCase3();
+ void fgCreateFiltersForGenericExceptions();
+
void fgCheckForLoopsInHandlers();
#ifdef DEBUG
{
noway_assert(!compIsForInlining());
+ // For runtime determined Exception types we're going to emit a fake EH filter with isinst for this
+ // type with a runtime lookup
+ fgCreateFiltersForGenericExceptions();
+
// The backend requires a scratch BB into which it can safely insert a P/Invoke method prolog if one is
// required. Similarly, we need a scratch BB for poisoning. Create it here.
if (compMethodRequiresPInvokeFrame() || compShouldPoisonFrame())
return modified;
}
+//------------------------------------------------------------------------
+// fgCreateFiltersForGenericExceptions:
+// For Exception types which require runtime lookup it creates a "fake" single-block
+// EH filter that performs "catchArg isinst T!!" and in case of success forwards to the
+// original EH handler.
+//
+
+void Compiler::fgCreateFiltersForGenericExceptions()
+{
+ for (unsigned ehNum = 0; ehNum < compHndBBtabCount; ehNum++)
+ {
+ EHblkDsc* eh = ehGetDsc(ehNum);
+ if (eh->ebdHandlerType == EH_HANDLER_CATCH)
+ {
+ // Resolve Exception type and check if it needs a runtime lookup
+ CORINFO_RESOLVED_TOKEN resolvedToken;
+ resolvedToken.tokenContext = impTokenLookupContextHandle;
+ resolvedToken.tokenScope = info.compScopeHnd;
+ resolvedToken.token = eh->ebdTyp;
+ resolvedToken.tokenType = CORINFO_TOKENKIND_Casting;
+ info.compCompHnd->resolveToken(&resolvedToken);
+
+ CORINFO_GENERICHANDLE_RESULT embedInfo;
+ info.compCompHnd->embedGenericHandle(&resolvedToken, true, &embedInfo);
+ if (!embedInfo.lookup.lookupKind.needsRuntimeLookup)
+ {
+ // Exception type does not need runtime lookup
+ continue;
+ }
+
+ // Create a new bb for the fake filter
+ BasicBlock* filterBb = bbNewBasicBlock(BBJ_EHFILTERRET);
+ BasicBlock* handlerBb = eh->ebdHndBeg;
+
+ // Now we need to spill CATCH_ARG (it should be the first thing evaluated)
+ GenTree* arg = new (this, GT_CATCH_ARG) GenTree(GT_CATCH_ARG, TYP_REF);
+ arg->gtFlags |= GTF_ORDER_SIDEEFF;
+ unsigned tempNum = lvaGrabTemp(false DEBUGARG("SpillCatchArg"));
+ lvaTable[tempNum].lvType = TYP_REF;
+ GenTree* argAsg = gtNewTempAssign(tempNum, arg);
+ arg = gtNewLclvNode(tempNum, TYP_REF);
+ fgInsertStmtAtBeg(filterBb, gtNewStmt(argAsg, handlerBb->firstStmt()->GetDebugInfo()));
+
+ // Create "catchArg is TException" tree
+ GenTree* runtimeLookup;
+ if (embedInfo.lookup.runtimeLookup.indirections == CORINFO_USEHELPER)
+ {
+ GenTree* ctxTree = getRuntimeContextTree(embedInfo.lookup.lookupKind.runtimeLookupKind);
+ runtimeLookup = impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_GENERIC_HANDLE,
+ TYP_I_IMPL, &embedInfo.lookup.lookupKind, ctxTree);
+ }
+ else
+ {
+ runtimeLookup = getTokenHandleTree(&resolvedToken, true);
+ }
+ GenTree* isInstOfT = gtNewHelperCallNode(CORINFO_HELP_ISINSTANCEOF_EXCEPTION, TYP_INT, runtimeLookup, arg);
+ GenTree* retFilt = gtNewOperNode(GT_RETFILT, TYP_INT, isInstOfT);
+
+ // Insert it right before the handler (and make it a pred of the handler)
+ fgInsertBBbefore(handlerBb, filterBb);
+ fgAddRefPred(handlerBb, filterBb);
+ fgNewStmtAtEnd(filterBb, retFilt, handlerBb->firstStmt()->GetDebugInfo());
+
+ filterBb->bbCatchTyp = BBCT_FILTER;
+ filterBb->bbCodeOffs = handlerBb->bbCodeOffs;
+ filterBb->bbHndIndex = handlerBb->bbHndIndex;
+ filterBb->bbTryIndex = handlerBb->bbTryIndex;
+ filterBb->bbJumpDest = handlerBb;
+ filterBb->bbSetRunRarely();
+ filterBb->bbFlags |= BBF_INTERNAL | BBF_DONT_REMOVE;
+
+ handlerBb->bbCatchTyp = BBCT_FILTER_HANDLER;
+ eh->ebdHandlerType = EH_HANDLER_FILTER;
+ eh->ebdFilter = filterBb;
+
+#ifdef DEBUG
+ if (verbose)
+ {
+ JITDUMP("EH%d: Adding EH filter block " FMT_BB " in front of generic handler " FMT_BB ":\n", ehNum,
+ filterBb->bbNum, handlerBb->bbNum);
+ fgDumpBlock(filterBb);
+ }
+#endif // DEBUG
+ }
+ }
+}
+
bool Compiler::fgNormalizeEHCase3()
{
bool modified = false;
AssertNotRuntimeObject(pClauseType);
#endif
- return TypeCast.IsInstanceOfClass(pClauseType, exception) != null;
+ return TypeCast.IsInstanceOfException(pClauseType, exception);
}
private static void InvokeSecondPass(ref ExInfo exInfo, uint idxStart)
return IsInstanceOfClass(pTargetType, obj);
}
+ [RuntimeExport("RhTypeCast_IsInstanceOfException")]
+ public static unsafe bool IsInstanceOfException(MethodTable* pTargetType, object? obj)
+ {
+ // Based on IsInstanceOfClass_Helper
+
+ if (obj == null)
+ return false;
+
+ MethodTable* pObjType = obj.GetMethodTable();
+
+ if (pTargetType->IsCloned)
+ pTargetType = pTargetType->CanonicalEEType;
+
+ if (pObjType->IsCloned)
+ pObjType = pObjType->CanonicalEEType;
+
+ if (pObjType == pTargetType)
+ return true;
+
+ // arrays can be cast to System.Object and System.Array
+ if (pObjType->IsArray)
+ return WellKnownEETypes.IsSystemObject(pTargetType) || WellKnownEETypes.IsSystemArray(pTargetType);
+
+ while (true)
+ {
+ pObjType = pObjType->NonClonedNonArrayBaseType;
+ if (pObjType == null)
+ return false;
+
+ if (pObjType->IsCloned)
+ pObjType = pObjType->CanonicalEEType;
+
+ if (pObjType == pTargetType)
+ return true;
+ }
+ }
+
[RuntimeExport("RhTypeCast_CheckCast")]
public static unsafe object CheckCast(MethodTable* pTargetType, object obj)
{
static const uint32_t Signature = 0x00525452; // 'RTR'
static const uint32_t CurrentMajorVersion = 7;
- static const uint32_t CurrentMinorVersion = 0;
+ static const uint32_t CurrentMinorVersion = 1;
};
struct ReadyToRunHeader
[RuntimeImport(RuntimeLibrary, "RhTypeCast_IsInstanceOfInterface")]
internal static extern unsafe object IsInstanceOfInterface(MethodTable* pTargetType, object obj);
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ [RuntimeImport(RuntimeLibrary, "RhTypeCast_IsInstanceOfException")]
+ internal static extern unsafe bool IsInstanceOfException(MethodTable* pTargetType, object obj);
+
internal static unsafe object IsInstanceOfInterface(EETypePtr pTargetType, object obj)
=> IsInstanceOfInterface(pTargetType.ToPointer(), obj);
public const uint Signature = 0x00525452; // 'RTR'
public const ushort CurrentMajorVersion = 7;
- public const ushort CurrentMinorVersion = 0;
+ public const ushort CurrentMinorVersion = 1;
}
#pragma warning disable 0169
GenericGcTlsBase = 0x66,
GenericNonGcTlsBase = 0x67,
VirtualFuncPtr = 0x68,
+ IsInstanceOfException = 0x69,
// Long mul/div/shift ops
LMul = 0xC0,
CORINFO_HELP_CHKCASTCLASS_SPECIAL, // Optimized helper for classes. Assumes that the trivial cases
// has been taken care of by the inlined check
+ CORINFO_HELP_ISINSTANCEOF_EXCEPTION,
+
CORINFO_HELP_BOX, // Fast box helper. Only possible exception is OutOfMemory
CORINFO_HELP_BOX_NULLABLE, // special form of boxing for Nullable<T>
CORINFO_HELP_UNBOX,
Get_CORINFO_SIG_INFO(method, sig: &methodInfo->args, methodIL);
Get_CORINFO_SIG_INFO(methodIL.GetLocals(), &methodInfo->locals);
-#if READYTORUN
- if ((methodInfo->options & CorInfoOptions.CORINFO_GENERICS_CTXT_MASK) != 0)
- {
- foreach (var region in exceptionRegions)
- {
- if (region.Kind == ILExceptionRegionKind.Catch)
- {
- TypeDesc catchType = (TypeDesc)methodIL.GetObject(region.ClassToken);
- if (catchType.IsCanonicalSubtype(CanonicalFormKind.Any))
- {
- methodInfo->options |= CorInfoOptions.CORINFO_GENERICS_CTXT_KEEP_ALIVE;
- break;
- }
- }
- }
- }
-#endif
-
return true;
}
case ReadyToRunHelper.CheckInstanceAny:
mangledName = "RhTypeCast_IsInstanceOf";
break;
+ case ReadyToRunHelper.IsInstanceOfException:
+ mangledName = "RhTypeCast_IsInstanceOfException";
+ break;
case ReadyToRunHelper.CheckCastInterface:
mangledName = "RhTypeCast_CheckCastInterface";
break;
if (region.Kind == ILExceptionRegionKind.Filter)
MarkBasicBlock(_basicBlocks[region.FilterOffset]);
- // Once https://github.com/dotnet/corert/issues/3460 is done, this should be deleted.
- // Throwing InvalidProgram is not great, but we want to do *something* if this happens
- // because doing nothing means problems at runtime. This is not worth piping a
- // a new exception with a fancy message for.
if (region.Kind == ILExceptionRegionKind.Catch)
{
TypeDesc catchType = (TypeDesc)_methodIL.GetObject(region.ClassToken);
if (catchType.IsRuntimeDeterminedSubtype)
- ThrowHelper.ThrowInvalidProgramException();
+ {
+ // For runtime determined Exception types we're going to emit a fake EH filter with isinst for this
+ // type with a runtime lookup
+ _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.TypeHandleForCasting, catchType), "EH filter");
+ }
}
}
}
id = ReadyToRunHelper.GetRuntimeTypeHandle;
break;
+ case CorInfoHelpFunc.CORINFO_HELP_ISINSTANCEOF_EXCEPTION:
+ id = ReadyToRunHelper.IsInstanceOfException;
+ break;
case CorInfoHelpFunc.CORINFO_HELP_BOX:
id = ReadyToRunHelper.Box;
break;
builder.Append("CHECK_INSTANCE_ANY");
break;
+ case ReadyToRunHelper.IsInstanceOfException:
+ builder.Append("SIMPLE_ISINSTANCE_OF");
+ break;
+
case ReadyToRunHelper.GenericGcStaticBase:
builder.Append("GENERIC_GC_STATIC_BASE");
break;
id = ReadyToRunHelper.AreTypesEquivalent;
break;
+ case CorInfoHelpFunc.CORINFO_HELP_ISINSTANCEOF_EXCEPTION:
+ id = ReadyToRunHelper.IsInstanceOfException;
+ break;
case CorInfoHelpFunc.CORINFO_HELP_BOX:
id = ReadyToRunHelper.Box;
break;
var methodIL = (MethodIL)HandleToObject((IntPtr)_methodScope);
var type = (TypeDesc)methodIL.GetObject((int)clause.ClassTokenOrOffset);
- // Once https://github.com/dotnet/corert/issues/3460 is done, this should be an assert.
- // Throwing InvalidProgram is not great, but we want to do *something* if this happens
- // because doing nothing means problems at runtime. This is not worth piping a
- // a new exception with a fancy message for.
- if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
- ThrowHelper.ThrowInvalidProgramException();
-
var typeSymbol = _compilation.NecessaryTypeSymbolIfPossible(type);
RelocType rel = (_compilation.NodeFactory.Target.IsWindows) ?
PREFIX_ASSUME(pModule != NULL);
SigTypeContext typeContext(pMD);
- VarKind k = hasNoVars;
-
- // In the vast majority of cases the code under the "if" below
- // will not be executed.
- //
- // First grab the representative instantiations. For code
- // shared by multiple generic instantiations these are the
- // canonical (representative) instantiation.
- if (TypeFromToken(typeTok) == mdtTypeSpec)
- {
- PCCOR_SIGNATURE pSig;
- ULONG cSig;
- IfFailThrow(pModule->GetMDImport()->GetTypeSpecFromToken(typeTok, &pSig, &cSig));
-
- SigPointer psig(pSig, cSig);
- k = psig.IsPolyType(&typeContext);
-
- // Grab the active class and method instantiation. This exact instantiation is only
- // needed in the corner case of "generic" exception catching in shared
- // generic code. We don't need the exact instantiation if the token
- // doesn't contain E_T_VAR or E_T_MVAR.
- if ((k & hasSharableVarsMask) != 0)
- {
- Instantiation classInst;
- Instantiation methodInst;
- pCf->GetExactGenericInstantiations(&classInst, &methodInst);
- SigTypeContext::InitTypeContext(pMD,classInst, methodInst,&typeContext);
- }
- }
-
return ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule, typeTok, &typeContext,
ClassLoader::ReturnNullIfNotFound);
}
PREFIX_ASSUME(pModule != NULL);
SigTypeContext typeContext(pMD);
- VarKind k = hasNoVars;
-
mdToken typeTok = pEHClause->ClassToken;
-
- // In the vast majority of cases the code un der the "if" below
- // will not be executed.
- //
- // First grab the representative instantiations. For code
- // shared by multiple generic instantiations these are the
- // canonical (representative) instantiation.
- if (TypeFromToken(typeTok) == mdtTypeSpec)
- {
- PCCOR_SIGNATURE pSig;
- ULONG cSig;
- IfFailThrow(pModule->GetMDImport()->GetTypeSpecFromToken(typeTok, &pSig, &cSig));
-
- SigPointer psig(pSig, cSig);
- k = psig.IsPolyType(&typeContext);
-
- // Grab the active class and method instantiation. This exact instantiation is only
- // needed in the corner case of "generic" exception catching in shared
- // generic code. We don't need the exact instantiation if the token
- // doesn't contain E_T_VAR or E_T_MVAR.
- if ((k & hasSharableVarsMask) != 0)
- {
- Instantiation classInst;
- Instantiation methodInst;
- pCf->GetExactGenericInstantiations(&classInst,&methodInst);
- SigTypeContext::InitTypeContext(pMD,classInst, methodInst,&typeContext);
- }
- }
-
return ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule, typeTok, &typeContext,
ClassLoader::ReturnNullIfNotFound);
}
FCALL_CONTRACT;
TypeHandle clsHnd(type);
-
// <TODO>@TODO right now we check for precisely the correct type.
// do we want to allow inheritance? (watch out since value
// classes inherit from object but do not normal object layout).</TODO>
HCIMPLEND
+/*************************************************************/
+HCIMPL2(BOOL, JIT_IsInstanceOfException, CORINFO_CLASS_HANDLE type, Object* obj)
+{
+ FCALL_CONTRACT;
+ TypeHandle clsHnd(type);
+ return ExceptionIsOfRightType(clsHnd, obj->GetTypeHandle());
+}
+HCIMPLEND
+
+
//========================================================================
//
// GENERICS HELPERS
{
methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
}
- else
#endif // defined(PROFILING_SUPPORTED)
- {
- // Check all the exception clauses
-
- if (ftn->IsDynamicMethod())
- {
- // @TODO: how do we detect the need to mark this flag?
- }
- else
- {
- COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
-
- for (unsigned i = 0; i < methInfo->EHcount; i++)
- {
- const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo =
- (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)header->EH->EHClause(i, &ehClause);
-
- // Is it a typed catch clause?
- if (ehInfo->GetFlags() != COR_ILEXCEPTION_CLAUSE_NONE)
- continue;
-
- // Check if we catch "C<T>" ?
-
- DWORD catchTypeToken = ehInfo->GetClassToken();
- if (TypeFromToken(catchTypeToken) != mdtTypeSpec)
- continue;
-
- PCCOR_SIGNATURE pSig;
- ULONG cSig;
- IfFailThrow(ftn->GetMDImport()->GetTypeSpecFromToken(catchTypeToken, &pSig, &cSig));
-
- SigPointer psig(pSig, cSig);
-
- SigTypeContext sigTypeContext(ftn);
- if (psig.IsPolyType(&sigTypeContext) & hasSharableVarsMask)
- {
- methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
- break;
- }
- }
- }
- }
}
PCCOR_SIGNATURE pSig = NULL;
#ifndef DACCESS_COMPILE
-// Does this type contain class or method type parameters whose instantiation cannot
-// be determined at JIT-compile time from the instantiations in the method context?
-// Return a combination of hasClassVar and hasMethodVar flags.
-// See header file for more info.
-VarKind SigPointer::IsPolyType(const SigTypeContext *pTypeContext) const
-{
- CONTRACTL
- {
- INSTANCE_CHECK;
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END
-
- SigPointer psig = *this;
- CorElementType typ;
-
- if (FAILED(psig.GetElemType(&typ)))
- return hasNoVars;
-
- switch(typ) {
- case ELEMENT_TYPE_VAR:
- case ELEMENT_TYPE_MVAR:
- {
- VarKind res = (typ == ELEMENT_TYPE_VAR ? hasClassVar : hasMethodVar);
- if (pTypeContext != NULL)
- {
- TypeHandle ty = psig.GetTypeVariable(typ, pTypeContext);
- if (ty.IsCanonicalSubtype())
- res = (VarKind) (res | (typ == ELEMENT_TYPE_VAR ? hasSharableClassVar : hasSharableMethodVar));
- }
- return (res);
- }
-
- case ELEMENT_TYPE_U:
- case ELEMENT_TYPE_I:
- case ELEMENT_TYPE_STRING:
- case ELEMENT_TYPE_OBJECT:
- case ELEMENT_TYPE_I1:
- case ELEMENT_TYPE_U1:
- case ELEMENT_TYPE_BOOLEAN:
- case ELEMENT_TYPE_I2:
- case ELEMENT_TYPE_U2:
- case ELEMENT_TYPE_CHAR:
- case ELEMENT_TYPE_I4:
- case ELEMENT_TYPE_U4:
- case ELEMENT_TYPE_I8:
- case ELEMENT_TYPE_U8:
- case ELEMENT_TYPE_R4:
- case ELEMENT_TYPE_R8:
- case ELEMENT_TYPE_VOID:
- case ELEMENT_TYPE_CLASS:
- case ELEMENT_TYPE_VALUETYPE:
- case ELEMENT_TYPE_TYPEDBYREF:
- return(hasNoVars);
-
- case ELEMENT_TYPE_GENERICINST:
- {
- VarKind k = psig.IsPolyType(pTypeContext);
- if (FAILED(psig.SkipExactlyOne()))
- return hasNoVars;
-
- uint32_t ntypars;
- if(FAILED(psig.GetData(&ntypars)))
- return hasNoVars;
-
- for (uint32_t i = 0; i < ntypars; i++)
- {
- k = (VarKind) (psig.IsPolyType(pTypeContext) | k);
- if (FAILED(psig.SkipExactlyOne()))
- return hasNoVars;
- }
- return(k);
- }
-
- case ELEMENT_TYPE_ARRAY:
- case ELEMENT_TYPE_SZARRAY:
- case ELEMENT_TYPE_PINNED:
- case ELEMENT_TYPE_BYREF:
- case ELEMENT_TYPE_PTR:
- {
- return(psig.IsPolyType(pTypeContext));
- }
-
- case ELEMENT_TYPE_FNPTR:
- {
- if (FAILED(psig.GetData(NULL)))
- return hasNoVars;
-
- // Get arg count;
- uint32_t cArgs;
- if (FAILED(psig.GetData(&cArgs)))
- return hasNoVars;
-
- VarKind k = psig.IsPolyType(pTypeContext);
- if (FAILED(psig.SkipExactlyOne()))
- return hasNoVars;
-
- for (unsigned i = 0; i < cArgs; i++)
- {
- k = (VarKind) (psig.IsPolyType(pTypeContext) | k);
- if (FAILED(psig.SkipExactlyOne()))
- return hasNoVars;
- }
-
- return(k);
- }
-
- default:
- BAD_FORMAT_NOTHROW_ASSERT(!"Bad type");
- }
- return(hasNoVars);
-}
-
BOOL SigPointer::IsStringType(Module* pModule, const SigTypeContext *pTypeContext) const
{
WRAPPER_NO_CONTRACT;
typedef const struct HardCodedMetaSig *LPHARDCODEDMETASIG;
-//@GENERICS: flags returned from IsPolyType indicating the presence or absence of class and
-// method type parameters in a type whose instantiation cannot be determined at JIT-compile time
-enum VarKind
-{
- hasNoVars = 0x0000,
- hasClassVar = 0x0001,
- hasMethodVar = 0x0002,
- hasSharableClassVar = 0x0004,
- hasSharableMethodVar = 0x0008,
- hasAnyVarsMask = 0x0003,
- hasSharableVarsMask = 0x000c
-};
-
//---------------------------------------------------------------------------------------
struct ScanContext;
public:
//------------------------------------------------------------------------
- // Does this type contain class or method type parameters whose instantiation cannot
- // be determined at JIT-compile time from the instantiations in the method context?
- // Return a combination of hasClassVar and hasMethodVar flags.
- //
- // Example: class C<A,B> containing instance method m<T,U>
- // Suppose that the method context is C<float,string>::m<double,object>
- // Then the type Dict<!0,!!0> is considered to have *no* "polymorphic" type parameters because
- // !0 is known to be float and !!0 is known to be double
- // But Dict<!1,!!1> has polymorphic class *and* method type parameters because both
- // !1=string and !!1=object are reference types and so code using these can be shared with
- // other reference instantiations.
- //------------------------------------------------------------------------
- VarKind IsPolyType(const SigTypeContext *pTypeContext) const;
-
- //------------------------------------------------------------------------
// Tests if the element type is a System.String. Accepts
// either ELEMENT_TYPE_STRING or ELEMENT_TYPE_CLASS encoding.
//------------------------------------------------------------------------
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+.assembly extern System.Runtime {}
+.assembly extern System.Console {}
+.assembly GenericCatchInterface {}
+
+// IL in this file is based on this C# program with a few IL modifications:
+
+// static class Program
+// {
+// private static int retCode = 0;
+// static int Main()
+// {
+// try
+// {
+// try
+// {
+// throw new MyException();
+// }
+// catch (MyException) // IL edit: Change to catch (IMyInterface)
+// {
+// Console.WriteLine("FAIL");
+// retCode++;
+// }
+// }
+// catch
+// {
+// Console.WriteLine("PASS");
+// retCode += 50;
+// }
+//
+// GenericCatch<MyException>(); // IL edit: Change to GenericCatch<IMyInterface>()
+//
+// return retCode;
+// }
+//
+// [MethodImpl(MethodImplOptions.NoInlining)]
+// static void GenericCatch<T>() where T : Exception // IL edit: Remove constraint
+// {
+// try
+// {
+// try
+// {
+// throw new MyException();
+// }
+// catch (T)
+// {
+// Console.WriteLine("FAIL");
+// retCode++;
+// }
+// }
+// catch
+// {
+// Console.WriteLine("PASS");
+// retCode += 50;
+// }
+// }
+// }
+// interface IMyInterface {}
+// class MyException : Exception, IMyInterface {}
+
+
+.class private abstract auto ansi sealed beforefieldinit GenericCatchInterfaceProgram
+ extends [System.Runtime]System.Object
+{
+ //
+ .field private static int32 retCode
+
+ .method private hidebysig static int32 Main() cil managed
+ {
+ .entrypoint
+ .maxstack 2
+ IL_0000: newobj instance void MyException::.ctor()
+ IL_0005: throw
+
+ IL_0006: pop
+ IL_0007: ldstr "FAIL"
+ IL_000c: call void [System.Console]System.Console::WriteLine(string)
+ IL_0011: ldsfld int32 GenericCatchInterfaceProgram::retCode
+ IL_0016: ldc.i4.1
+ IL_0017: add
+ IL_0018: stsfld int32 GenericCatchInterfaceProgram::retCode
+ IL_001d: leave.s IL_001f
+
+ IL_001f: leave.s IL_003b
+
+ IL_0021: pop
+ IL_0022: ldstr "PASS"
+ IL_0027: call void [System.Console]System.Console::WriteLine(string)
+ IL_002c: ldsfld int32 GenericCatchInterfaceProgram::retCode
+ IL_0031: ldc.i4.s 50
+ IL_0033: add
+ IL_0034: stsfld int32 GenericCatchInterfaceProgram::retCode
+ IL_0039: leave.s IL_003b
+
+ IL_003b: call void GenericCatchInterfaceProgram::GenericCatch<class IMyInterface>()
+ IL_0040: ldsfld int32 GenericCatchInterfaceProgram::retCode
+ IL_0045: ret
+ IL_0046:
+ .try IL_0000 to IL_0006 catch IMyInterface handler IL_0006 to IL_001f
+ .try IL_0000 to IL_0021 catch [System.Runtime]System.Object handler IL_0021 to IL_003b
+ }
+
+ .method private hidebysig static void GenericCatch<([System.Runtime]System.Object) T>() cil managed noinlining
+ {
+ .maxstack 2
+ IL_0000: newobj instance void MyException::.ctor()
+ IL_0005: throw
+
+ IL_0006: pop
+ IL_0007: ldstr "FAIL"
+ IL_000c: call void [System.Console]System.Console::WriteLine(string)
+ IL_0011: ldsfld int32 GenericCatchInterfaceProgram::retCode
+ IL_0016: ldc.i4.1
+ IL_0017: add
+ IL_0018: stsfld int32 GenericCatchInterfaceProgram::retCode
+ IL_001d: leave.s IL_001f
+
+ IL_001f: leave.s IL_003b
+
+ IL_0021: pop
+ IL_0022: ldstr "PASS"
+ IL_0027: call void [System.Console]System.Console::WriteLine(string)
+ IL_002c: ldsfld int32 GenericCatchInterfaceProgram::retCode
+ IL_0031: ldc.i4.s 50
+ IL_0033: add
+ IL_0034: stsfld int32 GenericCatchInterfaceProgram::retCode
+ IL_0039: leave.s IL_003b
+
+ IL_003b: ret
+ IL_003c:
+ .try IL_0000 to IL_0006 catch !!T handler IL_0006 to IL_001f
+ .try IL_0000 to IL_0021 catch [System.Runtime]System.Object handler IL_0021 to IL_003b
+ }
+}
+
+.class interface private abstract auto ansi IMyInterface {}
+
+.class private auto ansi beforefieldinit MyException
+ extends [System.Runtime]System.Exception
+ implements IMyInterface
+{
+ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
+ {
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance void [System.Runtime]System.Exception::.ctor()
+ IL_0006: ret
+ }
+}
\ No newline at end of file
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk.IL">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).il" />
+ </ItemGroup>
+</Project>
\ No newline at end of file
<ExcludeList Include="$(XunitTestBinBase)/Loader/classloader\DefaultInterfaceMethods\constrainedcall\constrained2\*" />
<ExcludeList Include="$(XunitTestBinBase)/Loader/classloader\DefaultInterfaceMethods\constrainedcall\constrained2_gm\*" />
- <!-- Catch(T) in shared code -->
- <!-- https://github.com/dotnet/runtimelab/issues/204 -->
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical\eh\generics\throwincatch_generics_d\*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical\eh\generics\throwincatch_generics_do\*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical\eh\generics\throwincatch_generics_r\*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical\eh\generics\throwincatch_generics_ro\*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical\eh\generics\trycatchnestedtype_d\*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical\eh\generics\trycatchnestedtype_do\*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical\eh\generics\trycatchnestedtype_r\*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical\eh\generics\trycatchnestedtype_ro\*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical\eh\generics\trycatchsimpletype_d\*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical\eh\generics\trycatchsimpletype_do\*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical\eh\generics\trycatchsimpletype_r\*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical\eh\generics\trycatchsimpletype_ro\*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/opt/InstructionCombining/ArrayLengthArithmetic/*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/CLR-x86-JIT/V2.0-Beta2/b441487/b441487/*" />
- <ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/JitBlue/GitHub_21990/GitHub_21990/*" />
-
<!-- Arrays with non-zero lower bounds -->
<!-- https://github.com/dotnet/runtimelab/issues/155 -->
<ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical\Arrays\huge\huge_b_il_r\*" />
<!-- Known failures for mono runtime on *all* architectures/operating systems in *all* runtime modes -->
<ItemGroup Condition="'$(RuntimeFlavor)' == 'mono'" >
+ <ExcludeList Include = "$(XUnitTestBinBase)/JIT/Generics/Exceptions/GenericCatchInterfaceProgram/**">
+ <Issue>https://github.com/dotnet/runtime/issues/72827</Issue>
+ </ExcludeList>
<ExcludeList Include = "$(XUnitTestBinBase)/JIT/Directed/Arrays/nintindexoutofrange/**">
<Issue>https://github.com/dotnet/runtime/issues/71656</Issue>
</ExcludeList>
new BringUpTest().ToString();
}
+ TestGenericExceptions();
+
int counter = 0;
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionEventHandler;
Console.WriteLine("Exception caught!");
if (e.Message != "My exception")
{
- Console.WriteLine("Unexpected exception message!");
- return Fail;
+ Console.WriteLine("Unexpected exception message!");
+ return Fail;
}
string stackTrace = e.StackTrace;
try
{
- g.myObjectField = new Object();
+ g.myObjectField = new Object();
}
catch (NullReferenceException)
{
try
{
- try
- {
- g.myField++;
- }
- finally
- {
- counter++;
- }
+ try
+ {
+ g.myField++;
+ }
+ finally
+ {
+ counter++;
+ }
}
catch (NullReferenceException)
{
Console.WriteLine("Exception caught via filter!");
if (e.Message != "Testing filter")
{
- Console.WriteLine("Unexpected exception message!");
- return Fail;
+ Console.WriteLine("Unexpected exception message!");
+ return Fail;
}
counter++;
}
}
}
+ static void TestGenericExceptions()
+ {
+ if (CatchGenericException<DivideByZeroException>(100, 0) != 42)
+ {
+ Environment.Exit(Fail);
+ }
+
+ try
+ {
+ CatchGenericException<NotSupportedException>(100, 0);
+ }
+ catch (DivideByZeroException)
+ {
+ return;
+ }
+ Environment.Exit(Fail);
+ }
+
+ static int CatchGenericException<T>(int a, int b) where T : Exception
+ {
+ try
+ {
+ return a / b;
+ }
+ catch (T)
+ {
+ return 42;
+ }
+ }
+
static bool FilterWithStackTrace(Exception e)
{
var stackTrace = new StackTrace(0, true);