#include "daScript/misc/platform.h"
#include "daScript/simulate/simulate.h"
#include "daScript/simulate/aot.h"
#include "daScript/simulate/simulate_nodes.h"
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4611)
#endif
/*
NOTE: this should be the only file where daslang needs exceptions enabled.
*/
namespace das {
static void stackWalkToErr(Context & ctx, const LineInfo & at, bool showArguments, bool showLocalVariables) {
const das::string stack = ctx.getStackWalk(&at, showArguments, showLocalVariables);
ctx.to_err(&at, stack.c_str());
}
void Context::throw_fatal_error ( const char * message, const LineInfo & at ) {
exceptionMessage = message ? message : "";
exceptionMessage += "\n";
exception = exceptionMessage.c_str();
exceptionAt = at;
#if DAS_ENABLE_EXCEPTIONS
if ( alwaysErrorOnException ) {
to_err(&at, exception);
}
if ( alwaysStackWalkOnException ) {
stackWalkToErr(*this, at, showArgumentsOnException, showLocalVariablesOnException);
}
if ( breakOnException ) breakPoint(at, "exception", exception);
throw dasException(exception, at);
#else
if ( throwBuf ) {
if ( alwaysErrorOnException ) {
to_err(&at, exception);
}
if ( alwaysStackWalkOnException ) {
stackWalkToErr(*this, at, showArgumentsOnException, showLocalVariablesOnException);
}
if ( breakOnException ) breakPoint(at, "exception", exception);
#if defined(WIN64) || defined(_WIN64)
// "An invalid or unaligned stack was encountered during an unwind operation." exception is issued via longjmp
// this is a known issue with longjmp on x64, and this workaround disables stack unwinding
((_JUMP_BUFFER *)throwBuf)->Frame = 0;
#endif
longjmp(*throwBuf,1);
} else {
string msg = "\nunhandled exception\n" + exceptionAt.describe() + ": " + exception;
to_err(&at, msg.c_str());
stackWalkToErr(*this, at, showArgumentsOnException, showLocalVariablesOnException);
breakPoint(at, "exception", exception);
}
#endif
#if !defined(_MSC_VER) || (_MSC_VER>1900)
exit(0);
#endif
}
void Context::rethrow () {
#if DAS_ENABLE_EXCEPTIONS
throw dasException(exception ? exception : "", exceptionAt);
#else
if ( throwBuf ) {
#if defined(WIN64) || defined(_WIN64)
// "An invalid or unaligned stack was encountered during an unwind operation." exception is issued via longjmp
// this is a known issue with longjmp on x64, and this workaround disables stack unwinding
((_JUMP_BUFFER *)throwBuf)->Frame = 0;
#endif
longjmp(*throwBuf,1);
} else {
if ( exception ) {
string msg = "\nunhandled exception\n" + exceptionAt.describe() + ": " + exception + "\n";
to_err(nullptr, msg.c_str());
} else {
to_err(nullptr, "\nunhandled exception\n");
}
stackWalk(nullptr, false, false);
os_debug_break();
}
#endif
#if !defined(_MSC_VER) || (_MSC_VER>1900)
exit(0);
#endif
}
vec4f WIN_EH_NO_ASAN Context::evalWithCatch ( SimNode * node ) {
auto aa = abiArg;
auto acm = abiCMRES;
auto atba = abiThisBlockArg;
char * EP, * SP;
stack.watermark(EP,SP);
vec4f vres = v_zero();
#if DAS_ENABLE_EXCEPTIONS
try {
vres = node->eval(*this);
} catch ( const dasException & ex ) {
abiArg = aa;
abiCMRES = acm;
abiThisBlockArg = atba;
stack.pop(EP,SP);
exceptionMessage = ex.what();
exception = exceptionMessage.c_str();
exceptionAt = ex.exceptionAt;
}
#else
jmp_buf ev;
jmp_buf * JB = throwBuf;
throwBuf = &ev;
if ( !setjmp(ev) ) {
vres = node->eval(*this);
} else {
abiArg = aa;
abiCMRES = acm;
abiThisBlockArg = atba;
stack.pop(EP,SP);
}
throwBuf = JB;
#endif
return vres;
}
bool WIN_EH_NO_ASAN Context::runWithCatch ( const callable & subexpr ) {
auto aa = abiArg;
auto acm = abiCMRES;
auto atba = abiThisBlockArg;
char * EP, * SP;
stack.watermark(EP,SP);
bool bres = false;
#if DAS_ENABLE_EXCEPTIONS
try {
subexpr();
bres = true;
} catch ( const dasException & ex ) {
abiArg = aa;
abiCMRES = acm;
abiThisBlockArg = atba;
stack.pop(EP,SP);
exceptionMessage = ex.what();
exception = exceptionMessage.c_str();
exceptionAt = ex.exceptionAt;
}
#else
jmp_buf ev;
jmp_buf * JB = throwBuf;
throwBuf = &ev;
if ( !setjmp(ev) ) {
subexpr();
bres = true;
} else {
abiArg = aa;
abiCMRES = acm;
abiThisBlockArg = atba;
stack.pop(EP,SP);
}
throwBuf = JB;
#endif
return bres;
}
vec4f WIN_EH_NO_ASAN Context::evalWithCatch ( SimFunction * fnPtr, vec4f * args, void * res ) {
auto aa = abiArg;
auto acm = abiCMRES;
auto atba = abiThisBlockArg;
char * EP, * SP;
stack.watermark(EP,SP);
vec4f vres = v_zero();
#if DAS_ENABLE_EXCEPTIONS
try {
vres = callWithCopyOnReturn(fnPtr, args, res, 0);
} catch ( const dasException & ex ) {
abiArg = aa;
abiCMRES = acm;
abiThisBlockArg = atba;
stack.pop(EP,SP);
exceptionMessage = ex.what();
exception = exceptionMessage.c_str();
exceptionAt = ex.exceptionAt;
}
#else
jmp_buf ev;
jmp_buf * JB = throwBuf;
throwBuf = &ev;
if ( !setjmp(ev) ) {
vres = callWithCopyOnReturn(fnPtr, args, res, 0);
} else {
abiArg = aa;
abiCMRES = acm;
abiThisBlockArg = atba;
stack.pop(EP,SP);
}
throwBuf = JB;
#endif
return vres;
}
// SimNode_TryCatch
vec4f WIN_EH_NO_ASAN SimNode_TryCatch::eval ( Context & context ) {
DAS_PROFILE_NODE
auto aa = context.abiArg; auto acm = context.abiCMRES;
char * EP, * SP;
context.stack.watermark(EP,SP);
#if DAS_ENABLE_EXCEPTIONS
try {
try_block->eval(context);
} catch ( const dasException & ) {
context.abiArg = aa;
context.abiCMRES = acm;
context.stack.pop(EP,SP);
context.stopFlags = 0;
context.last_exception = context.exception;
context.exception = nullptr;
catch_block->eval(context);
}
#else
jmp_buf ev;
jmp_buf * JB = context.throwBuf;
context.throwBuf = &ev;
if ( !setjmp(ev) ) {
try_block->eval(context);
} else {
context.throwBuf = JB;
context.abiArg = aa;
context.abiCMRES = acm;
context.stack.pop(EP,SP);
context.stopFlags = 0;
context.last_exception = context.exception;
context.exception = nullptr;
catch_block->eval(context);
}
context.throwBuf = JB;
#endif
return v_zero();
}
#if DAS_DEBUGGER
vec4f WIN_EH_NO_ASAN SimNodeDebug_TryCatch::eval ( Context & context ) {
DAS_PROFILE_NODE
auto aa = context.abiArg; auto acm = context.abiCMRES;
char * EP, * SP;
context.stack.watermark(EP,SP);
#if DAS_ENABLE_EXCEPTIONS
try {
DAS_SINGLE_STEP(context,try_block->debugInfo,false);
try_block->eval(context);
} catch ( const dasException & ) {
context.abiArg = aa;
context.abiCMRES = acm;
context.stack.pop(EP,SP);
context.stopFlags = 0;
context.last_exception = context.exception;
context.exception = nullptr;
DAS_SINGLE_STEP(context,catch_block->debugInfo,false);
catch_block->eval(context);
}
#else
jmp_buf ev;
jmp_buf * JB = context.throwBuf;
context.throwBuf = &ev;
if ( !setjmp(ev) ) {
DAS_SINGLE_STEP(context,try_block->debugInfo,false);
try_block->eval(context);
} else {
context.throwBuf = JB;
context.abiArg = aa;
context.abiCMRES = acm;
context.stack.pop(EP,SP);
context.stopFlags = 0;
context.last_exception = context.exception;
context.exception = nullptr;
DAS_SINGLE_STEP(context,catch_block->debugInfo,false);
catch_block->eval(context);
}
context.throwBuf = JB;
#endif
return v_zero();
}
#endif
void WIN_EH_NO_ASAN das_try_recover ( Context * __context__, const callable & try_block, const callable & catch_block ) {
auto aa = __context__->abiArg; auto acm = __context__->abiCMRES;
char * EP, * SP;
__context__->stack.watermark(EP,SP);
#if DAS_ENABLE_EXCEPTIONS
try {
try_block();
} catch ( const dasException & ) {
catch_block();
__context__->abiArg = aa;
__context__->abiCMRES = acm;
__context__->stack.pop(EP,SP);
__context__->stopFlags = 0;
__context__->last_exception = __context__->exception;
__context__->exception = nullptr;
}
#else
jmp_buf ev;
jmp_buf * JB = __context__->throwBuf;
__context__->throwBuf = &ev;
if ( !setjmp(ev) ) {
try_block();
} else {
catch_block();
__context__->throwBuf = JB;
__context__->abiArg = aa;
__context__->abiCMRES = acm;
__context__->stack.pop(EP,SP);
__context__->stopFlags = 0;
__context__->last_exception = __context__->exception;
__context__->exception = nullptr;
}
__context__->throwBuf = JB;
#endif
}
void WIN_EH_NO_ASAN builtin_try_recover ( const Block & try_block, const Block & catch_block, Context * context, LineInfoArg * at ) {
auto aa = context->abiArg; auto acm = context->abiCMRES;
char * EP, * SP;
context->stack.watermark(EP,SP);
#if DAS_ENABLE_EXCEPTIONS
try {
context->invoke(try_block, nullptr, nullptr, at);
} catch ( const dasException & ) {
context->abiArg = aa;
context->abiCMRES = acm;
context->stack.pop(EP,SP);
context->stopFlags = 0;
context->last_exception = context->exception;
context->exception = nullptr;
context->invoke(catch_block,nullptr,nullptr, at);
}
#else
jmp_buf ev;
jmp_buf * JB = context->throwBuf;
context->throwBuf = &ev;
if ( !setjmp(ev) ) {
context->invoke(try_block,nullptr,nullptr, at);
} else {
context->throwBuf = JB;
context->abiArg = aa;
context->abiCMRES = acm;
context->stack.pop(EP,SP);
context->stopFlags = 0;
context->last_exception = context->exception;
context->exception = nullptr;
context->invoke(catch_block,nullptr,nullptr, at);
}
context->throwBuf = JB;
#endif
}
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif