1 Continuation
Needed here in the exceptions library because it can be thrown as an exception.
share/lib/rtl/flx_continuation.hpp
#ifndef _FLX_CONTINUATION_HPP #define _FLX_CONTINUATION_HPP #include "flx_exceptions_config.hpp" #include "flx_compiler_support_headers.hpp" // ******************************************************** /// CONTINUATION. // ******************************************************** namespace flx {namespace rtl { struct FLX_EXCEPTIONS_EXTERN con_t ///< abstract base for mutable continuations { FLX_PC_DECL ///< interior program counter union svc_req_t *p_svc; ///< pointer to service request con_t(); ///< initialise pc, p_svc to 0 virtual con_t *resume()=0;///< method to perform a computational step virtual ~con_t(); con_t * _caller; ///< callers continuation (return address) }; }} //namespaces #endif
share/src/exceptions/flx_continuation.cpp
#include "flx_continuation.hpp" namespace flx { namespace rtl { // ******************************************************** // con_t implementation // ******************************************************** con_t::con_t() : pc(0), p_svc(0), _caller(0) { #if FLX_DEBUG_CONT fprintf(stderr,"Constructing %p\n",this); #endif } con_t::~con_t(){ #if FLX_DEBUG_CONT fprintf(stderr,"Destroying %p\n",this); #endif } }} // namespaces
2 Exceptions
Felix programs can throw a number of exceptions representing errors. Such exceptions cannot be handled. The Felix RTL catches these exceptions, displays a diagnostic, and then terminates the program.
Exceptions thrown in a thread should also terminate the program, that is, the whole containing process and any child processes if the OS supports that.
These exceptions are for fatal errors only.
Internally Felix may throw continuations to unwind the machine stack so that a long jump (non-local goto) can be executed in a top level procedure.
Exception handling is, however, supported in one very special case: it is allowed to directly wrap a C++ primitive function with a try/catch/entry construction. General Felix code can NOT be wrapped because procedures do not use the machine stack to retain continuations (return addresses).
In general C++ style dynamic exception handling is unsafe and should not be used.
share/lib/rtl/flx_exceptions.hpp
#ifndef __FLX_EXCEPTIONS_HPP__ #define __FLX_EXCEPTIONS_HPP__ #include "flx_exceptions_config.hpp" #include <string> namespace flx { namespace rtl { // ******************************************************** // Standard C++ Exceptions // ******************************************************** struct FLX_EXCEPTIONS_EXTERN flx_exception_t; struct FLX_EXCEPTIONS_EXTERN flx_out_of_memory_t; struct FLX_EXCEPTIONS_EXTERN flx_exec_failure_t; struct FLX_EXCEPTIONS_EXTERN flx_range_srcref_t; struct FLX_EXCEPTIONS_EXTERN flx_match_failure_t; struct FLX_EXCEPTIONS_EXTERN flx_assert_failure_t; struct FLX_EXCEPTIONS_EXTERN flx_assert2_failure_t; struct FLX_EXCEPTIONS_EXTERN flx_axiom_check_failure_t; struct FLX_EXCEPTIONS_EXTERN flx_switch_failure_t; struct FLX_EXCEPTIONS_EXTERN flx_dead_frame_failure_t; struct FLX_EXCEPTIONS_EXTERN flx_dropthru_failure_t; struct FLX_EXCEPTIONS_EXTERN flx_link_failure_t; // ******************************************************** /// EXCEPTION: Felix exception base abstraction. /// Mainly used to convert catches into subroutine /// calls which then dispatch on RTTI manually. // ******************************************************** struct FLX_EXCEPTIONS_EXTERN flx_exception_t { virtual ~flx_exception_t()=0; }; // ******************************************************** /// EXCEPTION: Out of Memory. /// Thrown when out of memory or memory bound exceeded. // ******************************************************** struct FLX_EXCEPTIONS_EXTERN flx_out_of_memory_t : flx_exception_t { flx_out_of_memory_t(); virtual ~flx_out_of_memory_t(); }; // ******************************************************** /// EXCEPTION: EXEC protocol failure. /// Thrown when trying to run a dead procedure // ******************************************************** struct FLX_EXCEPTIONS_EXTERN flx_exec_failure_t : flx_exception_t { ::std::string filename; ///< dll filename ::std::string operation; ///< faulty operation ::std::string what; ///< error description flx_exec_failure_t(::std::string f, ::std::string o, ::std::string w); virtual ~flx_exec_failure_t(); }; // ******************************************************** /// SOURCE REFERENCE: to track places in user source code. // ******************************************************** struct FLX_EXCEPTIONS_EXTERN flx_range_srcref_t { char const *filename; ///< source file name int startline; ///< first line (1 origin) int startcol; ///< first column (1 origin) int endline; ///< last line int endcol; ///< last column flx_range_srcref_t(char const *f,int sl, int sc, int el, int ec); flx_range_srcref_t(); }; // ******************************************************** /// EXCEPTION: HALT. /// Thrown by halt command // ******************************************************** struct FLX_EXCEPTIONS_EXTERN flx_halt_t : flx_exception_t { ::std::string reason; ///< halt argument flx_range_srcref_t flx_loc; ///< location in Felix file char const *cxx_srcfile; ///< C++ file name int cxx_srcline; ///< C++ line number flx_halt_t(flx_range_srcref_t ff, char const *cf, int cl, ::std::string reason); virtual ~flx_halt_t(); }; // ******************************************************** /// EXCEPTION: MATCH failure. /// Thrown when no match cases match the argument of a match, /// regmatch, or reglex // ******************************************************** struct FLX_EXCEPTIONS_EXTERN flx_match_failure_t : flx_exception_t { flx_range_srcref_t flx_loc; ///< location in Felix file char const *cxx_srcfile; ///< C++ file name int cxx_srcline; ///< C++ line number flx_match_failure_t(flx_range_srcref_t ff, char const *cf, int cl); virtual ~flx_match_failure_t(); }; // ******************************************************** /// EXCEPTION: DROPTHRU failure. /// Thrown when function drops off end without returning value // ******************************************************** struct FLX_EXCEPTIONS_EXTERN flx_dropthru_failure_t : flx_exception_t { flx_range_srcref_t flx_loc; ///< location in Felix file char const *cxx_srcfile; ///< C++ file name int cxx_srcline; ///< C++ line number flx_dropthru_failure_t(flx_range_srcref_t ff, char const *cf, int cl); virtual ~flx_dropthru_failure_t(); }; // ******************************************************** /// EXCEPTION: ASSERT failure. /// Thrown when user assertion fails // ******************************************************** struct FLX_EXCEPTIONS_EXTERN flx_assert_failure_t : flx_exception_t { flx_range_srcref_t flx_loc; ///< location in Felix file char const *cxx_srcfile; ///< C++ file int cxx_srcline; ///< __LINE__ macro flx_assert_failure_t(flx_range_srcref_t ff, char const *cf, int cl); virtual ~flx_assert_failure_t(); }; struct FLX_EXCEPTIONS_EXTERN flx_assert2_failure_t : flx_exception_t { flx_range_srcref_t flx_loc; ///< location in Felix file flx_range_srcref_t flx_loc2; ///< second location in Felix file char const *cxx_srcfile; ///< C++ file int cxx_srcline; ///< __LINE__ macro flx_assert2_failure_t(flx_range_srcref_t ff, flx_range_srcref_t ff2, char const *cf, int cl); virtual ~flx_assert2_failure_t(); }; struct FLX_EXCEPTIONS_EXTERN flx_axiom_check_failure_t : flx_exception_t { flx_range_srcref_t flx_loc; ///< location in Felix file flx_range_srcref_t flx_loc2; ///< second location in Felix file char const *cxx_srcfile; ///< C++ file int cxx_srcline; ///< __LINE__ macro flx_axiom_check_failure_t (flx_range_srcref_t ff, flx_range_srcref_t ff2, char const *cf, int cl); virtual ~flx_axiom_check_failure_t (); }; // ******************************************************** /// EXCEPTION: RANGE failure. /// Thrown when a range check fails // ******************************************************** struct FLX_EXCEPTIONS_EXTERN flx_range_failure_t : flx_exception_t { long min; long v; long max; flx_range_srcref_t flx_loc; ///< location in Felix file char const *cxx_srcfile; ///< C++ file int cxx_srcline; ///< __LINE__ macro flx_range_failure_t(long,long,long,flx_range_srcref_t ff, char const *cf, int cl); virtual ~flx_range_failure_t(); }; FLX_EXCEPTIONS_EXTERN long range_check (long l, long x, long h, flx_range_srcref_t sref, char const *cf, int cl); FLX_EXCEPTIONS_EXTERN void print_loc(FILE *ef,flx_range_srcref_t x,char const *cf, int cl); FLX_EXCEPTIONS_EXTERN void print_cxxloc(FILE *ef,char const *cf, int cl); FLX_EXCEPTIONS_EXTERN void print_srclines(FILE *ef,flx_range_srcref_t x); // ******************************************************** /// EXCEPTION: SWITCH failure. this is a system failure! // ******************************************************** struct FLX_EXCEPTIONS_EXTERN flx_switch_failure_t : flx_exception_t { char const *cxx_srcfile; ///< C++ file int cxx_srcline; ///< __LINE__ macro flx_switch_failure_t(char const *cf, int cl); virtual ~flx_switch_failure_t(); }; // ******************************************************** /// EXCEPTION: DEAD FRAME failure. /// Thrown on attempt to resume already returned procedure frame. // ******************************************************** struct FLX_EXCEPTIONS_EXTERN flx_dead_frame_failure_t : flx_exception_t { char const *cxx_srcfile; ///< C++ file int cxx_srcline; ///< __LINE__ macro flx_dead_frame_failure_t(char const *cf, int cl); virtual ~flx_dead_frame_failure_t(); }; // ******************************************************** /// EXCEPTION: DYNAMIC LINKAGE failure. this is a system failure! // ******************************************************** struct FLX_EXCEPTIONS_EXTERN flx_link_failure_t : flx_exception_t { ::std::string filename; ::std::string operation; ::std::string what; flx_link_failure_t(::std::string f, ::std::string o, ::std::string w); flx_link_failure_t(); // unfortunately this one requires a default ctor. virtual ~flx_link_failure_t(); }; }} #endif
share/src/exceptions/flx_exceptions.cpp
#include <stdio.h> #include <string.h> #include "flx_exceptions.hpp" namespace flx { namespace rtl { // ******************************************************** // standard exceptions -- implementation // ******************************************************** flx_exception_t::~flx_exception_t(){} flx_exec_failure_t::flx_exec_failure_t(::std::string f, ::std::string o, ::std::string w) : filename(f), operation(o), what(w) {} flx_out_of_memory_t::flx_out_of_memory_t(){} flx_out_of_memory_t::~flx_out_of_memory_t(){} flx_exec_failure_t::~flx_exec_failure_t(){} flx_range_srcref_t::flx_range_srcref_t() : filename(""),startline(0),startcol(0),endline(0),endcol(0){} flx_range_srcref_t::flx_range_srcref_t(char const *f,int sl, int sc, int el, int ec) : filename(f),startline(sl),startcol(sc),endline(el),endcol(ec){} flx_halt_t::flx_halt_t(flx_range_srcref_t ff, char const *cf, int cl, ::std::string r) : reason(r), flx_loc(ff), cxx_srcfile(cf), cxx_srcline(cl) {} flx_halt_t::~flx_halt_t(){} flx_match_failure_t::flx_match_failure_t(flx_range_srcref_t ff, char const *cf, int cl) : flx_loc(ff), cxx_srcfile(cf), cxx_srcline(cl) {} flx_match_failure_t::~flx_match_failure_t(){} flx_dropthru_failure_t::flx_dropthru_failure_t(flx_range_srcref_t ff, char const *cf, int cl) : flx_loc(ff), cxx_srcfile(cf), cxx_srcline(cl) {} flx_dropthru_failure_t::~flx_dropthru_failure_t(){} flx_assert_failure_t::flx_assert_failure_t(flx_range_srcref_t ff, char const *cf, int cl) : flx_loc(ff), cxx_srcfile(cf), cxx_srcline(cl) {} flx_assert_failure_t::~flx_assert_failure_t(){} flx_assert2_failure_t::flx_assert2_failure_t(flx_range_srcref_t ff, flx_range_srcref_t ff2, char const *cf, int cl) : flx_loc(ff), flx_loc2(ff2), cxx_srcfile(cf), cxx_srcline(cl) {} flx_assert2_failure_t::~flx_assert2_failure_t(){} flx_axiom_check_failure_t::flx_axiom_check_failure_t(flx_range_srcref_t ff, flx_range_srcref_t ff2, char const *cf, int cl) : flx_loc(ff), flx_loc2(ff2), cxx_srcfile(cf), cxx_srcline(cl) {} flx_axiom_check_failure_t::~flx_axiom_check_failure_t(){} flx_range_failure_t::flx_range_failure_t(long l, long x, long h, flx_range_srcref_t ff, char const *cf, int cl) : min(l), v(x), max(h), flx_loc(ff), cxx_srcfile(cf), cxx_srcline(cl) {} flx_range_failure_t::~flx_range_failure_t(){} flx_switch_failure_t::~flx_switch_failure_t(){} flx_switch_failure_t::flx_switch_failure_t (char const *cf, int cl) : cxx_srcfile(cf), cxx_srcline (cl) {} flx_dead_frame_failure_t::~flx_dead_frame_failure_t(){} flx_dead_frame_failure_t::flx_dead_frame_failure_t(char const *cf, int cl) : cxx_srcfile(cf), cxx_srcline (cl) {} flx_link_failure_t::flx_link_failure_t(::std::string f, ::std::string o, ::std::string w) : filename(f), operation(o), what(w) {} flx_link_failure_t::~flx_link_failure_t(){} flx_link_failure_t::flx_link_failure_t(){} long range_check (long l, long x, long h, flx_range_srcref_t sref, char const *cf, int cl) { if (x>=l && x<h) return x; throw flx::rtl::flx_range_failure_t (l,x,h,sref,cf,cl); } void print_cxxloc(FILE *ef,char const *cf, int cl) { fprintf(ef,"C++ location : %s %d\n", cf, cl); } void print_loc(FILE *ef,flx_range_srcref_t x,char const *cf, int cl) { fprintf(ef,"Felix location: %s %d[%d]-%d[%d]\n", x.filename, x.startline, x.startcol, x.endline, x.endcol ); fprintf(ef,"C++ location : %s %d\n", cf, cl); } #define SRC_LINE_SZ 512 void print_srclines(FILE *ef,flx_range_srcref_t x) { FILE* fp; char buf[SRC_LINE_SZ]; int lnr = 0; if ((fp = fopen(x.filename, "r")) != NULL) { /* display code lines: startline-1 .. endline+1 **/ buf[SRC_LINE_SZ-1] = '\0'; while ((fgets(buf, sizeof(buf)-1, fp) != NULL) && (++lnr <= x.endline+1)) { buf[strlen(buf)-1] = '\0'; // eat the newline if ((lnr >= x.startline-1) && (lnr <= x.endline+1)) { if (lnr == x.startline-1 || lnr == 1) { fprintf(ef,"Felix code: %s\n", buf); } else { fprintf(ef," %s\n", buf); } } } fclose(fp); } } }}
3 Handling Exceptions
These exception handlers are called with standard C++ exceptions or Felix exceptions, decoded as best as possible, an error message printed, and the program terminated.
Note that at the time of writing, exception decoding does not work when using clang 3.3 and the exception is thrown across a DLL boundary. This is a bug in clang handling dynamic_casts across DLL boundaries. Gcc does not have this bug.
share/lib/rtl/flx_eh.hpp
#ifndef __FLX_EH_H__ #define __FLX_EH_H__ #include "flx_rtl_config.hpp" #include "flx_exceptions.hpp" namespace flx { namespace rtl { int FLX_EXCEPTIONS_EXTERN std_exception_handler (::std::exception const *e); int FLX_EXCEPTIONS_EXTERN flx_exception_handler (::flx::rtl::flx_exception_t const *e); }} #endif
share/src/exceptions/flx_eh.cpp
#include <stdio.h> #include "flx_exceptions.hpp" #include "flx_eh.hpp" using namespace ::flx::rtl; int ::flx::rtl::std_exception_handler (::std::exception const *e) { fprintf(stderr,"C++ STANDARD EXCEPTION %s\n",e->what()); return 4; } int ::flx::rtl::flx_exception_handler (flx_exception_t const *e) { fprintf(stderr, "Felix exception handler\n"); if (flx_halt_t const *x = dynamic_cast<flx_halt_t const*>(e)) { fprintf(stderr,"Halt: %s \n",x->reason.data()); print_loc(stderr,x->flx_loc,x->cxx_srcfile, x->cxx_srcline); return 3; } if (flx_link_failure_t const *x = dynamic_cast<flx_link_failure_t const*>(e)) { fprintf(stderr,"Dynamic linkage error\n"); fprintf(stderr,"filename: %s\n",x->filename.data()); fprintf(stderr,"operation: %s\n",x->operation.data()); fprintf(stderr,"what: %s\n",x->what.data()); return 3; } else if (flx_exec_failure_t const *x = dynamic_cast<flx_exec_failure_t const*>(e)) { fprintf(stderr,"Execution error\n"); fprintf(stderr,"filename: %s\n",x->filename.data()); fprintf(stderr,"operation: %s\n",x->operation.data()); fprintf(stderr,"what: %s\n",x->what.data()); return 3; } else if (flx_assert_failure_t const *x = dynamic_cast<flx_assert_failure_t const*>(e)) { fprintf(stderr,"Assertion Failure\n"); print_srclines(stderr,x->flx_loc); print_loc(stderr,x->flx_loc,x->cxx_srcfile, x->cxx_srcline); return 3; } else if (flx_assert2_failure_t const *x = dynamic_cast<flx_assert2_failure_t const*>(e)) { fprintf(stderr,"Assertion2 Failure\n"); print_loc(stderr,x->flx_loc,x->cxx_srcfile, x->cxx_srcline); print_loc(stderr,x->flx_loc2,x->cxx_srcfile, x->cxx_srcline); return 3; } if (flx_axiom_check_failure_t const *x = dynamic_cast<flx_axiom_check_failure_t const*>(e)) { fprintf(stderr,"Axiom Check Failure\n"); print_loc(stderr,x->flx_loc,x->cxx_srcfile, x->cxx_srcline); print_loc(stderr,x->flx_loc2,x->cxx_srcfile, x->cxx_srcline); return 3; } else if (flx_match_failure_t const *x = dynamic_cast<flx_match_failure_t const*>(e)) { fprintf(stderr,"Match Failure\n"); print_loc(stderr,x->flx_loc,x->cxx_srcfile, x->cxx_srcline); return 3; } else if (flx_switch_failure_t const *x = dynamic_cast<flx_switch_failure_t const*>(e)) { fprintf(stderr,"Attempt to switch to non-existant case\n"); print_cxxloc(stderr,x->cxx_srcfile, x->cxx_srcline); return 3; } if (flx_dead_frame_failure_t const *x = dynamic_cast<flx_dead_frame_failure_t const*>(e)) { fprintf(stderr,"Attempt to resume non-live procedure frame\n"); print_cxxloc(stderr,x->cxx_srcfile, x->cxx_srcline); return 3; } else if (flx_dropthru_failure_t const *x = dynamic_cast<flx_dropthru_failure_t const*>(e)) { fprintf(stderr,"Function Drops Off End Failure\n"); print_loc(stderr,x->flx_loc,x->cxx_srcfile, x->cxx_srcline); return 3; } else if (flx_range_failure_t const *x = dynamic_cast<flx_range_failure_t const*>(e)) { fprintf(stderr,"Range Check Failure %ld <= %ld < %ld\n",x->min, x->v,x->max); print_loc(stderr,x->flx_loc,x->cxx_srcfile, x->cxx_srcline); return 3; } else if (dynamic_cast<flx_out_of_memory_t const*>(e)) { fprintf(stderr,"Felix Out of Malloc or Specified Max allocation Exceeded"); return 3; } else { fprintf(stderr,"Unknown Felix EXCEPTION!\n"); return 5; } }
share/lib/rtl/flx_exceptions_config.hpp
#ifndef __FLX_EXCEPTIONS_CONFIG_H__ #define __FLX_EXCEPTIONS_CONFIG_H__ #include "flx_rtl_config.hpp" #ifdef BUILD_FLX_EXCEPTIONS #define FLX_EXCEPTIONS_EXTERN FLX_EXPORT #else #define FLX_EXCEPTIONS_EXTERN FLX_IMPORT #endif #endif
$PWD/src/config/unix/flx_exceptions.fpc
Name: flx_exceptions Description: Felix exceptions provides_dlib: -lflx_exceptions_dynamic provides_slib: -lflx_exceptions_static library: flx_exceptions macros: BUILD_FLX_EXCEPTIONS includes: '"flx_exceptions.hpp"' srcdir: src/exceptions src: .*\.cpp
$PWD/src/config/win/flx_exceptions.fpc
Name: flx Description: Felix exceptions provides_dlib: /DEFAULTLIB:flx_exceptions_dynamic provides_slib: /DEFAULTLIB:flx_exceptions_static library: flx_exceptions macros: BUILD_FLX_EXCEPTIONS includes: '"flx_exceptions.hpp"' srcdir: src/exceptions src: .*\.cpp
$PWD/buildsystem/flx_exceptions.py
import fbuild from fbuild.path import Path from fbuild.record import Record from fbuild.builders.file import copy import buildsystem # ------------------------------------------------------------------------------ def build_runtime(phase): print('[fbuild] [rtl] build exceptions') path = Path(phase.ctx.buildroot/'share'/'src/exceptions') srcs = [ path / 'flx_continuation.cpp', path / 'flx_exceptions.cpp', path / 'flx_eh.cpp', ] includes = [phase.ctx.buildroot / 'host/lib/rtl', phase.ctx.buildroot / 'share/lib/rtl'] macros = ['BUILD_FLX_EXCEPTIONS'] dst = 'host/lib/rtl/flx_exceptions' return Record( static=buildsystem.build_cxx_static_lib(phase, dst, srcs, includes=includes, macros=macros), shared=buildsystem.build_cxx_shared_lib(phase, dst, srcs, includes=includes, macros=macros))