Changeset 949339b for doc/theses/andrew_beach_MMath
- Timestamp:
- Sep 27, 2021, 2:09:55 PM (4 years ago)
- Branches:
- ADT, ast-experimental, enum, forall-pointer-decay, master, pthread-emulation, qualifiedEnum
- Children:
- cc287800
- Parents:
- 4e28d2e9 (diff), 056cbdb (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- doc/theses/andrew_beach_MMath
- Files:
-
- 2 added
- 22 edited
- 10 moved
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/andrew_beach_MMath/Makefile
r4e28d2e9 r949339b 31 31 32 32 # The main rule, it does all the tex/latex processing. 33 ${BUILD}/${BASE}.dvi: ${RAWSRC} ${FIGTEX} Makefile | ${BUILD}33 ${BUILD}/${BASE}.dvi: ${RAWSRC} ${FIGTEX} termhandle.pstex resumhandle.pstex Makefile | ${BUILD} 34 34 ${LATEX} ${BASE} 35 35 ${BIBTEX} ${BUILD}/${BASE} … … 40 40 ${FIGTEX}: ${BUILD}/%.tex: %.fig | ${BUILD} 41 41 fig2dev -L eepic $< > $@ 42 43 %.pstex : %.fig | ${Build} 44 fig2dev -L pstex $< > ${BUILD}/$@ 45 fig2dev -L pstex_t -p ${BUILD}/$@ $< > ${BUILD}/$@_t 42 46 43 47 # Step through dvi & postscript to handle xfig specials. -
doc/theses/andrew_beach_MMath/code/FixupEmpty.java
r4e28d2e9 r949339b 1 public class ResumeFixupEmpty {1 public class FixupEmpty { 2 2 public interface Fixup { 3 3 public int op(int fixup); -
doc/theses/andrew_beach_MMath/code/FixupOther.java
r4e28d2e9 r949339b 1 public class ResumeFixupOther {1 public class FixupOther { 2 2 public interface Fixup { 3 3 public int op(int fixup); -
doc/theses/andrew_beach_MMath/code/cond-catch.py
r4e28d2e9 r949339b 32 32 33 33 end_time = thread_time_ns() 34 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.))34 print('Run-Time (s): {:.1f}'.format((end_time - start_time) / 1_000_000_000.)) 35 35 36 36 -
doc/theses/andrew_beach_MMath/code/fixup-empty-f.cfa
r4e28d2e9 r949339b 2 2 #include <clock.hfa> 3 3 #include <fstream.hfa> 4 #include <stdlib.hfa> // strto4 #include <stdlib.hfa> 5 5 6 intnounwind_fixup(unsigned int frames, void (*raised_rtn)(int &)) {6 void nounwind_fixup(unsigned int frames, void (*raised_rtn)(int &)) { 7 7 if (frames) { 8 int rtn = nounwind_fixup(frames - 1, raised_rtn); 9 if ( rtn == 42 ) printf( "42" ); // make non-tail recursive 10 return rtn; 11 8 nounwind_fixup(frames - 1, raised_rtn); 9 // "Always" false, but prevents recursion elimination. 10 if (-1 == frames) printf("~"); 12 11 } else { 13 12 int fixup = 17; 14 13 raised_rtn(fixup); 15 return fixup;16 14 } 17 15 } … … 27 25 } 28 26 27 // Closures at the top level are allowed to be true closures. 29 28 void raised(int & fixup) { 30 fixup = total_frames + 42; // use local scope => lexical link31 if ( total_frames == 42 ) printf( "42");29 fixup = total_frames + 42; 30 if (total_frames == 42) printf("42"); 32 31 } 33 32 -
doc/theses/andrew_beach_MMath/code/fixup-empty-r.cfa
r4e28d2e9 r949339b 3 3 #include <exception.hfa> 4 4 #include <fstream.hfa> 5 #include <stdlib.hfa> // strto5 #include <stdlib.hfa> 6 6 7 7 exception fixup_exception { … … 10 10 vtable(fixup_exception) fixup_vt; 11 11 12 intnounwind_empty(unsigned int frames) {12 void nounwind_empty(unsigned int frames) { 13 13 if (frames) { 14 int rtn =nounwind_empty(frames - 1);15 if ( rtn == 42 ) printf( "42" ); // make non-tail recursive16 return rtn;14 nounwind_empty(frames - 1); 15 // "Always" false, but prevents recursion elimination. 16 if (-1 == frames) printf("~"); 17 17 } else { 18 18 int fixup = 17; 19 throwResume (fixup_exception){&fixup_vt, fixup}; // change bad fixup 20 return fixup; 19 throwResume (fixup_exception){&fixup_vt, fixup}; 21 20 } 22 21 } -
doc/theses/andrew_beach_MMath/code/fixup-empty.py
r4e28d2e9 r949339b 25 25 26 26 end_time = thread_time_ns() 27 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.))27 print('Run-Time (s): {:.1f}'.format((end_time - start_time) / 1_000_000_000.)) 28 28 29 29 -
doc/theses/andrew_beach_MMath/code/fixup-other-f.cfa
r4e28d2e9 r949339b 2 2 #include <clock.hfa> 3 3 #include <fstream.hfa> 4 #include <stdlib.hfa> // strto4 #include <stdlib.hfa> 5 5 6 unsigned int frames; // use global because of gcc thunk problem 6 // Using a global value to allow hoisting (and avoid thunks). 7 unsigned int frames; 7 8 8 9 void nounwind_fixup(unsigned int dummy, void (*raised_rtn)(int &), void (*not_raised_rtn)(int &)) { 9 10 void not_raised(int & fixup) { 10 fixup = frames + 42; // use local scope => lexical link11 fixup = frames + 42; 11 12 } 12 13 … … 14 15 frames -= 1; 15 16 nounwind_fixup(42, raised_rtn, not_raised); 17 // Always false, but prevents recursion elimination. 18 if (-1 == frames) printf("~"); 16 19 } else { 17 20 int fixup = dummy; … … 31 34 frames = total_frames; 32 35 36 // Closures at the top level are allowed to be true closures. 33 37 void raised(int & fixup) { 34 fixup = total_frames + 42; // use local scope => lexical link38 fixup = total_frames + 42; 35 39 } 36 40 void not_raised(int & fixup) { 37 fixup = total_frames + 42; // use local scope => lexical link41 fixup = total_frames + 42; 38 42 } 39 43 -
doc/theses/andrew_beach_MMath/code/fixup-other-r.cfa
r4e28d2e9 r949339b 3 3 #include <exception.hfa> 4 4 #include <fstream.hfa> 5 #include <stdlib.hfa> // strto5 #include <stdlib.hfa> 6 6 7 7 exception fixup_exception { … … 13 13 }; 14 14 15 unsigned int frames; // use global because of gcc thunk problem 15 // Using a global value to allow hoisting (and avoid thunks). 16 unsigned int frames; 16 17 17 18 void nounwind_other(unsigned int dummy) { … … 20 21 try { 21 22 nounwind_other(42); 23 // Always false, but prevents recursion elimination. 24 if (-1 == frames) printf("~"); 22 25 } catchResume (not_raised_exception * ex) { 23 ex->fixup = frames + 42; // use local scope => lexical link26 ex->fixup = frames + 42; 24 27 } 25 28 } else { 26 29 int fixup = dummy; 27 throwResume (fixup_exception){&fixup_vt, fixup}; // change bad fixup30 throwResume (fixup_exception){&fixup_vt, fixup}; 28 31 } 29 32 } -
doc/theses/andrew_beach_MMath/code/fixup-other.py
r4e28d2e9 r949339b 27 27 28 28 end_time = thread_time_ns() 29 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.))29 print('Run-Time (s): {:.1f}'.format((end_time - start_time) / 1_000_000_000.)) 30 30 31 31 -
doc/theses/andrew_beach_MMath/code/resume-empty.cfa
r4e28d2e9 r949339b 11 11 if (frames) { 12 12 nounwind_empty(frames - 1); 13 if ( frames == -1 ) printf( "42" ); // prevent recursion optimizations 13 14 } else { 14 15 throwResume (empty_exception){&empty_vt}; -
doc/theses/andrew_beach_MMath/code/run.sh
r4e28d2e9 r949339b 1 1 #!/usr/bin/env bash 2 2 3 readonly ALL_TESTS=(raise-{empty,detor,finally,other} try-{catch,finally} cond-match-{all,none}\4 raise-{fixup-empty,fixup-other})3 readonly ALL_TESTS=(raise-{empty,detor,finally,other} try-{catch,finally} \ 4 cond-match-{all,none} fixup-{empty,other}) 5 5 6 6 gen-file-name() ( … … 18 18 ) 19 19 20 #readonly N=${1:-5}21 20 readonly N=${1:-1} 22 21 readonly OUT_FILE=$(gen-file-name ${2:-run-%-$N}) -
doc/theses/andrew_beach_MMath/code/test.sh
r4e28d2e9 r949339b 13 13 # View the result from TEST in LANGUAGE stored in FILE. 14 14 15 readonly ITERS_1M=1000000 # 1 000 000, one million 16 readonly ITERS_10M=10000000 # 10 000 000, ten million 17 readonly ITERS_100M=100000000 # 100 000 000, hundred million 18 readonly ITERS_1000M=1000000000 # 1 000 000 000, billion 15 readonly DIR=$(dirname "$(readlink -f "$0")") 16 cd $DIR 17 18 readonly MIL=000000 19 # Various preset values used as arguments. 20 readonly ITERS_1M=1$MIL 21 readonly ITERS_10M=10$MIL 22 readonly ITERS_100M=100$MIL 23 readonly ITERS_1000M=1000$MIL 19 24 readonly STACK_HEIGHT=100 20 25 … … 30 35 case "$1" in 31 36 *.cfa) 32 # Requires a symbolic link. 33 mmake "${1%.cfa}" "$1" cfa -DNDEBUG -nodebug -O3 "$1" -o "${1%.cfa}" 37 # A symbolic link/local copy can be used as an override. 38 cmd=./cfa 39 if [ ! -x $cmd ]; then 40 cmd=cfa 41 fi 42 mmake "${1%.cfa}" "$1" $cmd -DNDEBUG -nodebug -O3 "$1" -o "${1%.cfa}" 34 43 ;; 35 44 *.cpp) … … 46 55 ) 47 56 48 if [ "-a" = "$1" ]; then # build all57 if [ "-a" = "$1" ]; then 49 58 for file in *.cfa *.cpp *.java; do 50 59 build $file 51 60 done 52 61 exit 0 53 elif [ "-b" = "$1" ]; then # build given62 elif [ "-b" = "$1" ]; then 54 63 for file in "${@:2}"; do 55 64 build $file 56 65 done 57 66 exit 0 58 elif [ "-c" = "$1" ]; then # clean all67 elif [ "-c" = "$1" ]; then 59 68 rm $(basename -s ".cfa" -a *.cfa) 60 69 rm $(basename -s ".cpp" -a *.cpp) … … 83 92 raise-empty) 84 93 CFAT="./throw-empty $ITERS_1M $STACK_HEIGHT" 85 # see resume-fixup-empty-r CFAR="./resume-empty $ITERS_1M $STACK_HEIGHT"94 CFAR="./resume-empty $ITERS_10M $STACK_HEIGHT" 86 95 CPP="./throw-empty-cpp $ITERS_1M $STACK_HEIGHT" 87 96 JAVA="java ThrowEmpty $ITERS_1M $STACK_HEIGHT" … … 90 99 raise-detor) 91 100 CFAT="./throw-detor $ITERS_1M $STACK_HEIGHT" 92 # N/A CFAR="./resume-detor $ITERS_1M $STACK_HEIGHT"101 CFAR="./resume-detor $ITERS_10M $STACK_HEIGHT" 93 102 CPP="./throw-detor-cpp $ITERS_1M $STACK_HEIGHT" 94 103 JAVA=unsupported … … 97 106 raise-finally) 98 107 CFAT="./throw-finally $ITERS_1M $STACK_HEIGHT" 99 # N/A CFAR="./resume-finally $ITERS_1M $STACK_HEIGHT"108 CFAR="./resume-finally $ITERS_10M $STACK_HEIGHT" 100 109 CPP=unsupported 101 110 JAVA="java ThrowFinally $ITERS_1M $STACK_HEIGHT" … … 104 113 raise-other) 105 114 CFAT="./throw-other $ITERS_1M $STACK_HEIGHT" 106 # N/A CFAR="./resume-other $ITERS_1M $STACK_HEIGHT"115 CFAR="./resume-other $ITERS_10M $STACK_HEIGHT" 107 116 CPP="./throw-other-cpp $ITERS_1M $STACK_HEIGHT" 108 117 JAVA="java ThrowOther $ITERS_1M $STACK_HEIGHT" … … 125 134 cond-match-all) 126 135 CFAT="./cond-catch $ITERS_10M 1" 127 CFAR="./cond-fixup $ITERS_10 M 1"136 CFAR="./cond-fixup $ITERS_100M 1" 128 137 CPP="./cond-catch-cpp $ITERS_10M 1" 129 138 JAVA="java CondCatch $ITERS_10M 1" … … 132 141 cond-match-none) 133 142 CFAT="./cond-catch $ITERS_10M 0" 134 CFAR="./cond-fixup $ITERS_10 M 0"143 CFAR="./cond-fixup $ITERS_100M 0" 135 144 CPP="./cond-catch-cpp $ITERS_10M 0" 136 145 JAVA="java CondCatch $ITERS_10M 0" 137 146 PYTHON="./cond-catch.py $ITERS_10M 0" 138 147 ;; 139 raise-fixup-empty)140 CFAT="./ resume-fixup-empty-f $ITERS_10M $STACK_HEIGHT"141 CFAR="./ resume-fixup-empty-r $ITERS_10M $STACK_HEIGHT"142 CPP="./ resume-fixup-empty-cpp $ITERS_10M $STACK_HEIGHT"143 JAVA="java ResumeFixupEmpty $ITERS_10M $STACK_HEIGHT"144 PYTHON="./ resume-fixup-empty.py $ITERS_10M $STACK_HEIGHT"148 fixup-empty) 149 CFAT="./fixup-empty-f $ITERS_10M $STACK_HEIGHT" 150 CFAR="./fixup-empty-r $ITERS_10M $STACK_HEIGHT" 151 CPP="./fixup-empty-cpp $ITERS_10M $STACK_HEIGHT" 152 JAVA="java FixupEmpty $ITERS_10M $STACK_HEIGHT" 153 PYTHON="./fixup-empty.py $ITERS_10M $STACK_HEIGHT" 145 154 ;; 146 raise-fixup-other)147 CFAT="./ resume-fixup-other-f $ITERS_10M $STACK_HEIGHT"148 CFAR="./ resume-fixup-other-r $ITERS_10M $STACK_HEIGHT"149 CPP="./ resume-fixup-other-cpp $ITERS_10M $STACK_HEIGHT"150 JAVA="java ResumeFixupOther $ITERS_10M $STACK_HEIGHT"151 PYTHON="./ resume-fixup-other.py $ITERS_10M $STACK_HEIGHT"155 fixup-other) 156 CFAT="./fixup-other-f $ITERS_10M $STACK_HEIGHT" 157 CFAR="./fixup-other-r $ITERS_10M $STACK_HEIGHT" 158 CPP="./fixup-other-cpp $ITERS_10M $STACK_HEIGHT" 159 JAVA="java FixupOther $ITERS_10M $STACK_HEIGHT" 160 PYTHON="./fixup-other.py $ITERS_10M $STACK_HEIGHT" 152 161 ;; 153 162 *) … … 158 167 159 168 case "$TEST_LANG" in 160 161 162 163 164 165 166 167 169 cfa-t) CALL="$CFAT";; 170 cfa-r) CALL="$CFAR";; 171 cpp) CALL="$CPP";; 172 java) CALL="$JAVA";; 173 python) CALL="$PYTHON";; 174 *) 175 echo "No such language: $TEST_LANG" >&2 176 exit 2 168 177 ;; 169 178 esac … … 172 181 173 182 if [ -n "$VIEW_FILE" ]; then 174 grep -A 1 -B 0 "$CALL" "$VIEW_FILE" | sed -n -e 's!Run-Time (ns): !!;T;p'183 grep -A 1 -B 0 "$CALL" "$VIEW_FILE" | sed -n -e 's!Run-Time.*: !!;T;p' 175 184 exit 176 185 fi -
doc/theses/andrew_beach_MMath/code/throw-empty.cfa
r4e28d2e9 r949339b 11 11 if (frames) { 12 12 unwind_empty(frames - 1); 13 if ( frames == -1 ) printf( "42" ); // prevent recursion optimizations 13 14 } else { 14 15 throw (empty_exception){&empty_vt}; -
doc/theses/andrew_beach_MMath/code/throw-empty.cpp
r4e28d2e9 r949339b 1 1 // Throw Across Empty Function 2 2 #include <chrono> 3 #include <cstdio> 3 4 #include <cstdlib> 4 5 #include <exception> … … 14 15 if (frames) { 15 16 unwind_empty(frames - 1); 17 if (-1 == frames) printf("~"); 16 18 } else { 17 19 throw (EmptyException){}; -
doc/theses/andrew_beach_MMath/code/throw-empty.py
r4e28d2e9 r949339b 33 33 34 34 end_time = thread_time_ns() 35 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.))35 print('Run-Time (s): {:.1f}'.format((end_time - start_time) / 1_000_000_000.)) 36 36 37 37 -
doc/theses/andrew_beach_MMath/code/throw-finally.py
r4e28d2e9 r949339b 36 36 37 37 end_time = thread_time_ns() 38 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.))38 print('Run-Time (s): {:.1f}'.format((end_time - start_time) / 1_000_000_000.)) 39 39 40 40 -
doc/theses/andrew_beach_MMath/code/throw-other.py
r4e28d2e9 r949339b 40 40 41 41 end_time = thread_time_ns() 42 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.))42 print('Run-Time (s): {:.1f}'.format((end_time - start_time) / 1_000_000_000.)) 43 43 44 44 -
doc/theses/andrew_beach_MMath/code/throw-with.py
r4e28d2e9 r949339b 43 43 44 44 end_time = thread_time_ns() 45 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.))45 print('Run-Time (s): {:.1f}'.format((end_time - start_time) / 1_000_000_000.)) 46 46 47 47 -
doc/theses/andrew_beach_MMath/code/try-catch.py
r4e28d2e9 r949339b 23 23 24 24 end_time = thread_time_ns() 25 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.))25 print('Run-Time (s): {:.1f}'.format((end_time - start_time) / 1_000_000_000.)) 26 26 27 27 -
doc/theses/andrew_beach_MMath/code/try-finally.py
r4e28d2e9 r949339b 22 22 23 23 end_time = thread_time_ns() 24 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.))24 print('Run-Time (s): {:.1f}'.format((end_time - start_time) / 1_000_000_000.)) 25 25 26 26 -
doc/theses/andrew_beach_MMath/conclusion.tex
r4e28d2e9 r949339b 3 3 % Just a little knot to tie the paper together. 4 4 5 In the previous chapters this thesis presents the design and implementation5 In the previous chapters, this thesis presents the design and implementation 6 6 of \CFA's exception handling mechanism (EHM). 7 7 Both the design and implementation are based off of tools and 8 8 techniques developed for other programming languages but they were adapted to 9 9 better fit \CFA's feature set and add a few features that do not exist in 10 other EHMs ;10 other EHMs, 11 11 including conditional matching, default handlers for unhandled exceptions 12 12 and cancellation though coroutines and threads back to the program main stack. -
doc/theses/andrew_beach_MMath/existing.tex
r4e28d2e9 r949339b 6 6 compatibility with C and its programmers. \CFA is designed to have an 7 7 orthogonal feature-set based closely on the C programming paradigm 8 (non-object-oriented) and these features can be added incrementally to an 9 existing C code-base allowing programmers to learn \CFA on an as-needed basis. 8 (non-object-oriented), and these features can be added incrementally to an 9 existing C code-base, 10 allowing programmers to learn \CFA on an as-needed basis. 10 11 11 12 Only those \CFA features pertaining to this thesis are discussed. … … 45 46 \CFA adds a reference type to C as an auto-dereferencing pointer. 46 47 They work very similarly to pointers. 47 Reference-types are written the same way as a pointer-typebut each48 Reference-types are written the same way as pointer-types, but each 48 49 asterisk (@*@) is replaced with a ampersand (@&@); 49 this includes cv-qualifiers and multiple levels of reference. 50 51 Generally, references act like pointers with an implicate dereferencing 50 this includes cv-qualifiers (\snake{const} and \snake{volatile}) 51 and multiple levels of reference. 52 53 Generally, references act like pointers with an implicit dereferencing 52 54 operation added to each use of the variable. 53 55 These automatic dereferences may be disabled with the address-of operator … … 83 85 Mutable references may be assigned to by converting them to a pointer 84 86 with a @&@ and then assigning a pointer to them, as in @&ri = &j;@ above. 85 % ???86 87 87 88 \section{Operators} … … 93 94 For example, 94 95 infixed multiplication is @?*?@, while prefix dereference is @*?@. 95 This syntax make it easy to tell the difference between prefix operations96 (such as @++?@) and post -fix operations (@?++@).96 This syntax makes it easy to tell the difference between prefix operations 97 (such as @++?@) and postfix operations (@?++@). 97 98 98 99 As an example, here are the addition and equality operators for a point type. … … 104 105 } 105 106 \end{cfa} 106 Note that this syntax works effectively but a textual transformation,107 Note that this syntax works effectively as a textual transformation; 107 108 the compiler converts all operators into functions and then resolves them 108 109 normally. This means any combination of types may be used, … … 113 114 %\subsection{Constructors and Destructors} 114 115 In \CFA, constructors and destructors are operators, which means they are 115 functions with special operator names rather than type names in \Cpp.116 functions with special operator names, rather than type names as in \Cpp. 116 117 Both constructors and destructors can be implicity called by the compiler, 117 118 however the operator names allow explicit calls. … … 137 138 @b@ because of the explicit call and @a@ implicitly. 138 139 @c@ will be initalized with the second constructor. 139 Currently, there is no general way to skip initial ation.140 Currently, there is no general way to skip initialization. 140 141 % I don't use @= anywhere in the thesis. 141 142 … … 202 203 do_twice(i); 203 204 \end{cfa} 204 Any objectwith a type fulfilling the assertion may be passed as an argument to205 Any value with a type fulfilling the assertion may be passed as an argument to 205 206 a @do_twice@ call. 206 207 … … 222 223 function. The matched assertion function is then passed as a function pointer 223 224 to @do_twice@ and called within it. 224 The global definition of @do_once@ is ignored, however if quadrupletook a225 The global definition of @do_once@ is ignored, however if @quadruple@ took a 225 226 @double@ argument, then the global definition would be used instead as it 226 227 would then be a better match.\cite{Moss19} 227 228 228 229 To avoid typing long lists of assertions, constraints can be collected into 229 convenient apackage called a @trait@, which can then be used in an assertion230 a convenient package called a @trait@, which can then be used in an assertion 230 231 instead of the individual constraints. 231 232 \begin{cfa} … … 241 242 functions and variables, and are usually used to create a shorthand for, and 242 243 give descriptive names to, common groupings of assertions describing a certain 243 functionality, like @sum able@, @listable@, \etc.244 functionality, like @summable@, @listable@, \etc. 244 245 245 246 Polymorphic structures and unions are defined by qualifying an aggregate type 246 247 with @forall@. The type variables work the same except they are used in field 247 declarations instead of parameters, returns ,and local variable declarations.248 declarations instead of parameters, returns and local variable declarations. 248 249 \begin{cfa} 249 250 forall(dtype T) … … 261 262 262 263 \section{Control Flow} 263 \CFA has a number of advanced control-flow features: @generator@, @coroutine@, @monitor@, @mutex@ parameters, and @thread@. 264 \CFA has a number of advanced control-flow features: @generator@, @coroutine@, 265 @monitor@, @mutex@ parameters, and @thread@. 264 266 The two features that interact with 265 267 the exception system are @coroutine@ and @thread@; they and their supporting … … 268 270 \subsection{Coroutine} 269 271 A coroutine is a type with associated functions, where the functions are not 270 required to finish execution when control is handed back to the caller. Instead 272 required to finish execution when control is handed back to the caller. 273 Instead, 271 274 they may suspend execution at any time and be resumed later at the point of 272 last suspension. (Generators are stackless and coroutines are stackful.) These 275 last suspension. 276 Coroutine 273 277 types are not concurrent but share some similarities along with common 274 underpinnings, so they are combined with the \CFA threading library. Further 275 discussion in this section only refers to the coroutine because generators are 276 similar. 278 underpinnings, so they are combined with the \CFA threading library. 279 % I had mention of generators, but they don't actually matter here. 277 280 278 281 In \CFA, a coroutine is created using the @coroutine@ keyword, which is an … … 322 325 \end{cfa} 323 326 324 When the main function returns the coroutine halts and can no longer be327 When the main function returns, the coroutine halts and can no longer be 325 328 resumed. 326 329 327 330 \subsection{Monitor and Mutex Parameter} 328 Concurrency does not guarantee ordering; without ordering results are331 Concurrency does not guarantee ordering; without ordering, results are 329 332 non-deterministic. To claw back ordering, \CFA uses monitors and @mutex@ 330 333 (mutual exclusion) parameters. A monitor is another kind of aggregate, where … … 332 335 @mutex@ parameters. 333 336 334 A function that requires deterministic (ordered) execution ,acquires mutual337 A function that requires deterministic (ordered) execution acquires mutual 335 338 exclusion on a monitor object by qualifying an object reference parameter with 336 @mutex@.339 the @mutex@ qualifier. 337 340 \begin{cfa} 338 341 void example(MonitorA & mutex argA, MonitorB & mutex argB); … … 344 347 345 348 \subsection{Thread} 346 Functions, generators , and coroutines are sequentialso there is only a single349 Functions, generators and coroutines are sequential, so there is only a single 347 350 (but potentially sophisticated) execution path in a program. Threads introduce 348 351 multiple execution paths that continue independently. 349 352 350 353 For threads to work safely with objects requires mutual exclusion using 351 monitors and mutex parameters. For threads to work safely with other threads ,354 monitors and mutex parameters. For threads to work safely with other threads 352 355 also requires mutual exclusion in the form of a communication rendezvous, which 353 356 also supports internal synchronization as for mutex objects. For exceptions, -
doc/theses/andrew_beach_MMath/features.tex
r4e28d2e9 r949339b 5 5 and begins with a general overview of EHMs. It is not a strict 6 6 definition of all EHMs nor an exhaustive list of all possible features. 7 However it does cover the most common structure and features found in them.7 However, it does cover the most common structure and features found in them. 8 8 9 9 \section{Overview of EHMs} … … 42 42 43 43 The @try@ statements of \Cpp, Java and Python are common examples. All three 44 also show another common feature of handlers ,they are grouped by the guarded44 also show another common feature of handlers: they are grouped by the guarded 45 45 region. 46 46 … … 84 84 \paragraph{Hierarchy} 85 85 A common way to organize exceptions is in a hierarchical structure. 86 This pattern comes from object-orient ated languages where the86 This pattern comes from object-oriented languages where the 87 87 exception hierarchy is a natural extension of the object hierarchy. 88 88 … … 101 101 between different sub-hierarchies. 102 102 This design is used in \CFA even though it is not a object-orientated 103 language ;so different tools are used to create the hierarchy.103 language, so different tools are used to create the hierarchy. 104 104 105 105 % Could I cite the rational for the Python IO exception rework? … … 118 118 For effective exception handling, additional information is often passed 119 119 from the raise to the handler and back again. 120 So far, only communication of the exception s'identity is covered.120 So far, only communication of the exception's identity is covered. 121 121 A common communication method for adding information to an exception 122 122 is putting fields into the exception instance … … 129 129 \section{Virtuals} 130 130 \label{s:virtuals} 131 A common feature in many programming languages is a tool to pair code 132 (behaviour) with data. 133 In \CFA, this is done with the virtual system, 134 which allow type information to be abstracted away, recovered and allow 135 operations to be performed on the abstract objects. 136 131 137 Virtual types and casts are not part of \CFA's EHM nor are they required for 132 138 an EHM. … … 152 158 % A type's descendants are its children and its children's descendants. 153 159 154 For the purposes of illustration, a proposed -- but unimplemented syntax --160 For the purposes of illustration, a proposed, but unimplemented, syntax 155 161 will be used. Each virtual type is represented by a trait with an annotation 156 162 that makes it a virtual type. This annotation is empty for a root type, which … … 177 183 \end{minipage} 178 184 179 Every virtual type also has a list of virtual members and a unique id ,180 both are stored in a virtual table.185 Every virtual type also has a list of virtual members and a unique id. 186 Both are stored in a virtual table. 181 187 Every instance of a virtual type also has a pointer to a virtual table stored 182 188 in it, although there is no per-type virtual table as in many other languages. 183 189 184 The list of virtual members is built up down the tree. Every virtual type 190 The list of virtual members is accumulated from the root type down the tree. 191 Every virtual type 185 192 inherits the list of virtual members from its parent and may add more 186 193 virtual members to the end of the list which are passed on to its children. … … 198 205 % Consider adding a diagram, but we might be good with the explanation. 199 206 200 As @child_type@ is a child of @root_type@ it has the virtual members of207 As @child_type@ is a child of @root_type@, it has the virtual members of 201 208 @root_type@ (@to_string@ and @size@) as well as the one it declared 202 209 (@irrelevant_function@). … … 206 213 The names ``size" and ``align" are reserved for the size and alignment of the 207 214 virtual type, and are always automatically initialized as such. 208 The other special case areuses of the trait's polymorphic argument215 The other special case is uses of the trait's polymorphic argument 209 216 (@T@ in the example), which are always updated to refer to the current 210 virtual type. This allows functions that refer to t opolymorphic argument217 virtual type. This allows functions that refer to the polymorphic argument 211 218 to act as traditional virtual methods (@to_string@ in the example), as the 212 219 object can always be passed to a virtual method in its virtual table. 213 220 214 Up until this point the virtual system is similar to ones found in215 object-oriented languages but this is where \CFA diverges.221 Up until this point, the virtual system is similar to ones found in 222 object-oriented languages, but this is where \CFA diverges. 216 223 Objects encapsulate a single set of methods in each type, 217 224 universally across the entire program, … … 223 230 224 231 In \CFA, types do not encapsulate any code. 225 Whether or not satisfies any given assertion, and hence any trait, is232 Whether or not a type satisfies any given assertion, and hence any trait, is 226 233 context sensitive. Types can begin to satisfy a trait, stop satisfying it or 227 234 satisfy the same trait at any lexical location in the program. 228 In this sense, a ntype's implementation in the set of functions and variables235 In this sense, a type's implementation in the set of functions and variables 229 236 that allow it to satisfy a trait is ``open" and can change 230 237 throughout the program. … … 248 255 \end{cfa} 249 256 250 Like any variable they may be forward declared with the @extern@ keyword.257 Like any variable, they may be forward declared with the @extern@ keyword. 251 258 Forward declaring virtual tables is relatively common. 252 259 Many virtual types have an ``obvious" implementation that works in most … … 259 266 Initialization is automatic. 260 267 The type id and special virtual members ``size" and ``align" only depend on 261 the virtual type, which is fixed given the type of the virtual table and268 the virtual type, which is fixed given the type of the virtual table, and 262 269 so the compiler fills in a fixed value. 263 The other virtual members are resolved ,using the best match to the member's270 The other virtual members are resolved using the best match to the member's 264 271 name and type, in the same context as the virtual table is declared using 265 272 \CFA's normal resolution rules. 266 273 267 While much of the virtual infrastructure is created, it is currently only used 274 While much of the virtual infrastructure has been created, 275 it is currently only used 268 276 internally for exception handling. The only user-level feature is the virtual 269 277 cast, which is the same as the \Cpp \code{C++}{dynamic_cast}. … … 274 282 Note, the syntax and semantics matches a C-cast, rather than the function-like 275 283 \Cpp syntax for special casts. Both the type of @EXPRESSION@ and @TYPE@ must be 276 a pointer to a virtual type.284 pointers to virtual types. 277 285 The cast dynamically checks if the @EXPRESSION@ type is the same or a sub-type 278 286 of @TYPE@, and if true, returns a pointer to the 279 287 @EXPRESSION@ object, otherwise it returns @0p@ (null pointer). 288 This allows the expression to be used as both a cast and a type check. 280 289 281 290 \section{Exceptions} 282 291 283 292 The syntax for declaring an exception is the same as declaring a structure 284 except the keyword that is swapped out:293 except the keyword: 285 294 \begin{cfa} 286 295 exception TYPE_NAME { … … 289 298 \end{cfa} 290 299 291 Fields are filled in the same way as a structure as well. However an extra300 Fields are filled in the same way as a structure as well. However, an extra 292 301 field is added that contains the pointer to the virtual table. 293 302 It must be explicitly initialized by the user when the exception is … … 299 308 300 309 \begin{minipage}[t]{0.4\textwidth} 301 Header :310 Header (.hfa): 302 311 \begin{cfa} 303 312 exception Example { … … 310 319 \end{minipage} 311 320 \begin{minipage}[t]{0.6\textwidth} 312 Source:321 Implementation (.cfa): 313 322 \begin{cfa} 314 323 vtable(Example) example_base_vtable … … 319 328 %\subsection{Exception Details} 320 329 This is the only interface needed when raising and handling exceptions. 321 However it is actually a shorthand for a more complex322 trait 330 However, it is actually a shorthand for a more complex 331 trait-based interface. 323 332 324 333 The language views exceptions through a series of traits. … … 336 345 completing the virtual system). The imaginary assertions would probably come 337 346 from a trait defined by the virtual system, and state that the exception type 338 is a virtual type, is a descendant of @exception_t@ (the base exception type) 347 is a virtual type, 348 that that the type is a descendant of @exception_t@ (the base exception type) 339 349 and allow the user to find the virtual table type. 340 350 … … 355 365 }; 356 366 \end{cfa} 357 Both traits ensure a pair of types is an exception type , its virtual table358 type 367 Both traits ensure a pair of types is an exception type and 368 its virtual table type, 359 369 and defines one of the two default handlers. The default handlers are used 360 as fallbacks and are discussed in detail in \ vref{s:ExceptionHandling}.370 as fallbacks and are discussed in detail in \autoref{s:ExceptionHandling}. 361 371 362 372 However, all three of these traits can be tricky to use directly. 363 373 While there is a bit of repetition required, 364 374 the largest issue is that the virtual table type is mangled and not in a user 365 facing way. So these three macros are provided to wrap these traits to375 facing way. So, these three macros are provided to wrap these traits to 366 376 simplify referring to the names: 367 377 @IS_EXCEPTION@, @IS_TERMINATION_EXCEPTION@ and @IS_RESUMPTION_EXCEPTION@. … … 371 381 The second (optional) argument is a parenthesized list of polymorphic 372 382 arguments. This argument is only used with polymorphic exceptions and the 373 list is bepassed to both types.383 list is passed to both types. 374 384 In the current set-up, the two types always have the same polymorphic 375 arguments so these macros can be used without losing flexibility.376 377 For example consider a function that is polymorphic over types that have a385 arguments, so these macros can be used without losing flexibility. 386 387 For example, consider a function that is polymorphic over types that have a 378 388 defined arithmetic exception: 379 389 \begin{cfa} … … 388 398 These twin operations are the core of \CFA's exception handling mechanism. 389 399 This section covers the general patterns shared by the two operations and 390 then goes on to cover the details each individual operation.400 then goes on to cover the details of each individual operation. 391 401 392 402 Both operations follow the same set of steps. … … 407 417 \label{s:Termination} 408 418 Termination handling is the familiar kind of handling 409 andused in most programming419 used in most programming 410 420 languages with exception handling. 411 421 It is a dynamic, non-local goto. If the raised exception is matched and … … 483 493 Since it is so general, a more specific handler can be defined, 484 494 overriding the default behaviour for the specific exception types. 495 496 For example, consider an error reading a configuration file. 497 This is most likely a problem with the configuration file (@config_error@), 498 but the function could have been passed the wrong file name (@arg_error@). 499 In this case the function could raise one exception and then, if it is 500 unhandled, raise the other. 501 This is not usual behaviour for either exception so changing the 502 default handler will be done locally: 503 \begin{cfa} 504 { 505 void defaultTerminationHandler(config_error &) { 506 throw (arg_error){arg_vt}; 507 } 508 throw (config_error){config_vt}; 509 } 510 \end{cfa} 485 511 486 512 \subsection{Resumption} … … 542 568 @EXCEPTION_TYPE@$_i$ is matched and @NAME@$_i$ is bound to the exception, 543 569 @HANDLER_BLOCK@$_i$ is executed right away without first unwinding the stack. 544 After the block has finished running control jumps to the raise site, where570 After the block has finished running, control jumps to the raise site, where 545 571 the just handled exception came from, and continues executing after it, 546 572 not after the try statement. 573 574 For instance, a resumption used to send messages to the logger may not 575 need to be handled at all. Putting the following default handler 576 at the global scope can make handling that exception optional by default. 577 \begin{cfa} 578 void defaultResumptionHandler(log_message &) { 579 // Nothing, it is fine not to handle logging. 580 } 581 // ... No change at raise sites. ... 582 throwResume (log_message){strlit_log, "Begin event processing."} 583 \end{cfa} 547 584 548 585 \subsubsection{Resumption Marking} … … 551 588 not unwind the stack. A side effect is that, when a handler is matched 552 589 and run, its try block (the guarded statements) and every try statement 553 searched before it are still on the stack. The represence can lead to590 searched before it are still on the stack. Their presence can lead to 554 591 the recursive resumption problem.\cite{Buhr00a} 555 592 % Other possible citation is MacLaren77, but the form is different. … … 585 622 \end{center} 586 623 587 There are other sets of marking rules that could be used ,588 for instance, marking just the handlers that caught the exception, 624 There are other sets of marking rules that could be used. 625 For instance, marking just the handlers that caught the exception 589 626 would also prevent recursive resumption. 590 However, the rules selected mirror swhat happens with termination,627 However, the rules selected mirror what happens with termination, 591 628 so this reduces the amount of rules and patterns a programmer has to know. 592 629 … … 628 665 // Handle a failure relating to f2 further down the stack. 629 666 \end{cfa} 630 In this example the file that experienced the IO error is used to decide667 In this example, the file that experienced the IO error is used to decide 631 668 which handler should be run, if any at all. 632 669 … … 657 694 658 695 \subsection{Comparison with Reraising} 659 In languages without conditional catch , that isno ability to match an660 exception based on something other than its type ,it can be mimicked696 In languages without conditional catch -- that is, no ability to match an 697 exception based on something other than its type -- it can be mimicked 661 698 by matching all exceptions of the right type, checking any additional 662 699 conditions inside the handler and re-raising the exception if it does not … … 664 701 665 702 Here is a minimal example comparing both patterns, using @throw;@ 666 (no argument) to start a re-raise.703 (no operand) to start a re-raise. 667 704 \begin{center} 668 705 \begin{tabular}{l r} … … 692 729 \end{tabular} 693 730 \end{center} 694 At first glance catch-and-reraise may appear to just be a quality oflife731 At first glance, catch-and-reraise may appear to just be a quality-of-life 695 732 feature, but there are some significant differences between the two 696 strat agies.733 strategies. 697 734 698 735 A simple difference that is more important for \CFA than many other languages 699 is that the raise site changes , with a re-raisebut does not with a736 is that the raise site changes with a re-raise, but does not with a 700 737 conditional catch. 701 738 This is important in \CFA because control returns to the raise site to run 702 the per-site default handler. Because of this only a conditional catch can739 the per-site default handler. Because of this, only a conditional catch can 703 740 allow the original raise to continue. 704 741 … … 753 790 % } else throw; 754 791 % } 755 In similar simple examples translating from re-raise to conditional catch756 takes less code but it does not have a general trivial solution either.792 In similar simple examples, translating from re-raise to conditional catch 793 takes less code but it does not have a general, trivial solution either. 757 794 758 795 So, given that the two patterns do not trivially translate into each other, 759 796 it becomes a matter of which on should be encouraged and made the default. 760 From the premise that if a handler thatcould handle an exception then it797 From the premise that if a handler could handle an exception then it 761 798 should, it follows that checking as many handlers as possible is preferred. 762 So conditional catch and checking later handlers is a good default.799 So, conditional catch and checking later handlers is a good default. 763 800 764 801 \section{Finally Clauses} 765 802 \label{s:FinallyClauses} 766 Finally clauses are used to p reform unconditional clean-up when leaving a803 Finally clauses are used to perform unconditional cleanup when leaving a 767 804 scope and are placed at the end of a try statement after any handler clauses: 768 805 \begin{cfa} … … 782 819 Execution of the finally block should always finish, meaning control runs off 783 820 the end of the block. This requirement ensures control always continues as if 784 the finally clause is not present, \ie finally is for cleanup not changing821 the finally clause is not present, \ie finally is for cleanup, not changing 785 822 control flow. 786 823 Because of this requirement, local control flow out of the finally block 787 824 is forbidden. The compiler precludes any @break@, @continue@, @fallthru@ or 788 825 @return@ that causes control to leave the finally block. Other ways to leave 789 the finally block, such as a long jumpor termination are much harder to check,790 and at best requir ingadditional run-time overhead, and so are only826 the finally block, such as a @longjmp@ or termination are much harder to check, 827 and at best require additional run-time overhead, and so are only 791 828 discouraged. 792 829 793 Not all languages with unwinding have finally clauses. Notably \Cpp does830 Not all languages with unwinding have finally clauses. Notably, \Cpp does 794 831 without it as destructors, and the RAII design pattern, serve a similar role. 795 832 Although destructors and finally clauses can be used for the same cases, … … 798 835 Destructors take more work to create, but if there is clean-up code 799 836 that needs to be run every time a type is used, they are much easier 800 to set -up for each use. % It's automatic.801 On the other hand finally clauses capture the local context, so iseasy to802 use when the clean -up is not dependent on the type of a variable or requires837 to set up for each use. % It's automatic. 838 On the other hand, finally clauses capture the local context, so are easy to 839 use when the cleanup is not dependent on the type of a variable or requires 803 840 information from multiple variables. 804 841 … … 807 844 Cancellation is a stack-level abort, which can be thought of as as an 808 845 uncatchable termination. It unwinds the entire current stack, and if 809 possible forwards the cancellation exception to a different stack.846 possible, forwards the cancellation exception to a different stack. 810 847 811 848 Cancellation is not an exception operation like termination or resumption. 812 849 There is no special statement for starting a cancellation; instead the standard 813 library function @cancel_stack@ is called passing an exception. Unlike a814 raise, this exception is not used in matching only to pass information about850 library function @cancel_stack@ is called, passing an exception. Unlike a 851 raise, this exception is not used in matching, only to pass information about 815 852 the cause of the cancellation. 816 853 Finally, as no handler is provided, there is no default handler. 817 854 818 After @cancel_stack@ is called the exception is copied into the EHM's memory855 After @cancel_stack@ is called, the exception is copied into the EHM's memory 819 856 and the current stack is unwound. 820 857 The behaviour after that depends on the kind of stack being cancelled. 821 858 822 859 \paragraph{Main Stack} 823 The main stack is the one used by the program main at the start of execution, 860 The main stack is the one used by 861 the program's main function at the start of execution, 824 862 and is the only stack in a sequential program. 825 After the main stack is unwound there is a program-level abort.863 After the main stack is unwound, there is a program-level abort. 826 864 827 865 The first reason for this behaviour is for sequential programs where there 828 is only one stack, and hence to stack to pass information to.866 is only one stack, and hence no stack to pass information to. 829 867 Second, even in concurrent programs, the main stack has no dependency 830 868 on another stack and no reliable way to find another living stack. … … 842 880 and an implicit join (from a destructor call). The explicit join takes the 843 881 default handler (@defaultResumptionHandler@) from its calling context while 844 the implicit join provides its own ;which does a program abort if the882 the implicit join provides its own, which does a program abort if the 845 883 @ThreadCancelled@ exception cannot be handled. 846 884 … … 870 908 After a coroutine stack is unwound, control returns to the @resume@ function 871 909 that most recently resumed it. @resume@ reports a 872 @CoroutineCancelled@ exception, which contains a reference sto the cancelled910 @CoroutineCancelled@ exception, which contains a reference to the cancelled 873 911 coroutine and the exception used to cancel it. 874 912 The @resume@ function also takes the \defaultResumptionHandler{} from the -
doc/theses/andrew_beach_MMath/future.tex
r4e28d2e9 r949339b 3 3 4 4 The following discussion covers both possible interesting research 5 that could follow from this work as longas simple implementation5 that could follow from this work as well as simple implementation 6 6 improvements. 7 7 … … 10 10 \CFA is a developing programming language. As such, there are partially or 11 11 unimplemented features (including several broken components) 12 that I had to work around while building the EHM largely in12 that I had to work around while building the EHM largely in 13 13 the \CFA language (some C components). Below are a few of these issues 14 14 and how implementing/fixing them would affect the EHM. 15 In addition there are some simple improvements that had no interesting15 In addition, there are some simple improvements that had no interesting 16 16 research attached to them but would make using the language easier. 17 17 \begin{itemize} … … 28 28 Termination handlers cannot use local control-flow transfers, \eg by @break@, 29 29 @return@, \etc. The reason is that current code generation hoists a handler 30 into a nested function for convenience (versus assembl e-code generation at the30 into a nested function for convenience (versus assembly-code generation at the 31 31 try statement). Hence, when the handler runs, it can still access local 32 32 variables in the lexical scope of the try statement. Still, it does mean 33 33 that seemingly local control flow is not in fact local and crosses a function 34 34 boundary. 35 Making the termination handler s code within the surrounding35 Making the termination handler's code within the surrounding 36 36 function would remove this limitation. 37 37 % Try blocks are much more difficult to do practically (requires our own 38 38 % assembly) and resumption handlers have some theoretical complexity. 39 39 \item 40 There is no detection of colliding unwinds. It is possible for clean -up code41 run during an unwind to trigger another unwind that escapes the clean -up code42 itself ;such as a termination exception caught further down the stack or a40 There is no detection of colliding unwinds. It is possible for cleanup code 41 run during an unwind to trigger another unwind that escapes the cleanup code 42 itself, such as a termination exception caught further down the stack or a 43 43 cancellation. There do exist ways to handle this case, but currently there is 44 44 no detection and the first unwind will simply be forgotten, often leaving … … 64 64 Other features of the virtual system could also remove some of the 65 65 special cases around exception virtual tables, such as the generation 66 of the @msg@ function , could be removed.66 of the @msg@ function. 67 67 68 68 The full virtual system might also include other improvement like associated … … 74 74 \section{Additional Raises} 75 75 Several other kinds of exception raises were considered beyond termination 76 (@throw@), resumption (@throwResume@), and re raise.76 (@throw@), resumption (@throwResume@), and re-raise. 77 77 78 78 The first is a non-local/concurrent raise providing asynchronous exceptions, … … 110 110 passed on. 111 111 112 However checked exceptions were never seriously considered for this project112 Checked exceptions were never seriously considered for this project 113 113 because they have significant trade-offs in usability and code reuse in 114 114 exchange for the increased safety. … … 116 116 higher-order functions from the functions the user passed into the 117 117 higher-order function. There are no well known solutions to this problem 118 that were satisfactory for \CFA (which carries some of C's flexibility119 oversafety design) so additional research is needed.118 that were satisfactory for \CFA (which carries some of C's 119 flexibility-over-safety design) so additional research is needed. 120 120 121 121 Follow-up work might add some form of checked exceptions to \CFA, … … 140 140 Zero-cost resumptions is still an open problem. First, because libunwind does 141 141 not support a successful-exiting stack-search without doing an unwind. 142 Workarounds are possible but awkward. Ideally an extension to libunwind could142 Workarounds are possible but awkward. Ideally, an extension to libunwind could 143 143 be made, but that would either require separate maintenance or gaining enough 144 144 support to have it folded into the official library itself. 145 145 146 Also new techniques to skip previously searched parts of the stack need to be146 Also, new techniques to skip previously searched parts of the stack need to be 147 147 developed to handle the recursive resume problem and support advanced algebraic 148 148 effects. -
doc/theses/andrew_beach_MMath/implement.tex
r4e28d2e9 r949339b 14 14 \label{s:VirtualSystem} 15 15 % Virtual table rules. Virtual tables, the pointer to them and the cast. 16 While the \CFA virtual system currently has only onepublic features, virtual16 While the \CFA virtual system currently has only two public features, virtual 17 17 cast and virtual tables, 18 % ??? refs (see the virtual cast feature \vpageref{p:VirtualCast}),19 18 substantial structure is required to support them, 20 19 and provide features for exception handling and the standard library. … … 35 34 as part of field-by-field construction. 36 35 37 \subsection{Type I d}38 Every virtual type has a unique id.36 \subsection{Type ID} 37 Every virtual type has a unique ID. 39 38 These are used in type equality, to check if the representation of two values 40 39 are the same, and to access the type's type information. … … 44 43 45 44 Our approach for program uniqueness is using a static declaration for each 46 type id, where the run-time storage address of that variable is guaranteed to45 type ID, where the run-time storage address of that variable is guaranteed to 47 46 be unique during program execution. 48 The type idstorage can also be used for other purposes,47 The type ID storage can also be used for other purposes, 49 48 and is used for type information. 50 49 51 The problem is that a type idmay appear in multiple TUs that compose a52 program (see \autoref{ss:VirtualTable}) ;so the initial solution would seem53 to be make it external in each translation unit. Ho vever, the type idmust50 The problem is that a type ID may appear in multiple TUs that compose a 51 program (see \autoref{ss:VirtualTable}), so the initial solution would seem 52 to be make it external in each translation unit. However, the type ID must 54 53 have a declaration in (exactly) one of the TUs to create the storage. 55 54 No other declaration related to the virtual type has this property, so doing 56 55 this through standard C declarations would require the user to do it manually. 57 56 58 Instead the linker is used to handle this problem.57 Instead, the linker is used to handle this problem. 59 58 % I did not base anything off of C++17; they are solving the same problem. 60 59 A new feature has been added to \CFA for this purpose, the special attribute 61 60 \snake{cfa_linkonce}, which uses the special section @.gnu.linkonce@. 62 When used as a prefix (\eg @.gnu.linkonce.example@) the linker does61 When used as a prefix (\eg @.gnu.linkonce.example@), the linker does 63 62 not combine these sections, but instead discards all but one with the same 64 63 full name. 65 64 66 So each type id must be given a unique section name with the linkonce67 prefix. Luckily \CFA already has a way to get unique names, the name mangler.65 So, each type ID must be given a unique section name with the \snake{linkonce} 66 prefix. Luckily, \CFA already has a way to get unique names, the name mangler. 68 67 For example, this could be written directly in \CFA: 69 68 \begin{cfa} … … 74 73 __attribute__((section(".gnu.linkonce._X1fFv___1"))) void _X1fFv___1() {} 75 74 \end{cfa} 76 This is done internally to access the name mangler s.75 This is done internally to access the name mangler. 77 76 This attribute is useful for other purposes, any other place a unique 78 77 instance required, and should eventually be made part of a public and … … 81 80 \subsection{Type Information} 82 81 83 There is data stored at the type id's declaration, the type information.84 The type information currently is only the parent's type idor, if the82 There is data stored at the type ID's declaration, the type information. 83 The type information currently is only the parent's type ID or, if the 85 84 type has no parent, the null pointer. 86 The ancestors of a virtual type are found by traversing type ids through85 The ancestors of a virtual type are found by traversing type IDs through 87 86 the type information. 88 87 An example using helper macros looks like: … … 105 104 \item 106 105 Generate a new structure definition to store the type 107 information. The layout is the same in each case, just the parent's type id,106 information. The layout is the same in each case, just the parent's type ID, 108 107 but the types used change from instance to instance. 109 108 The generated name is used for both this structure and, if relevant, the … … 115 114 \item 116 115 The definition is generated and initialized. 117 The parent idis set to the null pointer or to the address of the parent's116 The parent ID is set to the null pointer or to the address of the parent's 118 117 type information instance. Name resolution handles the rest. 119 118 \item … … 151 150 file as if it was a forward declaration, except no definition is required. 152 151 153 This technique is used for type -idinstances. A link-once definition is152 This technique is used for type ID instances. A link-once definition is 154 153 generated each time the structure is seen. This will result in multiple 155 154 copies but the link-once attribute ensures all but one are removed for a … … 168 167 \subsection{Virtual Table} 169 168 \label{ss:VirtualTable} 170 Each virtual type has a virtual table type that stores its type idand169 Each virtual type has a virtual table type that stores its type ID and 171 170 virtual members. 172 Each virtual type instance is bound to a table instance that is filled with 173 the values of virtual members. 174 Both the layout of the fields and their value are decided by the rules given 171 An instance of a virtual type is bound to a virtual table instance, 172 which have the values of the virtual members. 173 Both the layout of the fields (in the virtual table type) 174 and their value (in the virtual table instance) are decided by the rules given 175 175 below. 176 176 177 177 The layout always comes in three parts (see \autoref{f:VirtualTableLayout}). 178 The first section is just the type idat the head of the table. It is always178 The first section is just the type ID at the head of the table. It is always 179 179 there to ensure that it can be found even when the accessing code does not 180 180 know which virtual type it has. 181 The second section areall the virtual members of the parent, in the same181 The second section is all the virtual members of the parent, in the same 182 182 order as they appear in the parent's virtual table. Note that the type may 183 183 change slightly as references to the ``this" change. This is limited to … … 199 199 This, combined with the fixed offset to the virtual table pointer, means that 200 200 for any virtual type, it is always safe to access its virtual table and, 201 from there, it is safe to check the type idto identify the exact type of the201 from there, it is safe to check the type ID to identify the exact type of the 202 202 underlying object, access any of the virtual members and pass the object to 203 203 any of the method-like virtual members. … … 207 207 the context of the declaration. 208 208 209 The type id is always fixed;with each virtual table type having210 exactly one possible type id.209 The type ID is always fixed, with each virtual table type having 210 exactly one possible type ID. 211 211 The virtual members are usually filled in by type resolution. 212 212 The best match for a given name and type at the declaration site is used. 213 213 There are two exceptions to that rule: the @size@ field, the type's size, 214 is set using a @sizeof@ expression and the @align@ field, the214 is set using a @sizeof@ expression, and the @align@ field, the 215 215 type's alignment, is set using an @alignof@ expression. 216 216 217 217 Most of these tools are already inside the compiler. Using simple 218 code transformations early on in compilation ,allows most of that work to be218 code transformations early on in compilation allows most of that work to be 219 219 handed off to the existing tools. \autoref{f:VirtualTableTransformation} 220 shows an example transformation ,this example shows an exception virtual table.220 shows an example transformation; this example shows an exception virtual table. 221 221 It also shows the transformation on the full declaration. 222 222 For a forward declaration, the @extern@ keyword is preserved and the … … 312 312 struct __cfavir_type_id * const * child ); 313 313 \end{cfa} 314 The type idfor the target type of the virtual cast is passed in as314 The type ID for the target type of the virtual cast is passed in as 315 315 @parent@ and 316 316 the cast target is passed in as @child@. … … 322 322 The virtual cast either returns the original pointer or the null pointer 323 323 as the new type. 324 So the function does the parent check and returns the appropriate value.325 The parent check is a simple linear search of child's ancestors using the324 The function does the parent check and returns the appropriate value. 325 The parent check is a simple linear search of the child's ancestors using the 326 326 type information. 327 327 … … 329 329 % The implementation of exception types. 330 330 331 Creating exceptions can roughly divided into two parts,331 Creating exceptions can be roughly divided into two parts: 332 332 the exceptions themselves and the virtual system interactions. 333 333 … … 361 361 362 362 All types associated with a virtual type, 363 the types of the virtual table and the type id,363 the types of the virtual table and the type ID, 364 364 are generated when the virtual type (the exception) is first found. 365 The type id(the instance) is generated with the exception, if it is365 The type ID (the instance) is generated with the exception, if it is 366 366 a monomorphic type. 367 However, if the exception is polymorphic, then a different type idhas to367 However, if the exception is polymorphic, then a different type ID has to 368 368 be generated for every instance. In this case, generation is delayed 369 369 until a virtual table is created. … … 372 372 When a virtual table is created and initialized, two functions are created 373 373 to fill in the list of virtual members. 374 The first is a copyfunction that adapts the exception's copy constructor374 The first is the @copy@ function that adapts the exception's copy constructor 375 375 to work with pointers, avoiding some issues with the current copy constructor 376 376 interface. 377 Second is the msgfunction that returns a C-string with the type's name,377 Second is the @msg@ function that returns a C-string with the type's name, 378 378 including any polymorphic parameters. 379 379 … … 402 402 403 403 % Discussing multiple frame stack unwinding: 404 Unwinding across multiple stack frames is more complex because that404 Unwinding across multiple stack frames is more complex, because that 405 405 information is no longer contained within the current function. 406 406 With separate compilation, 407 407 a function does not know its callers nor their frame layout. 408 408 Even using the return address, that information is encoded in terms of 409 actions in code, intermixed with the actions required finish the function.409 actions in code, intermixed with the actions required to finish the function. 410 410 Without changing the main code path it is impossible to select one of those 411 411 two groups of actions at the return site. 412 412 413 The traditional unwinding mechanism for C is implemented by saving a snap -shot414 of a function's state with @setjmp@ and restoring that snap -shot with413 The traditional unwinding mechanism for C is implemented by saving a snapshot 414 of a function's state with @setjmp@ and restoring that snapshot with 415 415 @longjmp@. This approach bypasses the need to know stack details by simply 416 reseting to a snap-shot of an arbitrary but existing function frame on the 417 stack. It is up to the programmer to ensure the snap-shot is valid when it is 418 reset and that all required clean-up from the unwound stacks is performed. 419 This approach is fragile and requires extra work in the surrounding code. 416 resetting to a snapshot of an arbitrary but existing function frame on the 417 stack. It is up to the programmer to ensure the snapshot is valid when it is 418 reset and that all required cleanup from the unwound stacks is performed. 419 Because it does not automate or check any of this cleanup, 420 it can be easy to make mistakes and always must be handled manually. 420 421 421 422 With respect to the extra work in the surrounding code, 422 many languages define clean -up actions that must be taken when certain423 sections of the stack are removed . Such as when the storage for a variable423 many languages define cleanup actions that must be taken when certain 424 sections of the stack are removed, such as when the storage for a variable 424 425 is removed from the stack, possibly requiring a destructor call, 425 426 or when a try statement with a finally clause is 426 427 (conceptually) popped from the stack. 427 None of these cases should be handled by the user -- -that would contradict the428 intention of these features -- -so they need to be handled automatically.428 None of these cases should be handled by the user -- that would contradict the 429 intention of these features -- so they need to be handled automatically. 429 430 430 431 To safely remove sections of the stack, the language must be able to find and 431 run these clean -up actions even when removing multiple functions unknown at432 run these cleanup actions even when removing multiple functions unknown at 432 433 the beginning of the unwinding. 433 434 … … 435 436 library that provides tools for stack walking, handler execution, and 436 437 unwinding. What follows is an overview of all the relevant features of 437 libunwind needed for this work, and how \CFA uses them to implement exception 438 handling. 438 libunwind needed for this work. 439 Following that is the description of the \CFA code that uses libunwind 440 to implement termination. 439 441 440 442 \subsection{libunwind Usage} … … 529 531 provided storage object. It has two public fields: the @exception_class@, 530 532 which is described above, and the @exception_cleanup@ function. 531 The clean -up function is used by the EHM to clean-up the exception, if it533 The cleanup function is used by the EHM to clean up the exception. If it 532 534 should need to be freed at an unusual time, it takes an argument that says 533 535 why it had to be cleaned up. … … 551 553 of the most recent stack frame. It continues to call personality functions 552 554 traversing the stack from newest to oldest until a function finds a handler or 553 the end of the stack is reached. In the latter case, raise exception returns554 @_U RC_END_OF_STACK@.555 556 Second, when a handler is matched, raise exception moves to the clean-up557 phase and walks the stack a second time.555 the end of the stack is reached. In the latter case, 556 @_Unwind_RaiseException@ returns @_URC_END_OF_STACK@. 557 558 Second, when a handler is matched, @_Unwind_RaiseException@ 559 moves to the cleanup phase and walks the stack a second time. 558 560 Once again, it calls the personality functions of each stack frame from newest 559 561 to oldest. This pass stops at the stack frame containing the matching handler. 560 If that personality function has not install a handler, it is an error.561 562 If an error is encountered, raise exceptionreturns either562 If that personality function has not installed a handler, it is an error. 563 564 If an error is encountered, @_Unwind_RaiseException@ returns either 563 565 @_URC_FATAL_PHASE1_ERROR@ or @_URC_FATAL_PHASE2_ERROR@ depending on when the 564 566 error occurred. … … 571 573 _Unwind_Stop_Fn, void *); 572 574 \end{cfa} 573 It also unwinds the stack but it does not use the search phase. Instead another 575 It also unwinds the stack but it does not use the search phase. Instead, 576 another 574 577 function, the stop function, is used to stop searching. The exception is the 575 same as the one passed to raise exception. The extra arguments are the stop 578 same as the one passed to @_Unwind_RaiseException@. 579 The extra arguments are the stop 576 580 function and the stop parameter. The stop function has a similar interface as a 577 581 personality function, except it is also passed the stop parameter. … … 721 725 one list per stack, with the 722 726 list head stored in the exception context. Within each linked list, the most 723 recently thrown exception is at the head followed by older thrown727 recently thrown exception is at the head, followed by older thrown 724 728 exceptions. This format allows exceptions to be thrown, while a different 725 729 exception is being handled. The exception at the head of the list is currently … … 732 736 exception into managed memory. After the exception is handled, the free 733 737 function is used to clean up the exception and then the entire node is 734 passed to free, returning the memory back to the heap.738 passed to @free@, returning the memory back to the heap. 735 739 736 740 \subsection{Try Statements and Catch Clauses} … … 757 761 The three functions passed to try terminate are: 758 762 \begin{description} 759 \item[try function:] This function is the try block , it is where all the code763 \item[try function:] This function is the try block. It is where all the code 760 764 from inside the try block is placed. It takes no parameters and has no 761 765 return value. This function is called during regular execution to run the try … … 766 770 from the conditional part of each handler and runs each check, top to bottom, 767 771 in turn, to see if the exception matches this handler. 768 The match is performed in two steps , firsta virtual cast is used to check772 The match is performed in two steps: first, a virtual cast is used to check 769 773 if the raised exception is an instance of the declared exception type or 770 774 one of its descendant types, and then the condition is evaluated, if 771 775 present. 772 776 The match function takes a pointer to the exception and returns 0 if the 773 exception is not handled here. Otherwise the return value is the idof the777 exception is not handled here. Otherwise, the return value is the ID of the 774 778 handler that matches the exception. 775 779 … … 782 786 \end{description} 783 787 All three functions are created with GCC nested functions. GCC nested functions 784 can be used to create closures ,788 can be used to create closures; 785 789 in other words, 786 functions that can refer to variables in their lexical scope even 790 functions that can refer to variables in their lexical scope even though 787 791 those variables are part of a different function. 788 792 This approach allows the functions to refer to all the … … 869 873 At each node, the EHM checks to see if the try statement the node represents 870 874 can handle the exception. If it can, then the exception is handled and 871 the operation finishes , otherwisethe search continues to the next node.875 the operation finishes; otherwise, the search continues to the next node. 872 876 If the search reaches the end of the list without finding a try statement 873 877 with a handler clause … … 879 883 if the exception is handled and false otherwise. 880 884 The handler function checks each of its internal handlers in order, 881 top-to-bottom, until it f unds a match. If a match is found that handler is885 top-to-bottom, until it finds a match. If a match is found that handler is 882 886 run, after which the function returns true, ignoring all remaining handlers. 883 887 If no match is found the function returns false. 884 The match is performed in two steps , first a virtual cast is used to see888 The match is performed in two steps. First a virtual cast is used to see 885 889 if the raised exception is an instance of the declared exception type or one 886 of its descendant types, if so then it is passed to the custom predicate 890 of its descendant types, if so, then the second step is to see if the 891 exception passes the custom predicate 887 892 if one is defined. 888 893 % You need to make sure the type is correct before running the predicate … … 936 941 % Recursive Resumption Stuff: 937 942 \autoref{f:ResumptionMarking} shows search skipping 938 (see \ vpageref{s:ResumptionMarking}), which ignores parts of943 (see \autoref{s:ResumptionMarking}), which ignores parts of 939 944 the stack 940 945 already examined, and is accomplished by updating the front of the list as … … 951 956 This structure also supports new handlers added while the resumption is being 952 957 handled. These are added to the front of the list, pointing back along the 953 stack -- - the first one points over all the checked handlers ---958 stack -- the first one points over all the checked handlers -- 954 959 and the ordering is maintained. 955 960 … … 979 984 %\autoref{code:cleanup} 980 985 A finally clause is handled by converting it into a once-off destructor. 981 The code inside the clause is placed into GCC nested-function986 The code inside the clause is placed into a GCC nested-function 982 987 with a unique name, and no arguments or return values. 983 988 This nested function is 984 989 then set as the cleanup function of an empty object that is declared at the 985 990 beginning of a block placed around the context of the associated try 986 statement (see \autoref{f:FinallyTransformation}).991 statement, as shown in \autoref{f:FinallyTransformation}. 987 992 988 993 \begin{figure} … … 1024 1029 % Stack selections, the three internal unwind functions. 1025 1030 1026 Cancellation also uses libunwind to do its stack traversal and unwinding ,1027 howeverit uses a different primary function: @_Unwind_ForcedUnwind@. Details1028 of its interface can be found in theSection~\vref{s:ForcedUnwind}.1031 Cancellation also uses libunwind to do its stack traversal and unwinding. 1032 However, it uses a different primary function: @_Unwind_ForcedUnwind@. Details 1033 of its interface can be found in Section~\vref{s:ForcedUnwind}. 1029 1034 1030 1035 The first step of cancellation is to find the cancelled stack and its type: -
doc/theses/andrew_beach_MMath/intro.tex
r4e28d2e9 r949339b 25 25 All types of exception handling link a raise with a handler. 26 26 Both operations are usually language primitives, although raises can be 27 treated as a primitivefunction that takes an exception argument.28 Handlers are more complex as they are added to and removed from the stack29 during execution, must specify what they can handle and give the code to27 treated as a function that takes an exception argument. 28 Handlers are more complex, as they are added to and removed from the stack 29 during execution, must specify what they can handle and must give the code to 30 30 handle the exception. 31 31 … … 39 39 it returns control to that function. 40 40 \begin{center} 41 \input{termination} 41 %\input{termination} 42 % 43 %\medskip 44 \input{termhandle.pstex_t} 45 % I hate these diagrams, but I can't access xfig to fix them and they are 46 % better than the alternative. 42 47 \end{center} 43 48 … … 46 51 The handler is run on top of the existing stack, often as a new function or 47 52 closure capturing the context in which the handler was defined. 48 After the handler has finished running it returns control to the function53 After the handler has finished running, it returns control to the function 49 54 that preformed the raise, usually starting after the raise. 50 55 \begin{center} 51 \input{resumption} 56 %\input{resumption} 57 % 58 %\medskip 59 \input{resumhandle.pstex_t} 60 % The other one. 52 61 \end{center} 53 62 54 63 Although a powerful feature, exception handling tends to be complex to set up 55 and expensive to use 64 and expensive to use, 56 65 so it is often limited to unusual or ``exceptional" cases. 57 The classic example is error handling ,exceptions can be used to66 The classic example is error handling; exceptions can be used to 58 67 remove error handling logic from the main execution path, and pay 59 68 most of the cost only when the error actually occurs. … … 63 72 The \CFA EHM implements all of the common exception features (or an 64 73 equivalent) found in most other EHMs and adds some features of its own. 65 The design of all the features had to be adapted to \CFA's feature set as74 The design of all the features had to be adapted to \CFA's feature set, as 66 75 some of the underlying tools used to implement and express exception handling 67 76 in other languages are absent in \CFA. 68 Still the resulting syntax resembles that of other languages:77 Still, the resulting syntax resembles that of other languages: 69 78 \begin{cfa} 70 79 try { … … 88 97 covering both changes to the compiler and the run-time. 89 98 In addition, a suite of test cases and performance benchmarks were created 90 along 99 alongside the implementation. 91 100 The implementation techniques are generally applicable in other programming 92 101 languages and much of the design is as well. … … 100 109 \item Implementing stack unwinding and the \CFA EHM, including updating 101 110 the \CFA compiler and the run-time environment. 102 \item Design ed and implementeda prototype virtual system.111 \item Designing and implementing a prototype virtual system. 103 112 % I think the virtual system and per-call site default handlers are the only 104 113 % "new" features, everything else is a matter of implementation. 105 114 \item Creating tests to check the behaviour of the EHM. 106 \item Creating benchmarks to check the performance sof the EHM,115 \item Creating benchmarks to check the performance of the EHM, 107 116 as compared to other languages. 108 117 \end{enumerate} … … 110 119 The rest of this thesis is organized as follows. 111 120 The current state of exceptions is covered in \autoref{s:background}. 112 The existing state of \CFA is alsocovered in \autoref{c:existing}.121 The existing state of \CFA is covered in \autoref{c:existing}. 113 122 New EHM features are introduced in \autoref{c:features}, 114 123 covering their usage and design. … … 129 138 message as a payload\cite{Ada12}. 130 139 131 The modern flag -ship for termination exceptionsis \Cpp,140 The modern flagship for termination exceptions -- if one exists -- is \Cpp, 132 141 which added them in its first major wave of non-object-orientated features 133 142 in 1990.\cite{CppHistory} … … 137 146 inheriting from 138 147 \code{C++}{std::exception}. 139 Although there is a special catch-all syntax (@catch(...)@) there are no148 Although there is a special catch-all syntax (@catch(...)@), there are no 140 149 operations that can be performed on the caught value, not even type inspection. 141 Instead the base exception-type \code{C++}{std::exception} defines common150 Instead, the base exception-type \code{C++}{std::exception} defines common 142 151 functionality (such as 143 152 the ability to describe the reason the exception was raised) and all … … 148 157 149 158 Java was the next popular language to use exceptions.\cite{Java8} 150 Its exception system largely reflects that of \Cpp, except that requires159 Its exception system largely reflects that of \Cpp, except that it requires 151 160 you throw a child type of \code{Java}{java.lang.Throwable} 152 161 and it uses checked exceptions. 153 162 Checked exceptions are part of a function's interface, 154 163 the exception signature of the function. 155 Every function that could be raised from a function, either directly or164 Every exception that could be raised from a function, either directly or 156 165 because it is not handled from a called function, is given. 157 166 Using this information, it is possible to statically verify if any given 158 exception is handled and guarantee that no exception will go unhandled.167 exception is handled, and guarantee that no exception will go unhandled. 159 168 Making exception information explicit improves clarity and safety, 160 169 but can slow down or restrict programming. … … 169 178 recovery or repair. In theory that could be good enough to properly handle 170 179 the exception, but more often is used to ignore an exception that the 171 programmer does not feel is worth the effort of handling it, for instance if180 programmer does not feel is worth the effort of handling, for instance if 172 181 they do not believe it will ever be raised. 173 If they are incorrect the exception will be silenced, while in a similar182 If they are incorrect, the exception will be silenced, while in a similar 174 183 situation with unchecked exceptions the exception would at least activate 175 the language's unhandled exception code (usually program abort with an184 the language's unhandled exception code (usually, a program abort with an 176 185 error message). 177 186 178 187 %\subsection 179 188 Resumption exceptions are less popular, 180 although resumption is as old as termination; hence, few189 although resumption is as old as termination; that is, few 181 190 programming languages have implemented them. 182 191 % http://bitsavers.informatik.uni-stuttgart.de/pdf/xerox/parc/techReports/ … … 186 195 included in the \Cpp standard. 187 196 % https://en.wikipedia.org/wiki/Exception_handling 188 Since then resumptions have been ignored in main-stream programming languages.197 Since then, resumptions have been ignored in mainstream programming languages. 189 198 However, resumption is being revisited in the context of decades of other 190 199 developments in programming languages. 191 200 While rejecting resumption may have been the right decision in the past, 192 201 the situation has changed since then. 193 Some developments, such as the function programming equivalent to resumptions,202 Some developments, such as the functional programming equivalent to resumptions, 194 203 algebraic effects\cite{Zhang19}, are enjoying success. 195 A complete reexamination of resumption sis beyond this thesis,196 but the re reemergence is enoughto try them in \CFA.204 A complete reexamination of resumption is beyond this thesis, 205 but their reemergence is enough reason to try them in \CFA. 197 206 % Especially considering how much easier they are to implement than 198 207 % termination exceptions and how much Peter likes them. … … 208 217 209 218 %\subsection 210 More recently exceptions seem to be vanishing from newer programming219 More recently, exceptions seem to be vanishing from newer programming 211 220 languages, replaced by ``panic". 212 221 In Rust, a panic is just a program level abort that may be implemented by 213 222 unwinding the stack like in termination exception 214 223 handling.\cite{RustPanicMacro}\cite{RustPanicModule} 215 Go's panic th rough is very similar to a termination, except it only supports224 Go's panic though is very similar to a termination, except it only supports 216 225 a catch-all by calling \code{Go}{recover()}, simplifying the interface at 217 226 the cost of flexibility.\cite{Go:2021} 218 227 219 228 %\subsection 220 Whileexception handling's most common use cases are in error handling,229 As exception handling's most common use cases are in error handling, 221 230 here are some other ways to handle errors with comparisons with exceptions. 222 231 \begin{itemize} … … 233 242 is discarded to avoid this problem. 234 243 Checking error codes also bloats the main execution path, 235 especially if the error is not handled immediately hand has to be passed244 especially if the error is not handled immediately and has to be passed 236 245 through multiple functions before it is addressed. 246 247 Here is an example of the pattern in Bash, where commands can only ``return" 248 numbers and most output is done through streams of text. 249 \begin{lstlisting}[language=bash,escapechar={}] 250 # Immediately after running a command: 251 case $? in 252 0) 253 # Success 254 ;; 255 1) 256 # Error Code 1 257 ;; 258 2|3) 259 # Error Code 2 or Error Code 3 260 ;; 261 # Add more cases as needed. 262 asac 263 \end{lstlisting} 237 264 238 265 \item\emph{Special Return with Global Store}: 239 266 Similar to the error codes pattern but the function itself only returns 240 that there was an error 241 and store the reason for the error in a fixed global location.242 For example many routines in the C standard library will only return some267 that there was an error, 268 and stores the reason for the error in a fixed global location. 269 For example, many routines in the C standard library will only return some 243 270 error value (such as -1 or a null pointer) and the error code is written into 244 271 the standard variable @errno@. 245 272 246 273 This approach avoids the multiple results issue encountered with straight 247 error codes but otherwise has the same disadvantages and more. 274 error codes as only a single error value has to be returned, 275 but otherwise has the same disadvantages and more. 248 276 Every function that reads or writes to the global store must agree on all 249 277 possible errors and managing it becomes more complex with concurrency. 278 279 This example shows some of what has to be done to robustly handle a C 280 standard library function that reports errors this way. 281 \begin{lstlisting}[language=C] 282 // Now a library function can set the error. 283 int handle = open(path_name, flags); 284 if (-1 == handle) { 285 switch (errno) { 286 case ENAMETOOLONG: 287 // path_name is a bad argument. 288 break; 289 case ENFILE: 290 // A system resource has been exausted. 291 break; 292 // And many more... 293 } 294 } 295 \end{lstlisting} 296 % cite open man page? 250 297 251 298 \item\emph{Return Union}: … … 253 300 Success is one tag and the errors are another. 254 301 It is also possible to make each possible error its own tag and carry its own 255 additional information, but the two 302 additional information, but the two-branch format is easy to make generic 256 303 so that one type can be used everywhere in error handling code. 257 304 258 305 This pattern is very popular in any functional or semi-functional language 259 306 with primitive support for tagged unions (or algebraic data types). 307 Return unions can also be expressed as monads (evaluation in a context) 308 and often are in languages with special syntax for monadic evaluation, 309 such as Haskell's \code{haskell}{do} blocks. 310 311 The main advantage is that an arbitrary object can be used to represent an 312 error, so it can include a lot more information than a simple error code. 313 The disadvantages include that the it does have to be checked along the main 314 execution, and if there aren't primitive tagged unions proper, usage can be 315 hard to enforce. 260 316 % We need listing Rust/rust to format code snippets from it. 261 317 % Rust's \code{rust}{Result<T, E>} 262 The main advantage is that an arbitrary object can be used to represent an 263 error so it can include a lot more information than a simple error code. 264 The disadvantages include that the it does have to be checked along the main 265 execution and if there aren't primitive tagged unions proper usage can be 266 hard to enforce. 318 319 This is a simple example of examining the result of a failing function in 320 Haskell, using its \code{haskell}{Either} type. 321 Examining \code{haskell}{error} further would likely involve more matching, 322 but the type of \code{haskell}{error} is user defined so there are no 323 general cases. 324 \begin{lstlisting}[language=haskell] 325 case failingFunction argA argB of 326 Right value -> -- Use the successful computed value. 327 Left error -> -- Handle the produced error. 328 \end{lstlisting} 329 330 Return unions as monads will result in the same code, but can hide most 331 of the work to propagate errors in simple cases. The code to actually handle 332 the errors, or to interact with other monads (a common case in these 333 languages) still has to be written by hand. 334 335 If \code{haskell}{failingFunction} is implemented with two helpers that 336 use the same error type, then it can be implemented with a \code{haskell}{do} 337 block. 338 \begin{lstlisting}[language=haskell,literate={}] 339 failingFunction x y = do 340 z <- helperOne x 341 helperTwo y z 342 \end{lstlisting} 267 343 268 344 \item\emph{Handler Functions}: … … 274 350 variable). 275 351 C++ uses this approach as its fallback system if exception handling fails, 276 such as \snake{std::terminate_handler} and, for a time, 277 \snake{std::unexpected_handler}. 352 such as \snake{std::terminate} and, for a time, 353 \snake{std::unexpected}.\footnote{\snake{std::unexpected} was part of the 354 Dynamic Exception Specification, which has been removed from the standard 355 as of C++20.\cite{CppExceptSpec}} 278 356 279 357 Handler functions work a lot like resumption exceptions, … … 283 361 function calls, but cheaper (constant time) to call, 284 362 they are more suited to more frequent (less exceptional) situations. 363 Although, in \Cpp and other languages that do not have checked exceptions, 364 they can actually be enforced by the type system be more reliable. 365 366 This is a more local example in \Cpp, using a function to provide 367 a default value for a mapping. 368 \begin{lstlisting}[language=C++] 369 ValueT Map::key_or_default(KeyT key, ValueT(*make_default)(KeyT)) { 370 ValueT * value = find_value(key); 371 if (nullptr != value) { 372 return *value; 373 } else { 374 return make_default(key); 375 } 376 } 377 \end{lstlisting} 285 378 \end{itemize} 286 379 … … 288 381 Because of their cost, exceptions are rarely used for hot paths of execution. 289 382 Hence, there is an element of self-fulfilling prophecy as implementation 290 techniques have been focused on making them cheap to set -up,383 techniques have been focused on making them cheap to set up, 291 384 happily making them expensive to use in exchange. 292 385 This difference is less important in higher-level scripting languages, 293 where using exception for other tasks is more common.386 where using exceptions for other tasks is more common. 294 387 An iconic example is Python's 295 \code{Python}{StopIteration}\cite{PythonExceptions} exception that388 \code{Python}{StopIteration}\cite{PythonExceptions} exception, that 296 389 is thrown by an iterator to indicate that it is exhausted. 297 When paired with Python's iterator-based for-loop this will be thrown every390 When paired with Python's iterator-based for-loop, this will be thrown every 298 391 time the end of the loop is reached.\cite{PythonForLoop} -
doc/theses/andrew_beach_MMath/performance.tex
r4e28d2e9 r949339b 5 5 Instead, the focus was to get the features working. The only performance 6 6 requirement is to ensure the tests for correctness run in a reasonable 7 amount of time. Hence, a few basic performance tests were performed to7 amount of time. Hence, only a few basic performance tests were performed to 8 8 check this requirement. 9 9 … … 13 13 one with termination and one with resumption. 14 14 15 C++ is the most comparable language because both it and \CFA use the same15 GCC C++ is the most comparable language because both it and \CFA use the same 16 16 framework, libunwind. 17 17 In fact, the comparison is almost entirely in quality of implementation. … … 37 37 resumption exceptions. Even the older programming languages with resumption 38 38 seem to be notable only for having resumption. 39 On the other hand, the functional equivalents to resumption are too new. 40 There does not seem to be any standard implementations in well-known 41 languages; so far, they seem confined to extensions and research languages. 42 % There was some maybe interesting comparison to an OCaml extension 43 % but I'm not sure how to get that working if it is interesting. 39 44 Instead, resumption is compared to its simulation in other programming 40 45 languages: fixup functions that are explicitly passed into a function. … … 46 51 the number used in the timing runs is given with the results per test. 47 52 The Java tests run the main loop 1000 times before 48 beginning the actual test to ``warm -up" the JVM.53 beginning the actual test to ``warm up" the JVM. 49 54 % All other languages are precompiled or interpreted. 50 55 … … 54 59 unhandled exceptions in \Cpp and Java as that would cause the process to 55 60 terminate. 56 Luckily, performance on the ``give -up and kill the process" path is not61 Luckily, performance on the ``give up and kill the process" path is not 57 62 critical. 58 63 … … 76 81 using gcc-10 10.3.0 as a backend. 77 82 g++-10 10.3.0 is used for \Cpp. 78 Java tests are complied and run with version 11.0.11.79 Python used version 3.8.10.83 Java tests are complied and run with Oracle OpenJDK version 11.0.11. 84 Python used CPython version 3.8.10. 80 85 The machines used to run the tests are: 81 86 \begin{itemize}[nosep] … … 85 90 \lstinline{@} 2.5 GHz running Linux v5.11.0-25 86 91 \end{itemize} 87 Representingthe two major families of hardware architecture.92 These represent the two major families of hardware architecture. 88 93 89 94 \section{Tests} … … 93 98 94 99 \paragraph{Stack Traversal} 95 This group measures the cost of traversing the stack,100 This group of tests measures the cost of traversing the stack 96 101 (and in termination, unwinding it). 97 102 Inside the main loop is a call to a recursive function. … … 147 152 This group of tests measures the cost for setting up exception handling, 148 153 if it is 149 not used (because the exceptional case did not occur).154 not used because the exceptional case did not occur. 150 155 Tests repeatedly cross (enter, execute and leave) a try statement but never 151 156 perform a raise. … … 222 227 for that language and the result is marked N/A. 223 228 There are also cases where the feature is supported but measuring its 224 cost is impossible. This happened with Java, which uses a JIT that optimize 225 away the tests and itcannot be stopped.\cite{Dice21}229 cost is impossible. This happened with Java, which uses a JIT that optimizes 230 away the tests and cannot be stopped.\cite{Dice21} 226 231 These tests are marked N/C. 227 232 To get results in a consistent range (1 second to 1 minute is ideal, … … 230 235 results and has a value in the millions. 231 236 232 An anomaly in some results came from \CFA's use of gccnested functions.237 An anomaly in some results came from \CFA's use of GCC nested functions. 233 238 These nested functions are used to create closures that can access stack 234 239 variables in their lexical scope. 235 However, if they do so, then they can cause the benchmark's run -time to240 However, if they do so, then they can cause the benchmark's run time to 236 241 increase by an order of magnitude. 237 242 The simplest solution is to make those values global variables instead 238 of function 243 of function-local variables. 239 244 % Do we know if editing a global inside nested function is a problem? 240 245 Tests that had to be modified to avoid this problem have been marked … … 255 260 \multicolumn{1}{c}{\CFA} & \multicolumn{1}{c}{\Cpp} & \multicolumn{1}{c}{Java} & \multicolumn{1}{c|}{Python} \\ 256 261 \hline 257 Empty Traversal (1M) & 3.4 & 2.8 & 18.3 & 23.4 & 3.7 & 3.2 & 15.5 & 14.8\\258 D'tor Traversal (1M) & 48. 4 & 23.6 & N/A & N/A & 64.2 & 29.0& N/A & N/A \\259 Finally Traversal (1M) & 3. 4* & N/A & 17.9 & 29.0 & 4.1* & N/A & 15.6& 19.0 \\260 Other Traversal (1M) & 3. 6* & 23.2 & 18.2 & 32.7 & 4.0* & 24.5 & 15.5 & 21.4\\261 Cross Handler (1 00M) & 6.0 & 0.9 & N/C & 37.4 & 10.0 & 0.8 & N/C & 32.2\\262 Cross Finally (1 00M) & 0.9 & N/A & N/C & 44.1 & 0.8& N/A & N/C & 37.3 \\263 Match All (10M) & 3 2.9 & 20.7 & 13.4 & 4.9 & 36.2 & 24.5 & 12.0& 3.1 \\264 Match None (10M) & 3 2.7 & 50.3 & 11.0 & 5.1 & 36.3 & 71.9 & 12.3 & 4.2\\262 Empty Traversal (1M) & 23.0 & 9.6 & 17.6 & 23.4 & 30.6 & 13.6 & 15.5 & 14.7 \\ 263 D'tor Traversal (1M) & 48.1 & 23.5 & N/A & N/A & 64.2 & 29.2 & N/A & N/A \\ 264 Finally Traversal (1M) & 3.2* & N/A & 17.6 & 29.2 & 3.9* & N/A & 15.5 & 19.0 \\ 265 Other Traversal (1M) & 3.3* & 23.9 & 17.7 & 32.8 & 3.9* & 24.5 & 15.5 & 21.6 \\ 266 Cross Handler (1B) & 6.5 & 0.9 & N/C & 38.0 & 9.6 & 0.8 & N/C & 32.1 \\ 267 Cross Finally (1B) & 0.8 & N/A & N/C & 44.6 & 0.6 & N/A & N/C & 37.3 \\ 268 Match All (10M) & 30.5 & 20.6 & 11.2 & 3.9 & 36.9 & 24.6 & 10.7 & 3.1 \\ 269 Match None (10M) & 30.6 & 50.9 & 11.2 & 5.0 & 36.9 & 71.9 & 10.7 & 4.1 \\ 265 270 \hline 266 271 \end{tabular} … … 276 281 & AMD & ARM \\ 277 282 \hline 278 Empty Traversal (10M) & 0.2 & 0.3\\283 Empty Traversal (10M) & 1.4 & 1.2 \\ 279 284 D'tor Traversal (10M) & 1.8 & 1.0 \\ 280 Finally Traversal (10M) & 1. 7& 1.0 \\281 Other Traversal (10M) & 22.6 & 25. 9\\282 Cross Handler (1 00M) & 8.4& 11.9 \\285 Finally Traversal (10M) & 1.8 & 1.0 \\ 286 Other Traversal (10M) & 22.6 & 25.8 \\ 287 Cross Handler (1B) & 9.0 & 11.9 \\ 283 288 Match All (100M) & 2.3 & 3.2 \\ 284 Match None (100M) & 2.9 & 3.9\\289 Match None (100M) & 3.0 & 3.8 \\ 285 290 \hline 286 291 \end{tabular} … … 300 305 \multicolumn{1}{c}{Raise} & \multicolumn{1}{c}{\CFA} & \multicolumn{1}{c}{\Cpp} & \multicolumn{1}{c}{Java} & \multicolumn{1}{c|}{Python} \\ 301 306 \hline 302 Resume Empty (10M) & 1. 5 & 1.5 & 14.7 & 2.3 & 176.1 & 1.0 & 1.4 & 8.9 & 1.2 & 119.9\\307 Resume Empty (10M) & 1.4 & 1.4 & 15.4 & 2.3 & 178.0 & 1.2 & 1.2 & 8.9 & 1.2 & 118.4 \\ 303 308 \hline 304 309 \end{tabular} … … 312 317 \CFA, \Cpp and Java. 313 318 % To be exact, the Match All and Match None cases. 314 The most likely explanation is that, since exceptions 315 are rarely considered to be the common case, the more optimized languages 316 make that case expensive to improve other cases. 319 The most likely explanation is that 320 the generally faster languages have made ``common cases fast" at the expense 321 of the rarer cases. Since exceptions are considered rare, they are made 322 expensive to help speed up common actions, such as entering and leaving try 323 statements. 324 Python, on the other hand, while generally slower than the other languages, 325 uses exceptions more and has not sacrificed their performance. 317 326 In addition, languages with high-level representations have a much 318 327 easier time scanning the stack as there is less to decode. … … 346 355 Performance is similar to Empty Traversal in all languages that support finally 347 356 clauses. Only Python seems to have a larger than random noise change in 348 its run -time and it is still not large.357 its run time and it is still not large. 349 358 Despite the similarity between finally clauses and destructors, 350 finally clauses seem to avoid the spike that run -time destructors have.359 finally clauses seem to avoid the spike that run time destructors have. 351 360 Possibly some optimization removes the cost of changing contexts. 352 361 … … 356 365 This results in a significant jump. 357 366 358 Other languages experience a small increase in run -time.367 Other languages experience a small increase in run time. 359 368 The small increase likely comes from running the checks, 360 369 but they could avoid the spike by not having the same kind of overhead for … … 362 371 363 372 \item[Cross Handler] 364 Here \CFA falls behind \Cpp by a much more significant margin.365 This is likely due to the fact \CFA has to insert two extra function366 calls, while \Cpp does not have to doexecute any other instructions.373 Here, \CFA falls behind \Cpp by a much more significant margin. 374 This is likely due to the fact that \CFA has to insert two extra function 375 calls, while \Cpp does not have to execute any other instructions. 367 376 Python is much further behind. 368 377 … … 375 384 \item[Conditional Match] 376 385 Both of the conditional matching tests can be considered on their own. 377 However for evaluating the value of conditional matching itself, the386 However, for evaluating the value of conditional matching itself, the 378 387 comparison of the two sets of results is useful. 379 Consider the massive jump in run -time for \Cpp going from match all to match388 Consider the massive jump in run time for \Cpp going from match all to match 380 389 none, which none of the other languages have. 381 Some strange interaction is causing run -time to more than double for doing390 Some strange interaction is causing run time to more than double for doing 382 391 twice as many raises. 383 Java and Python avoid this problem and have similar run -time for both tests,392 Java and Python avoid this problem and have similar run time for both tests, 384 393 possibly through resource reuse or their program representation. 385 However \CFA is built like \Cpp and avoids the problem as well, this matches 394 However, \CFA is built like \Cpp, and avoids the problem as well. 395 This matches 386 396 the pattern of the conditional match, which makes the two execution paths 387 397 very similar. … … 391 401 \subsection{Resumption \texorpdfstring{(\autoref{t:PerformanceResumption})}{}} 392 402 393 Moving on to resumption, there is one general note ,403 Moving on to resumption, there is one general note: 394 404 resumption is \textit{fast}. The only test where it fell 395 405 behind termination is Cross Handler. 396 406 In every other case, the number of iterations had to be increased by a 397 factor of 10 to get the run -time in an appropriate range407 factor of 10 to get the run time in an appropriate range 398 408 and in some cases resumption still took less time. 399 409 … … 408 418 409 419 \item[D'tor Traversal] 410 Resumption does have the same spike in run -time that termination has.411 The run -time is actually very similar to Finally Traversal.420 Resumption does have the same spike in run time that termination has. 421 The run time is actually very similar to Finally Traversal. 412 422 As resumption does not unwind the stack, both destructors and finally 413 423 clauses are run while walking down the stack during the recursive returns. … … 416 426 \item[Finally Traversal] 417 427 Same as D'tor Traversal, 418 except termination did not have a spike in run -time on this test case.428 except termination did not have a spike in run time on this test case. 419 429 420 430 \item[Other Traversal] … … 427 437 The only test case where resumption could not keep up with termination, 428 438 although the difference is not as significant as many other cases. 429 It is simply a matter of where the costs come from ,430 both termination and resumption have some work to set -up or tear-down a439 It is simply a matter of where the costs come from: 440 both termination and resumption have some work to set up or tear down a 431 441 handler. It just so happens that resumption's work is slightly slower. 432 442 … … 434 444 Resumption shows a slight slowdown if the exception is not matched 435 445 by the first handler, which follows from the fact the second handler now has 436 to be checked. However the difference is not large.446 to be checked. However, the difference is not large. 437 447 438 448 \end{description} … … 448 458 More experiments could try to tease out the exact trade-offs, 449 459 but the prototype's only performance goal is to be reasonable. 450 It has already in that range, and \CFA's fixup routine simulation is460 It is already in that range, and \CFA's fixup routine simulation is 451 461 one of the faster simulations as well. 452 Plus exceptions add features and remove syntactic overhead,453 so even at similar performance resumptions have advantages462 Plus, exceptions add features and remove syntactic overhead, 463 so even at similar performance, resumptions have advantages 454 464 over fixup routines. -
doc/theses/andrew_beach_MMath/uw-ethesis-frontpgs.tex
r4e28d2e9 r949339b 129 129 \begin{center}\textbf{Abstract}\end{center} 130 130 131 This is the abstract. 131 The \CFA (Cforall) programming language is an evolutionary refinement of 132 the C programming language, adding modern programming features without 133 changing the programming paradigms of C. 134 One of these modern programming features is more powerful error handling 135 through the addition of an exception handling mechanism (EHM). 136 137 This thesis covers the design and implementation of the \CFA EHM, 138 along with a review of the other required \CFA features. 139 The EHM includes common features of termination exception handling, 140 which abandons and recovers from an operation, 141 and similar support for resumption exception handling, 142 which repairs and continues with an operation. 143 The design of both has been adapted to utilize other tools \CFA provides, 144 as well as fit with the assertion based interfaces of the language. 145 146 The EHM has been implemented into the \CFA compiler and run-time environment. 147 Although it has not yet been optimized, performance testing has shown it has 148 comparable performance to other EHMs, 149 which is sufficient for use in current \CFA programs. 132 150 133 151 \cleardoublepage … … 138 156 \begin{center}\textbf{Acknowledgements}\end{center} 139 157 140 I would like to thank all the little people who made this thesis possible. 158 As is tradition and his due, I would like to begin by thanking my 159 supervisor Peter Buhr. From accepting me in a first place, 160 to helping me run performance tests, I would not be here without him. 161 Also if there was an ``artist" field here he would be listed there as well, 162 he helped me a lot with the diagrams. 163 164 I would like to thank the readers 165 Gregor Richards and Yizhou Zhang 166 for their feedback and approval. 167 The presentation of the thesis has definitely been improved with their 168 feedback. 169 170 I also thank the entire Cforall Team who built the rest of the 171 \CFA compiler. From the existing features I used in my work, to the 172 internal tooling that makes further development easier and the optimizations 173 that make running tests pass by quickly. 174 This includes: Aaron Moss, Rob Schluntz, Thierry Delisle, Michael Brooks, 175 Mubeen Zulfieqar \& Fangren Yu. 176 177 And thank-you Henry Xue, the co-op student who 178 converted my macro implementation of exception declarations into 179 the compiler features presented in this thesis. 180 181 Finally I thank my family, who are still relieved I learned how to read. 182 141 183 \cleardoublepage 142 184 -
doc/theses/andrew_beach_MMath/uw-ethesis.bib
r4e28d2e9 r949339b 40 40 } 41 41 42 @misc{CppExceptSpec, 43 author={C++ Community}, 44 key={Cpp Reference Exception Specification}, 45 howpublished={\href{https://en.cppreference.com/w/cpp/language/except_spec}{https://\-en.cppreference.com/\-w/\-cpp/\-language/\-except\_spec}}, 46 addendum={Accessed 2021-09-08}, 47 } 48 42 49 @misc{RustPanicMacro, 43 50 author={The Rust Team}, 44 51 key={Rust Panic Macro}, 45 howpublished={\href{https://doc.rust-lang.org/std/ panic/index.html}{https://\-doc.rust-lang.org/\-std/\-panic/\-index.html}},52 howpublished={\href{https://doc.rust-lang.org/std/macro.panic.html}{https://\-doc.rust-lang.org/\-std/\-macro.panic.html}}, 46 53 addendum={Accessed 2021-08-31}, 47 54 }
Note:
See TracChangeset
for help on using the changeset viewer.