#include "runtimedetails.h"
#include "spmiutil.h"
-void MSC_ONLY(__declspec(noreturn)) ThrowException(DWORD exceptionCode)
-{
- if (BreakOnException())
- __debugbreak();
-
- RaiseException(exceptionCode, 0, 0, nullptr);
-}
-
// Allocating memory here seems moderately dangerous: we'll probably leak like a sieve...
void MSC_ONLY(__declspec(noreturn)) ThrowSpmiException(DWORD exceptionCode, va_list args, const char* message)
{
ThrowSpmiException(exceptionCode, ap, msg);
}
+// Throw an exception that indicates that the EE side threw an exception during recording.
+// These exceptions do not result in replay errors; see JitInstance::CompileMethod.
+// Note that we rely on the fact that the JIT do not look closely at exceptions thrown by the EE;
+// otherwise this could cause issues since it changes the exception code from what was actually
+// thrown.
+//
+// However, do note that crossgen2/ilc and the VM already do not use the same exception code when
+// throwing exceptions.
+//
+void MSC_ONLY(__declspec(noreturn)) ThrowRecordedException(DWORD innerExceptionCode)
+{
+ if (BreakOnException())
+ __debugbreak();
+
+ ULONG_PTR args[1];
+ args[0] = (ULONG_PTR)innerExceptionCode;
+ RaiseException(EXCEPTIONCODE_RECORDED_EXCEPTION, 0, ArrLen(args), args);
+}
+
SpmiException::SpmiException(FilterSuperPMIExceptionsParam_CaptureException* e)
: exCode(e->exceptionCode), exMessage(e->exceptionMessage)
{
#define _ErrorHandling
#include "logging.h"
-#include "corexcep.h"
// EXCEPTIONCODE_DebugBreakorAV is just the base exception number; calls to DebugBreakorAV()
// pass a unique number to add to this. EXCEPTIONCODE_DebugBreakorAV_MAX is the maximum number
#define EXCEPTIONCODE_LWM 0xe0423000
#define EXCEPTIONCODE_CALLUTILS 0xe0426000
#define EXCEPTIONCODE_TYPEUTILS 0xe0427000
+// Special exception code for rethrowing a recorded exception. This is NOT
+// considered an SPMI exception (see IsSuperPMIException), but it also does not
+// result in a replay failure (see JitInstance::CompileMethod).
+#define EXCEPTIONCODE_RECORDED_EXCEPTION 0xe0428000
#define EXCEPTIONCODE_ASSERT 0xe0440000
-#define EXCEPTIONCODE_COMPLUS EXCEPTION_COMPLUS
// RaiseException wrappers
-void MSC_ONLY(__declspec(noreturn)) ThrowException(DWORD exceptionCode);
void MSC_ONLY(__declspec(noreturn)) ThrowSpmiException(DWORD exceptionCode, const char* message, ...);
+void MSC_ONLY(__declspec(noreturn)) ThrowRecordedException(DWORD innerExceptionCode);
// Assert stuff
#define AssertCodeMsg(expr, exCode, msg, ...) \
DWORD exceptionCode = 0;
bool value = jitInstance->mc->repGetMethodInfo(ftn, info, context, &exceptionCode);
if (exceptionCode != 0)
- ThrowException(exceptionCode);
+ ThrowRecordedException(exceptionCode);
return value;
}
DWORD exceptionCode = 0;
CorInfoInline result = jitInstance->mc->repCanInline(callerHnd, calleeHnd, &exceptionCode);
if (exceptionCode != 0)
- ThrowException(exceptionCode);
+ ThrowRecordedException(exceptionCode);
return result;
}
jitInstance->mc->cr->AddCall("resolveToken");
jitInstance->mc->repResolveToken(pResolvedToken, &exceptionCode);
if (exceptionCode != 0)
- ThrowException(exceptionCode);
+ ThrowRecordedException(exceptionCode);
}
// Signature information about the call sig
jitInstance->mc->cr->AddCall("getArgType");
CorInfoTypeWithMod value = jitInstance->mc->repGetArgType(sig, args, vcTypeRet, &exceptionCode);
if (exceptionCode != 0)
- ThrowException(exceptionCode);
+ ThrowRecordedException(exceptionCode);
return value;
}
jitInstance->mc->cr->AddCall("getArgClass");
CORINFO_CLASS_HANDLE value = jitInstance->mc->repGetArgClass(sig, args, &exceptionCode);
if (exceptionCode != 0)
- ThrowException(exceptionCode);
+ ThrowRecordedException(exceptionCode);
return value;
}
jitInstance->mc->repGetCallInfo(pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult,
&exceptionCode);
if (exceptionCode != 0)
- ThrowException(exceptionCode);
+ ThrowRecordedException(exceptionCode);
}
// returns the class's domain ID for accessing shared statics
e.DeleteMessage();
param.result = RESULT_MISSING;
}
- else if (e.GetCode() == EXCEPTIONCODE_COMPLUS)
+ else if (e.GetCode() == EXCEPTIONCODE_RECORDED_EXCEPTION)
{
- // We assume that managed exceptions are never JIT bugs and were
- // thrown by the EE during recording. Various EE APIs can throw
- // managed exceptions and replay will faithfully rethrow these. The
- // JIT itself will sometimes catch them (e.g. during inlining), but
- // if they make it out of the JIT then we assume that they are not
- // JIT bugs. The typical scenario is something like
- // MissingFieldException thrown from resolveToken.
+ // Exception thrown by EE during recording, for example a managed
+ // MissingFieldException thrown by resolveToken. Several JIT-EE
+ // APIs can throw exceptions and the recorder expects and rethrows
+ // their exceptions under this exception code. We do not consider
+ // these a replay failure.
// Call these methods to capture that no code/GC info was generated.
mc->cr->recAllocMemCapture();