blob: 52caa4a8e738d114fb8c482e773a8f180797c749 [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
#ifdef STACK_BACK_TRACE
class StackBackTrace;
#endif
namespace Js {
class ScriptContext;
class Throw
{
public:
static void __declspec(noreturn) OutOfMemory();
static void __declspec(noreturn) StackOverflow(ScriptContext *scriptContext, PVOID returnAddress);
static void __declspec(noreturn) NotImplemented();
static void __declspec(noreturn) InternalError();
static void __declspec(noreturn) FatalInternalError();
static void __declspec(noreturn) FatalInternalErrorEx(int scenario);
static void __declspec(noreturn) FatalProjectionError();
#if ENABLE_JS_REENTRANCY_CHECK
static void __declspec(noreturn) FatalJsReentrancyError();
#endif
static void CheckAndThrowOutOfMemory(BOOLEAN status);
static bool ReportAssert(__in LPCSTR fileName, uint lineNumber, __in LPCSTR error, __in LPCSTR message);
static void LogAssert();
#ifdef GENERATE_DUMP
static int GenerateDump(PEXCEPTION_POINTERS exceptInfo, LPCWSTR filePath, int ret = EXCEPTION_CONTINUE_SEARCH, bool needLock = false);
static void GenerateDump(LPCWSTR filePath, bool terminate = false, bool needLock = false);
static void GenerateDumpForAssert(LPCWSTR filePath);
private:
static CriticalSection csGenerateDump;
#ifdef STACK_BACK_TRACE
THREAD_LOCAL static StackBackTrace * stackBackTrace;
static const int StackToSkip = 2;
static const int StackTraceDepth = 40;
#endif
#endif
};
// Info: Verify the result or throw catastrophic
// Parameters: HRESULT
inline void VerifyOkCatastrophic(__in HRESULT hr)
{
if (hr == E_OUTOFMEMORY)
{
Js::Throw::OutOfMemory();
}
else if (FAILED(hr))
{
Js::Throw::FatalProjectionError();
}
}
// Info: Verify the result or throw catastrophic
// Parameters: bool
template<typename TCheck>
inline void VerifyCatastrophic(__in TCheck result)
{
if (!result)
{
Assert(false);
Js::Throw::FatalProjectionError();
}
}
} // namespace Js
#define BEGIN_TRANSLATE_TO_HRESULT(type) \
{\
try \
{ \
AUTO_HANDLED_EXCEPTION_TYPE(type);
#define BEGIN_TRANSLATE_TO_HRESULT_NESTED(type) \
{\
try \
{ \
AUTO_NESTED_HANDLED_EXCEPTION_TYPE(type);
#define BEGIN_TRANSLATE_OOM_TO_HRESULT BEGIN_TRANSLATE_TO_HRESULT(ExceptionType_OutOfMemory)
#define BEGIN_TRANSLATE_OOM_TO_HRESULT_NESTED BEGIN_TRANSLATE_TO_HRESULT_NESTED(ExceptionType_OutOfMemory)
#define END_TRANSLATE_OOM_TO_HRESULT(hr) \
} \
catch (Js::OutOfMemoryException) \
{ \
hr = E_OUTOFMEMORY; \
}\
}
#define END_TRANSLATE_OOM_TO_HRESULT_AND_EXCEPTION_OBJECT(hr, scriptContext, exceptionObject) \
} \
catch(Js::OutOfMemoryException) \
{ \
hr = E_OUTOFMEMORY; \
*exceptionObject = Js::JavascriptExceptionOperators::GetOutOfMemoryExceptionObject(scriptContext); \
} \
}
#define BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT BEGIN_TRANSLATE_TO_HRESULT((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow))
#define BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT_NESTED BEGIN_TRANSLATE_TO_HRESULT_NESTED((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow))
#define BEGIN_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT BEGIN_TRANSLATE_TO_HRESULT((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow | ExceptionType_JavascriptException))
#define BEGIN_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT_NESTED BEGIN_TRANSLATE_TO_HRESULT_NESTED((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow | ExceptionType_JavascriptException))
#define END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT(hr) \
} \
catch (Js::OutOfMemoryException) \
{ \
hr = E_OUTOFMEMORY; \
} \
catch (Js::StackOverflowException) \
{ \
hr = VBSERR_OutOfStack; \
} \
catch (Js::NotImplementedException) \
{ \
hr = E_NOTIMPL; \
} \
catch (Js::ScriptAbortException) \
{ \
hr = E_ABORT; \
} \
catch (Js::AsmJsParseException) \
{ \
hr = JSERR_AsmJsCompileError; \
}
// This should be the inverse of END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT, and catch all the same cases.
#define THROW_KNOWN_HRESULT_EXCEPTIONS(hr, scriptContext) \
if (hr == E_OUTOFMEMORY) \
{ \
JavascriptError::ThrowOutOfMemoryError(scriptContext); \
} \
else if (hr == VBSERR_OutOfStack) \
{ \
JavascriptError::ThrowStackOverflowError(scriptContext); \
} \
else if (hr == E_NOTIMPL) \
{ \
throw Js::NotImplementedException(); \
} \
else if (hr == E_ABORT) \
{ \
throw Js::ScriptAbortException(); \
} \
else if (hr == JSERR_AsmJsCompileError) \
{ \
throw Js::AsmJsParseException(); \
} \
else if (FAILED(hr)) \
{ \
/* Intended to be the inverse of E_FAIL in CATCH_UNHANDLED_EXCEPTION */ \
AssertOrFailFast(false); \
}
#define CATCH_UNHANDLED_EXCEPTION(hr) \
catch (...) \
{ \
AssertOrFailFastMsg(FALSE, "invalid exception thrown and didn't get handled"); \
hr = E_FAIL; /* Suppress C4701 */ \
} \
}
#define END_TRANSLATE_EXCEPTION_TO_HRESULT(hr) \
END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT(hr)\
CATCH_UNHANDLED_EXCEPTION(hr)
#define END_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT(hr) \
Assert(!JsUtil::ExternalApi::IsScriptActiveOnCurrentThreadContext()); \
END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT(hr) \
END_TRANSLATE_ERROROBJECT_TO_HRESULT(hr) \
CATCH_UNHANDLED_EXCEPTION(hr)
// Use this version if execution is in script (use rarely)
#define END_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT_INSCRIPT(hr) \
Assert(JsUtil::ExternalApi::IsScriptActiveOnCurrentThreadContext()); \
END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT(hr) \
END_TRANSLATE_ERROROBJECT_TO_HRESULT_INSCRIPT(hr) \
CATCH_UNHANDLED_EXCEPTION(hr)
#define END_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT_NOASSERT(hr) \
END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT(hr) \
END_TRANSLATE_ERROROBJECT_TO_HRESULT(hr) \
CATCH_UNHANDLED_EXCEPTION(hr)
#define END_TRANSLATE_ERROROBJECT_TO_HRESULT_EX(hr, GetRuntimeErrorFunc) \
catch(const Js::JavascriptException& err) \
{ \
Js::JavascriptExceptionObject* exceptionObject = err.GetAndClear(); \
GET_RUNTIME_ERROR_IMPL(hr, GetRuntimeErrorFunc, exceptionObject); \
}
#define GET_RUNTIME_ERROR_IMPL(hr, GetRuntimeErrorFunc, exceptionObject) \
{ \
Js::Var errorObject = exceptionObject->GetThrownObject(nullptr); \
if (errorObject != nullptr && (Js::JavascriptError::Is(errorObject) || \
Js::JavascriptError::IsRemoteError(errorObject))) \
{ \
hr = GetRuntimeErrorFunc(Js::RecyclableObject::FromVar(errorObject), nullptr); \
} \
else \
{ \
AssertMsg(errorObject == nullptr, "errorObject should be NULL"); \
hr = E_OUTOFMEMORY; \
} \
}
#define GET_RUNTIME_ERROR(hr, exceptionObject) \
GET_RUNTIME_ERROR_IMPL(hr, Js::JavascriptError::GetRuntimeErrorWithScriptEnter, exceptionObject)
#define END_TRANSLATE_ERROROBJECT_TO_HRESULT(hr) \
END_TRANSLATE_ERROROBJECT_TO_HRESULT_EX(hr, Js::JavascriptError::GetRuntimeErrorWithScriptEnter)
#define END_GET_ERROROBJECT(hr, scriptContext, exceptionObject) \
catch (const Js::JavascriptException& err) \
{ \
Js::JavascriptExceptionObject * _exceptionObject = err.GetAndClear(); \
BEGIN_TRANSLATE_OOM_TO_HRESULT_NESTED \
exceptionObject = _exceptionObject; \
exceptionObject = exceptionObject->CloneIfStaticExceptionObject(scriptContext); \
END_TRANSLATE_OOM_TO_HRESULT(hr) \
}
#define CATCH_STATIC_JAVASCRIPT_EXCEPTION_OBJECT(errCode) \
catch (Js::OutOfMemoryException) \
{ \
errCode = JsErrorOutOfMemory; \
} catch (Js::StackOverflowException) \
{ \
errCode = JsErrorOutOfMemory; \
} \
#if ENABLE_TTD
#define CATCH_OTHER_EXCEPTIONS(errCode) \
catch (JsrtExceptionBase& e) \
{ \
errCode = e.GetJsErrorCode(); \
} \
catch (Js::ExceptionBase) \
{ \
AssertMsg(false, "Unexpected engine exception."); \
errCode = JsErrorFatal; \
} \
catch (TTD::TTDebuggerAbortException) \
{ \
throw; /*don't set errcode we treat this as non-termination of the code that was executing*/ \
} \
catch (...) \
{ \
AssertMsg(false, "Unexpected non-engine exception."); \
errCode = JsErrorFatal; \
}
#else
#define CATCH_OTHER_EXCEPTIONS(errCode) \
catch (JsrtExceptionBase& e) \
{ \
errCode = e.GetJsErrorCode(); \
} \
catch (Js::ExceptionBase) \
{ \
AssertMsg(false, "Unexpected engine exception."); \
errCode = JsErrorFatal; \
} \
catch (...) \
{ \
AssertMsg(false, "Unexpected non-engine exception."); \
errCode = JsErrorFatal; \
}
#endif
// Use this version if execution is in script (use rarely)
#define END_TRANSLATE_ERROROBJECT_TO_HRESULT_INSCRIPT(hr) \
END_TRANSLATE_ERROROBJECT_TO_HRESULT_EX(hr, Js::JavascriptError::GetRuntimeError)
#define TRANSLATE_EXCEPTION_TO_HRESULT_ENTRY(ex) \
} \
catch (ex) \
{
#define DEBUGGER_ATTACHDETACH_FATAL_ERROR_IF_FAILED(hr) if (hr != S_OK) Debugger_AttachDetach_fatal_error(hr);