diff --git a/lit-test/libartiq_personality/Makefile b/lit-test/libartiq_personality/Makefile index 3ef94aeb5..47daa9ac1 100644 --- a/lit-test/libartiq_personality/Makefile +++ b/lit-test/libartiq_personality/Makefile @@ -1,4 +1,4 @@ CC ?= clang -libartiq_personality.so: ../../soc/runtime/artiq_personality.c - $(CC) -Wall -Werror -I. -fPIC -shared -o $@ $< +libartiq_personality.so: ../../soc/runtime/artiq_personality.c artiq_terminate.c + $(CC) -Wall -Werror -I. -I../../soc/runtime -fPIC -shared -o $@ $^ diff --git a/lit-test/libartiq_personality/artiq_terminate.c b/lit-test/libartiq_personality/artiq_terminate.c new file mode 100644 index 000000000..9be7f36ca --- /dev/null +++ b/lit-test/libartiq_personality/artiq_terminate.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include +#include + +void __artiq_terminate(struct artiq_exception *exn) { + printf("Uncaught %s: %s (%"PRIi64", %"PRIi64", %"PRIi64")\n" + "at %s:%"PRIi32":%"PRIi32"", + exn->name, exn->message, + exn->param[0], exn->param[1], exn->param[1], + exn->file, exn->line, exn->column + 1); + exit(1); +} diff --git a/lit-test/not.py b/lit-test/not.py new file mode 100644 index 000000000..8c0421623 --- /dev/null +++ b/lit-test/not.py @@ -0,0 +1,2 @@ +import sys, subprocess +exit(not subprocess.call(sys.argv[1:])) diff --git a/lit-test/test/exceptions/raise.py b/lit-test/test/exceptions/raise.py index dbb221de4..4e056e025 100644 --- a/lit-test/test/exceptions/raise.py +++ b/lit-test/test/exceptions/raise.py @@ -1,4 +1,6 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s +# RUN: %not %python -m artiq.compiler.testbench.jit %s # REQUIRES: exceptions +# CHECK-L: Uncaught ZeroDivisionError: cannot divide by zero (0, 0, 0) +# CHECK-L: at input.py:${LINE:+1}:0 1/0 diff --git a/lit-test/test/lit.cfg b/lit-test/test/lit.cfg index b27244fba..9cbc6d070 100644 --- a/lit-test/test/lit.cfg +++ b/lit-test/test/lit.cfg @@ -9,9 +9,13 @@ config.test_format = lit.formats.ShTest() config.suffixes = ['.py'] python_executable = 'python3' + harness = '{} {}'.format(python_executable, os.path.join(root, 'harness.py')) config.substitutions.append( ('%python', harness) ) +not_ = '{} {}'.format(python_executable, os.path.join(root, 'not.py')) +config.substitutions.append( ('%not', not_) ) + if os.name == 'posix': personality_build = os.path.join(root, 'libartiq_personality') if subprocess.call(['make', '-sC', personality_build]) != 0: diff --git a/soc/runtime/artiq_personality.c b/soc/runtime/artiq_personality.c index 831abc82a..5c18de55c 100644 --- a/soc/runtime/artiq_personality.c +++ b/soc/runtime/artiq_personality.c @@ -1,25 +1,41 @@ #include #include +#include #include #include +#include "artiq_personality.h" -struct artiq_exception { - const char *name; - const char *file; - int32_t line; - int32_t column; - const char *message; - int64_t param[3]; +#define ARTIQ_EXCEPTION_CLASS 0x4152545141525451LL // 'ARTQARTQ' + +struct artiq_raised_exception { + struct _Unwind_Exception unwind; + struct artiq_exception artiq; }; -void __artiq_raise(struct artiq_exception *artiq_exn) { - printf("raised %s\n", artiq_exn->name); - abort(); +static void __artiq_cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *exc) { + struct artiq_raised_exception *inflight = (struct artiq_raised_exception*) exc; + // The in-flight exception is statically allocated, so we don't need to free it. + // But, we clear it to mark it as processed. + memset(&inflight->artiq, 0, sizeof(struct artiq_exception)); } -_Unwind_Reason_Code __artiq_personality(int version, - _Unwind_Action actions, uint64_t exceptionClass, - struct _Unwind_Exception *exceptionObject, - struct _Unwind_Context *context) { +void __artiq_raise(struct artiq_exception *artiq_exn) { + static struct artiq_raised_exception inflight; + memcpy(&inflight.artiq, artiq_exn, sizeof(struct artiq_exception)); + inflight.unwind.exception_class = ARTIQ_EXCEPTION_CLASS; + inflight.unwind.exception_cleanup = &__artiq_cleanup; + + _Unwind_Reason_Code result = _Unwind_RaiseException(&inflight.unwind); + if(result == _URC_END_OF_STACK) { + __artiq_terminate(&inflight.artiq); + } else { + fprintf(stderr, "__artiq_raise: unexpected error (%d)\n", result); + abort(); + } +} + +_Unwind_Reason_Code __artiq_personality( + int version, _Unwind_Action actions, uint64_t exceptionClass, + struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context) { abort(); } diff --git a/soc/runtime/artiq_personality.h b/soc/runtime/artiq_personality.h new file mode 100644 index 000000000..9c874e516 --- /dev/null +++ b/soc/runtime/artiq_personality.h @@ -0,0 +1,31 @@ +#ifndef __ARTIQ_PERSONALITY_H +#define __ARTIQ_PERSONALITY_H + +#include + +struct artiq_exception { + union { + void *typeinfo; + const char *name; + }; + const char *file; + int32_t line; + int32_t column; + const char *message; + int64_t param[3]; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +void __artiq_terminate(struct artiq_exception *artiq_exn) + __attribute__((noreturn)); + +void __artiq_raise(struct artiq_exception *artiq_exn); + +#ifdef __cplusplus +} +#endif + +#endif /* __ARTIQ_PERSONALITY_H */