Changes in / [0e4df2e:2802824]
- Files:
-
- 3 deleted
- 24 edited
-
driver/cfa.cc (modified) (3 diffs)
-
libcfa/src/Makefile.am (modified) (2 diffs)
-
libcfa/src/Makefile.in (modified) (2 diffs)
-
libcfa/src/concurrency/io.cfa (modified) (18 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (1 diff)
-
libcfa/src/containers/list.hfa (modified) (1 diff)
-
libcfa/src/containers/stackLockFree.hfa (deleted)
-
libcfa/src/exception.c (modified) (8 diffs)
-
libcfa/src/exception.h (modified) (3 diffs)
-
libcfa/src/exception.hfa (modified) (3 diffs)
-
libcfa/src/executor.cfa (modified) (6 diffs)
-
libcfa/src/heap.cfa (modified) (24 diffs)
-
libcfa/src/stdlib.hfa (modified) (8 diffs)
-
src/ControlStruct/ExceptTranslate.cc (modified) (19 diffs)
-
src/ControlStruct/ExceptTranslate.h (modified) (2 diffs)
-
src/main.cc (modified) (3 diffs)
-
tests/errors/.expect/completeType.txt (modified) (1 diff)
-
tests/exceptions/.expect/defaults.txt (deleted)
-
tests/exceptions/conditional.cfa (modified) (2 diffs)
-
tests/exceptions/data-except.cfa (modified) (2 diffs)
-
tests/exceptions/defaults.cfa (deleted)
-
tests/exceptions/finally.cfa (modified) (2 diffs)
-
tests/exceptions/interact.cfa (modified) (10 diffs)
-
tests/exceptions/resume.cfa (modified) (8 diffs)
-
tests/exceptions/terminate.cfa (modified) (8 diffs)
-
tests/list/.expect/dlist-insert-remove.txt (modified) (1 diff)
-
tests/list/dlist-insert-remove.cfa (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
driver/cfa.cc
r0e4df2e r2802824 10 10 // Created On : Tue Aug 20 13:44:49 2002 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon May 18 13:26:26202013 // Update Count : 42 412 // Last Modified On : Fri Jan 31 16:48:03 2020 13 // Update Count : 421 14 14 // 15 15 … … 301 301 } // for 302 302 303 #ifdef __x86_64__ 304 args[nargs++] = "-mcx16"; // allow double-wide CAA 305 #endif // __x86_64__ 306 303 307 #ifdef __DEBUG_H__ 304 308 cerr << "args:"; … … 415 419 args[nargs++] = "-lcfa"; 416 420 args[nargs++] = "-Wl,--pop-state"; 417 #ifdef __x86_64__418 args[nargs++] = "-mcx16"; // allow double-wide CAS419 args[nargs++] = "-latomic";420 #endif // __x86_64__421 421 args[nargs++] = "-pthread"; 422 422 args[nargs++] = "-ldl"; -
libcfa/src/Makefile.am
r0e4df2e r2802824 11 11 ## Created On : Sun May 31 08:54:01 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Sun May 17 21:10:26202014 ## Update Count : 24 313 ## Last Modified On : Mon Mar 16 18:07:59 2020 14 ## Update Count : 242 15 15 ############################################################################### 16 16 … … 39 39 #---------------------------------------------------------------------------------------------------------------- 40 40 if BUILDLIB 41 headers_nosrc = bitmanip.hfa math.hfa gmp.hfa time_t.hfa clock.hfa \ 42 bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa containers/list.hfa 41 headers_nosrc = bitmanip.hfa math.hfa gmp.hfa time_t.hfa bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa containers/list.hfa 43 42 headers = fstream.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa time.hfa stdlib.hfa common.hfa \ 44 containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/stackLockFree.hfa containers/vector.hfa43 containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa 45 44 46 45 libsrc = startup.cfa interpose.cfa bits/debug.cfa assert.cfa exception.c virtual.c heap.cfa ${headers:.hfa=.cfa} -
libcfa/src/Makefile.in
r0e4df2e r2802824 241 241 containers/maybe.hfa containers/pair.hfa containers/result.hfa \ 242 242 containers/vector.hfa bitmanip.hfa math.hfa gmp.hfa time_t.hfa \ 243 clock.hfabits/align.hfa bits/containers.hfa bits/defs.hfa \243 bits/align.hfa bits/containers.hfa bits/defs.hfa \ 244 244 bits/debug.hfa bits/locks.hfa containers/list.hfa \ 245 245 concurrency/coroutine.hfa concurrency/thread.hfa \ … … 465 465 466 466 #---------------------------------------------------------------------------------------------------------------- 467 @BUILDLIB_TRUE@headers_nosrc = bitmanip.hfa math.hfa gmp.hfa time_t.hfa clock.hfa \ 468 @BUILDLIB_TRUE@ bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa containers/list.hfa 469 467 @BUILDLIB_TRUE@headers_nosrc = bitmanip.hfa math.hfa gmp.hfa time_t.hfa bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa containers/list.hfa 470 468 @BUILDLIB_FALSE@headers = 471 469 @BUILDLIB_TRUE@headers = fstream.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa time.hfa stdlib.hfa common.hfa \ 472 @BUILDLIB_TRUE@ containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa470 @BUILDLIB_TRUE@ containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa 473 471 474 472 @BUILDLIB_FALSE@libsrc = -
libcfa/src/concurrency/io.cfa
r0e4df2e r2802824 124 124 125 125 // Like head/tail but not seen by the kernel 126 volatile uint32_t alloc; 126 127 volatile uint32_t * ready; 127 128 uint32_t ready_cnt; … … 140 141 struct { 141 142 struct { 142 volatile unsigned long long int rdy; 143 volatile unsigned long long int csm; 144 volatile unsigned long long int avl; 143 volatile unsigned long long int val; 145 144 volatile unsigned long long int cnt; 145 volatile unsigned long long int block; 146 146 } submit_avg; 147 147 struct { … … 150 150 volatile unsigned long long int block; 151 151 } look_avg; 152 struct {153 volatile unsigned long long int val;154 volatile unsigned long long int cnt;155 volatile unsigned long long int block;156 } alloc_avg;157 152 } stats; 158 153 #endif … … 284 279 sq.dropped = ( uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped); 285 280 sq.array = ( uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.array); 286 287 { 288 const uint32_t num = *sq.num; 289 for( i; num ) { 290 sq.sqes[i].user_data = 0ul64; 291 } 292 } 281 sq.alloc = *sq.tail; 293 282 294 283 if( io_flags & CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS ) { … … 333 322 // Initialize statistics 334 323 #if !defined(__CFA_NO_STATISTICS__) 335 this.io->submit_q.stats.submit_avg.rdy = 0; 336 this.io->submit_q.stats.submit_avg.csm = 0; 337 this.io->submit_q.stats.submit_avg.avl = 0; 338 this.io->submit_q.stats.submit_avg.cnt = 0; 324 this.io->submit_q.stats.submit_avg.val = 0; 325 this.io->submit_q.stats.submit_avg.cnt = 0; 326 this.io->submit_q.stats.submit_avg.block = 0; 339 327 this.io->submit_q.stats.look_avg.val = 0; 340 328 this.io->submit_q.stats.look_avg.cnt = 0; 341 329 this.io->submit_q.stats.look_avg.block = 0; 342 this.io->submit_q.stats.alloc_avg.val = 0;343 this.io->submit_q.stats.alloc_avg.cnt = 0;344 this.io->submit_q.stats.alloc_avg.block = 0;345 330 this.io->completion_q.stats.completed_avg.val = 0; 346 331 this.io->completion_q.stats.completed_avg.slow_cnt = 0; … … 399 384 this.ready_queue.head = 1p; 400 385 thrd.next = 0p; 401 __cfaabi_dbg_debug_do( thrd.unpark_stale = true );402 386 403 387 // Fixup the thread state … … 442 426 if(this.print_stats) { 443 427 with(this.io->submit_q.stats, this.io->completion_q.stats) { 444 double avgrdy = ((double)submit_avg.rdy) / submit_avg.cnt;445 double avgcsm = ((double)submit_avg.csm) / submit_avg.cnt;446 double avgavl = ((double)submit_avg.avl) / submit_avg.cnt;447 448 428 double lavgv = 0; 449 429 double lavgb = 0; … … 453 433 } 454 434 455 double aavgv = 0;456 double aavgb = 0;457 if(alloc_avg.cnt != 0) {458 aavgv = ((double)alloc_avg.val ) / alloc_avg.cnt;459 aavgb = ((double)alloc_avg.block) / alloc_avg.cnt;460 }461 462 435 __cfaabi_bits_print_safe( STDOUT_FILENO, 463 436 "----- I/O uRing Stats -----\n" 464 437 "- total submit calls : %'15llu\n" 465 "- avg ready entries : %'18.2lf\n" 466 "- avg submitted entries : %'18.2lf\n" 467 "- avg available entries : %'18.2lf\n" 438 "- avg submit : %'18.2lf\n" 439 "- pre-submit block %% : %'18.2lf\n" 468 440 "- total ready search : %'15llu\n" 469 441 "- avg ready search len : %'18.2lf\n" 470 442 "- avg ready search block : %'18.2lf\n" 471 "- total alloc search : %'15llu\n"472 "- avg alloc search len : %'18.2lf\n"473 "- avg alloc search block : %'18.2lf\n"474 443 "- total wait calls : %'15llu (%'llu slow, %'llu fast)\n" 475 444 "- avg completion/wait : %'18.2lf\n", 476 445 submit_avg.cnt, 477 avgrdy, 478 avgcsm, 479 avgavl, 446 ((double)submit_avg.val) / submit_avg.cnt, 447 (100.0 * submit_avg.block) / submit_avg.cnt, 480 448 look_avg.cnt, 481 449 lavgv, 482 450 lavgb, 483 alloc_avg.cnt,484 aavgv,485 aavgb,486 451 completed_avg.slow_cnt + completed_avg.fast_cnt, 487 452 completed_avg.slow_cnt, completed_avg.fast_cnt, … … 529 494 530 495 // If the poller thread also submits, then we need to aggregate the submissions which are ready 531 uint32_t tail = *ring.submit_q.tail;496 uint32_t * tail = ring.submit_q.tail; 532 497 const uint32_t mask = *ring.submit_q.mask; 533 498 … … 541 506 542 507 // If we got a real submission, append it to the list 543 ring.submit_q.array[ ( tail+ to_submit) & mask ] = idx & mask;508 ring.submit_q.array[ ((*tail) + to_submit) & mask ] = idx & mask; 544 509 to_submit++; 545 510 } 546 511 547 512 // Increment the tail based on how many we are ready to submit 548 __atomic_fetch_add(ring.submit_q.tail, to_submit, __ATOMIC_SEQ_CST); 549 } 550 551 const uint32_t smask = *ring.submit_q.mask; 552 uint32_t shead = *ring.submit_q.head; 513 __atomic_fetch_add(tail, to_submit, __ATOMIC_SEQ_CST); 514 515 // update statistics 516 #if !defined(__CFA_NO_STATISTICS__) 517 ring.submit_q.stats.submit_avg.val += to_submit; 518 ring.submit_q.stats.submit_avg.cnt += 1; 519 #endif 520 } 521 553 522 int ret = syscall( __NR_io_uring_enter, ring.fd, to_submit, waitcnt, IORING_ENTER_GETEVENTS, mask, _NSIG / 8); 554 523 if( ret < 0 ) { … … 562 531 } 563 532 564 verify( (shead + ret) == *ring.submit_q.head );565 566 // Release the consumed SQEs567 for( i; ret ) {568 uint32_t idx = ring.submit_q.array[ (i + shead) & smask ];569 ring.submit_q.sqes[ idx ].user_data = 0;570 }571 572 uint32_t avail = 0;573 uint32_t sqe_num = *ring.submit_q.num;574 for(i; sqe_num) {575 if( ring.submit_q.sqes[ i ].user_data == 0 ) avail++;576 }577 578 // update statistics579 #if !defined(__CFA_NO_STATISTICS__)580 ring.submit_q.stats.submit_avg.rdy += to_submit;581 ring.submit_q.stats.submit_avg.csm += ret;582 ring.submit_q.stats.submit_avg.avl += avail;583 ring.submit_q.stats.submit_avg.cnt += 1;584 #endif585 586 533 // Drain the queue 587 534 unsigned head = *ring.completion_q.head; 588 unsigned tail = *ring.completion_q.tail; 589 const uint32_t mask = *ring.completion_q.mask; 590 591 // Memory barrier 592 __atomic_thread_fence( __ATOMIC_SEQ_CST ); 535 unsigned tail = __atomic_load_n(ring.completion_q.tail, __ATOMIC_ACQUIRE); 593 536 594 537 // Nothing was new return 0 … … 599 542 uint32_t count = tail - head; 600 543 for(i; count) { 601 unsigned idx = (head + i) & mask;544 unsigned idx = (head + i) & (*ring.completion_q.mask); 602 545 struct io_uring_cqe & cqe = ring.completion_q.cqes[idx]; 603 546 … … 613 556 614 557 // Allow new submissions to happen 615 //V(ring.submit, count);558 V(ring.submit, count); 616 559 617 560 // Mark to the kernel that the cqe has been seen 618 561 // Ensure that the kernel only sees the new value of the head index after the CQEs have been read. 619 __atomic_thread_fence( __ATOMIC_SEQ_CST );620 562 __atomic_fetch_add( ring.completion_q.head, count, __ATOMIC_RELAXED ); 621 563 … … 768 710 // 769 711 770 static inline [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data ) { 771 verify( data != 0 ); 772 773 // Prepare the data we need 774 __attribute((unused)) int len = 0; 775 __attribute((unused)) int block = 0; 776 uint32_t cnt = *ring.submit_q.num; 777 uint32_t mask = *ring.submit_q.mask; 778 uint32_t off = __tls_rand(); 779 780 // Loop around looking for an available spot 781 LOOKING: for() { 782 // Look through the list starting at some offset 783 for(i; cnt) { 784 uint64_t expected = 0; 785 uint32_t idx = (i + off) & mask; 786 struct io_uring_sqe * sqe = &ring.submit_q.sqes[idx]; 787 volatile uint64_t * udata = &sqe->user_data; 788 789 if( *udata == expected && 790 __atomic_compare_exchange_n( udata, &expected, data, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) 791 { 792 // update statistics 793 #if !defined(__CFA_NO_STATISTICS__) 794 __atomic_fetch_add( &ring.submit_q.stats.alloc_avg.val, len, __ATOMIC_RELAXED ); 795 __atomic_fetch_add( &ring.submit_q.stats.alloc_avg.block, block, __ATOMIC_RELAXED ); 796 __atomic_fetch_add( &ring.submit_q.stats.alloc_avg.cnt, 1, __ATOMIC_RELAXED ); 797 #endif 798 799 // Success return the data 800 return [sqe, idx]; 801 } 802 verify(expected != data); 803 804 len ++; 805 } 806 807 block++; 808 yield(); 809 } 712 static inline [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring ) { 713 // Wait for a spot to be available 714 __attribute__((unused)) bool blocked = P(ring.submit); 715 #if !defined(__CFA_NO_STATISTICS__) 716 __atomic_fetch_add( &ring.submit_q.stats.submit_avg.block, blocked ? 1ul64 : 0ul64, __ATOMIC_RELAXED ); 717 #endif 718 719 // Allocate the sqe 720 uint32_t idx = __atomic_fetch_add(&ring.submit_q.alloc, 1ul32, __ATOMIC_SEQ_CST); 721 722 // Mask the idx now to allow make everything easier to check 723 idx &= *ring.submit_q.mask; 724 725 // Return the sqe 726 return [&ring.submit_q.sqes[ idx ], idx]; 810 727 } 811 728 … … 825 742 __attribute((unused)) int len = 0; 826 743 __attribute((unused)) int block = 0; 744 uint32_t expected = -1ul32; 827 745 uint32_t ready_mask = ring.submit_q.ready_cnt - 1; 828 746 uint32_t off = __tls_rand(); … … 830 748 for(i; ring.submit_q.ready_cnt) { 831 749 uint32_t ii = (i + off) & ready_mask; 832 uint32_t expected = -1ul32;833 750 if( __atomic_compare_exchange_n( &ring.submit_q.ready[ii], &expected, idx, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) { 834 751 break LOOKING; 835 752 } 836 verify(expected != idx);837 753 838 754 len ++; … … 876 792 // update statistics 877 793 #if !defined(__CFA_NO_STATISTICS__) 878 ring.submit_q.stats.submit_avg. csm+= 1;794 ring.submit_q.stats.submit_avg.val += 1; 879 795 ring.submit_q.stats.submit_avg.cnt += 1; 880 796 #endif … … 915 831 916 832 #define __submit_prelude \ 917 io_user_data data = { 0, active_thread() }; \ 918 struct __io_data & ring = *data.thrd->curr_cluster->io; \ 833 struct __io_data & ring = *active_cluster()->io; \ 919 834 struct io_uring_sqe * sqe; \ 920 835 uint32_t idx; \ 921 [sqe, idx] = __submit_alloc( ring , (uint64_t)&data);836 [sqe, idx] = __submit_alloc( ring ); 922 837 923 838 #define __submit_wait \ 839 io_user_data data = { 0, active_thread() }; \ 924 840 /*__cfaabi_bits_print_safe( STDERR_FILENO, "Preparing user data %p for %p\n", &data, data.thrd );*/ \ 925 verify( sqe->user_data == (uint64_t)&data ); \841 sqe->user_data = (uint64_t)&data; \ 926 842 __submit( ring, idx ); \ 927 843 park( __cfaabi_dbg_ctx ); \ -
libcfa/src/concurrency/kernel.cfa
r0e4df2e r2802824 648 648 649 649 // record activity 650 __cfaabi_dbg_debug_do( char * old_caller = thrd->unpark_caller; )651 650 __cfaabi_dbg_record_thrd( *thrd, false, caller ); 652 651 -
libcfa/src/containers/list.hfa
r0e4df2e r2802824 301 301 $prev_link(list_pos) = (Telem*) 0p; 302 302 } 303 304 static inline bool ?`is_empty(dlist(Tnode, Telem) &list) {305 assert( &list != 0p );306 $dlinks(Telem) *listLinks = & list.$links;307 if (listLinks->next.is_terminator) {308 assert(listLinks->prev.is_terminator);309 assert(listLinks->next.terminator);310 assert(listLinks->prev.terminator);311 return true;312 } else {313 assert(!listLinks->prev.is_terminator);314 assert(listLinks->next.elem);315 assert(listLinks->prev.elem);316 return false;317 }318 }319 320 static inline Telem & pop_first(dlist(Tnode, Telem) &list) {321 assert( &list != 0p );322 assert( !list`is_empty );323 $dlinks(Telem) *listLinks = & list.$links;324 Telem & first = *listLinks->next.elem;325 Tnode & list_pos_first = $tempcv_e2n( first );326 remove(list_pos_first);327 return first;328 }329 330 static inline Telem & pop_last(dlist(Tnode, Telem) &list) {331 assert( &list != 0p );332 assert( !list`is_empty );333 $dlinks(Telem) *listLinks = & list.$links;334 Telem & last = *listLinks->prev.elem;335 Tnode & list_pos_last = $tempcv_e2n( last );336 remove(list_pos_last);337 return last;338 }339 340 303 } 341 304 -
libcfa/src/exception.c
r0e4df2e r2802824 10 10 // Created On : Mon Jun 26 15:13:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hr May 21 12:18:00 202013 // Update Count : 2012 // Last Modified On : Tue Apr 14 12:01:00 2020 13 // Update Count : 18 14 14 // 15 15 … … 80 80 } 81 81 82 void __cfaehm_throw_resume(exception_t * except , void (*defaultHandler)(exception_t *)) {82 void __cfaehm_throw_resume(exception_t * except) { 83 83 struct exception_context_t * context = this_exception_context(); 84 84 … … 96 96 } 97 97 98 // No handler found, fall back to the default operation.99 98 __cfadbg_print_safe(exception, "Unhandled exception\n"); 100 defaultHandler(except); 99 100 // Fall back to termination: 101 __cfaehm_throw_terminate(except); 102 // TODO: Default handler for resumption. 101 103 } 102 104 … … 221 223 222 224 // Cancel the current stack, prefroming approprate clean-up and messaging. 223 void __cfaehm_cancel_stack( exception_t * exception ) { 225 static __attribute__((noreturn)) void __cfaehm_cancel_stack( 226 exception_t * exception ) { 224 227 // TODO: Detect current stack and pick a particular stop-function. 225 228 _Unwind_Reason_Code ret; … … 237 240 } 238 241 239 static void __cfaehm_cleanup_default( exception_t ** except ) {240 __cfaehm_delete_exception( *except );241 *except = NULL;242 }243 244 242 // The exception that is being thrown must already be stored. 245 static void __cfaehm_begin_unwind(void(*defaultHandler)(exception_t *)) { 246 struct exception_context_t * context = this_exception_context(); 247 struct _Unwind_Exception * storage = &this_exception_storage; 248 if ( NULL == context->current_exception ) { 243 static __attribute__((noreturn)) void __cfaehm_begin_unwind(void) { 244 if ( ! this_exception_context()->current_exception ) { 249 245 printf("UNWIND ERROR missing exception in begin unwind\n"); 250 246 abort(); … … 252 248 253 249 // Call stdlibc to raise the exception 254 __cfadbg_print_safe(exception, "Begin unwinding (storage &p, context %p)\n", storage, context); 255 _Unwind_Reason_Code ret = _Unwind_RaiseException( storage ); 250 _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage ); 256 251 257 252 // If we reach here it means something happened. For resumption to work we need to find a way … … 262 257 // the whole stack. 263 258 259 // No handler found, go to the default operation. 260 // Currently this will always be a cancellation. 261 if ( ret == _URC_END_OF_STACK ) { 262 __cfadbg_print_safe(exception, "Uncaught exception %p\n", &this_exception_storage); 263 264 __cfaehm_cancel_stack(this_exception_context()->current_exception); 265 } 266 264 267 // We did not simply reach the end of the stack without finding a handler. This is an error. 265 if ( ret != _URC_END_OF_STACK ) { 266 printf("UNWIND ERROR %d after raise exception\n", ret); 267 abort(); 268 } 269 270 // No handler found, go to the default operation. 271 __cfadbg_print_safe(exception, "Uncaught exception %p\n", storage); 272 273 __attribute__((cleanup(__cfaehm_cleanup_default))) 274 exception_t * exception = context->current_exception; 275 defaultHandler( exception ); 276 } 277 278 void __cfaehm_throw_terminate( exception_t * val, void (*defaultHandler)(exception_t *) ) { 268 printf("UNWIND ERROR %d after raise exception\n", ret); 269 abort(); 270 } 271 272 void __cfaehm_throw_terminate( exception_t * val ) { 279 273 __cfadbg_print_safe(exception, "Throwing termination exception\n"); 280 274 281 275 __cfaehm_allocate_exception( val ); 282 __cfaehm_begin_unwind( defaultHandler ); 283 } 284 285 static __attribute__((noreturn)) void __cfaehm_rethrow_adapter( exception_t * except ) { 286 // TODO: Print some error message. 287 (void)except; 288 abort(); 276 __cfaehm_begin_unwind(); 289 277 } 290 278 … … 292 280 __cfadbg_print_safe(exception, "Rethrowing termination exception\n"); 293 281 294 __cfaehm_begin_unwind( __cfaehm_rethrow_adapter ); 295 abort(); 282 __cfaehm_begin_unwind(); 296 283 } 297 284 -
libcfa/src/exception.h
r0e4df2e r2802824 10 10 // Created On : Mon Jun 26 15:11:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue May 19 14:17:00 202013 // Update Count : 1012 // Last Modified On : Fri Mar 27 10:16:00 2020 13 // Update Count : 9 14 14 // 15 15 … … 38 38 39 39 40 void __cfaehm_cancel_stack(exception_t * except) __attribute__((noreturn));41 42 40 // Used in throw statement translation. 43 void __cfaehm_throw_terminate(exception_t * except , void (*)(exception_t *));41 void __cfaehm_throw_terminate(exception_t * except) __attribute__((noreturn)); 44 42 void __cfaehm_rethrow_terminate() __attribute__((noreturn)); 45 void __cfaehm_throw_resume(exception_t * except , void (*)(exception_t *));43 void __cfaehm_throw_resume(exception_t * except); 46 44 47 45 // Function catches termination exceptions. … … 72 70 #ifdef __cforall 73 71 } 74 75 // Not all the built-ins can be expressed in C. These can't be76 // implemented in the .c file either so they all have to be inline.77 78 trait is_exception(dtype T) {79 /* The first field must be a pointer to a virtual table.80 * That virtual table must be a decendent of the base exception virtual tab$81 */82 void mark_exception(T *);83 // This is never used and should be a no-op.84 };85 86 trait is_termination_exception(dtype T | is_exception(T)) {87 void defaultTerminationHandler(T &);88 };89 90 trait is_resumption_exception(dtype T | is_exception(T)) {91 void defaultResumptionHandler(T &);92 };93 94 forall(dtype T | is_termination_exception(T))95 static inline void $throw(T & except) {96 __cfaehm_throw_terminate(97 (exception_t *)&except,98 (void(*)(exception_t *))defaultTerminationHandler99 );100 }101 102 forall(dtype T | is_resumption_exception(T))103 static inline void $throwResume(T & except) {104 __cfaehm_throw_resume(105 (exception_t *)&except,106 (void(*)(exception_t *))defaultResumptionHandler107 );108 }109 110 forall(dtype T | is_exception(T))111 static inline void cancel_stack(T & except) __attribute__((noreturn)) {112 __cfaehm_cancel_stack( (exception_t *)&except );113 }114 115 forall(dtype T | is_exception(T))116 static inline void defaultTerminationHandler(T & except) {117 return cancel_stack( except );118 }119 120 forall(dtype T | is_exception(T))121 static inline void defaultResumptionHandler(T & except) {122 throw except;123 }124 125 72 #endif -
libcfa/src/exception.hfa
r0e4df2e r2802824 10 10 // Created On : Thu Apr 7 10:25:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T ue May 19 14:17:00 202013 // Update Count : 212 // Last Modified On : Thu Apr 7 10:25:00 2020 13 // Update Count : 0 14 14 // 15 15 … … 69 69 #define _VTABLE_DECLARATION(exception_name, parent_name, ...) \ 70 70 struct exception_name; \ 71 void mark_exception(exception_name *); \72 71 VTABLE_TYPE(exception_name); \ 73 72 extern VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name); \ … … 86 85 #define VTABLE_INSTANCE(...) _EXC_DISPATCH(_VTABLE_INSTANCE, __VA_ARGS__) 87 86 #define _VTABLE_INSTANCE(exception_name, parent_name, ...) \ 88 void mark_exception(exception_name *) {} \89 87 void _GLUE2(exception_name,_copy)(exception_name * this, exception_name * other) { \ 90 88 *this = *other; \ -
libcfa/src/executor.cfa
r0e4df2e r2802824 4 4 // buffer. 5 5 6 #include < containers/list.hfa>6 #include <bits/containers.hfa> 7 7 #include <thread.hfa> 8 8 #include <stdio.h> 9 9 10 forall( dtype T ) 11 monitor Buffer { // unbounded buffer 12 __queue_t( T ) queue; // unbounded list of work requests 13 condition delay; 14 }; // Buffer 15 forall( dtype T | is_node(T) ) { 16 void insert( Buffer( T ) & mutex buf, T * elem ) with(buf) { 17 append( queue, elem ); // insert element into buffer 18 signal( delay ); // restart 19 } // insert 20 21 T * remove( Buffer( T ) & mutex buf ) with(buf) { 22 if ( queue.head != 0 ) wait( delay ); // no request to process ? => wait 23 // return pop_head( queue ); 24 } // remove 25 } // distribution 26 10 27 struct WRequest { // client request, no return 11 28 void (* action)( void ); 12 DLISTED_MGD_IMPL_IN(WRequest)29 WRequest * next; // intrusive queue field 13 30 }; // WRequest 14 DLISTED_MGD_IMPL_OUT(WRequest)15 31 16 void ?{}( WRequest & req ) with(req) { action = 0; } 17 void ?{}( WRequest & req, void (* action)( void ) ) with(req) { req.action = action; } 32 WRequest *& get_next( WRequest & this ) { return this.next; } 33 void ?{}( WRequest & req ) with(req) { action = 0; next = 0; } 34 void ?{}( WRequest & req, void (* action)( void ) ) with(req) { req.action = action; next = 0; } 18 35 bool stop( WRequest & req ) { return req.action == 0; } 19 36 void doit( WRequest & req ) { req.action(); } 20 21 monitor WRBuffer { // unbounded buffer22 dlist( WRequest, WRequest ) queue; // unbounded list of work requests23 condition delay;24 }; // WRBuffer25 26 void insert( WRBuffer & mutex buf, WRequest * elem ) with(buf) {27 insert_last( queue, *elem ); // insert element into buffer28 signal( delay ); // restart29 } // insert30 31 WRequest * remove( WRBuffer & mutex buf ) with(buf) {32 if ( queue`is_empty ) wait( delay ); // no request to process ? => wait33 return & pop_first( queue );34 } // remove35 37 36 38 // Each worker has its own work buffer to reduce contention between client and server. Hence, work requests arrive and … … 38 40 39 41 thread Worker { 40 WRBuffer* requests;42 Buffer( WRequest ) * requests; 41 43 unsigned int start, range; 42 44 }; // Worker … … 52 54 } // Worker::main 53 55 54 void ?{}( Worker & worker, cluster * wc, WRBuffer* requests, unsigned int start, unsigned int range ) {56 void ?{}( Worker & worker, cluster * wc, Buffer( WRequest ) * requests, unsigned int start, unsigned int range ) { 55 57 (*get_thread(worker)){ *wc }; // create on given cluster 56 58 worker.[requests, start, range] = [requests, start, range]; … … 60 62 cluster * cluster; // if workers execute on separate cluster 61 63 processor ** processors; // array of virtual processors adding parallelism for workers 62 WRBuffer * requests;// list of work requests64 Buffer( WRequest ) * requests; // list of work requests 63 65 Worker ** workers; // array of workers executing work requests 64 66 unsigned int nprocessors, nworkers, nmailboxes; // number of mailboxes/workers/processor tasks … … 77 79 cluster = sepClus ? new( "Executor" ) : active_cluster(); 78 80 processors = (processor **)anew( nprocessors ); 79 requests = (WRBuffer *)anew( nmailboxes );81 requests = anew( nmailboxes ); 80 82 workers = (Worker **)anew( nworkers ); 81 83 … … 139 141 for ( i; 3000 ) { 140 142 send( exector, workie ); 141 if ( i % 100 == 0 ) { 142 // fprintf( stderr, "%d\n", i ); 143 yield(); 144 } 143 if ( i % 100 ) yield(); 145 144 } // for 146 145 } -
libcfa/src/heap.cfa
r0e4df2e r2802824 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun May 17 20:58:17202013 // Update Count : 7 6212 // Last Modified On : Wed May 6 17:29:26 2020 13 // Update Count : 727 14 14 // 15 15 … … 128 128 #define LOCKFREE 1 129 129 #define BUCKETLOCK SPINLOCK 130 #if BUCKETLOCK == SPINLOCK 131 #elif BUCKETLOCK == LOCKFREE 132 #include <stackLockFree.hfa> 133 #else 134 #error undefined lock type for bucket lock 130 #if BUCKETLOCK == LOCKFREE 131 #include <uStackLF.h> 135 132 #endif // LOCKFREE 136 133 … … 140 137 141 138 struct HeapManager { 139 // struct FreeHeader; // forward declaration 140 142 141 struct Storage { 143 142 struct Header { // header … … 147 146 struct { // 4-byte word => 8-byte header, 8-byte word => 16-byte header 148 147 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4 149 uint 64_t padding; // unused, force home/blocksize to overlay alignment in fake header148 uint32_t padding; // unused, force home/blocksize to overlay alignment in fake header 150 149 #endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4 151 150 152 151 union { 153 //FreeHeader * home; // allocated block points back to home locations (must overlay alignment)152 // FreeHeader * home; // allocated block points back to home locations (must overlay alignment) 154 153 // 2nd low-order bit => zero filled 155 154 void * home; // allocated block points back to home locations (must overlay alignment) 156 155 size_t blockSize; // size for munmap (must overlay alignment) 157 #if BUCK ETLOCK == SPINLOCK156 #if BUCKLOCK == SPINLOCK 158 157 Storage * next; // freed block points next freed block of same size 159 158 #endif // SPINLOCK 160 159 }; 161 size_t size; // allocation size in bytes162 160 163 161 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4 164 uint 64_t padding; // unused, force home/blocksize to overlay alignment in fake header162 uint32_t padding; // unused, force home/blocksize to overlay alignment in fake header 165 163 #endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4 166 164 }; 167 #if BUCKETLOCK == LOCKFREE 168 Link(Storage) next; // freed block points next freed block of same size (double-wide) 165 // future code 166 #if BUCKLOCK == LOCKFREE 167 Stack<Storage>::Link next; // freed block points next freed block of same size (double-wide) 169 168 #endif // LOCKFREE 170 169 }; 171 170 } real; // RealHeader 172 173 171 struct FakeHeader { 174 172 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 175 uint32_t alignment; // 1st low-order bit => fake header & alignment 173 // 1st low-order bit => fake header & alignment 174 uint32_t alignment; 176 175 #endif // __ORDER_LITTLE_ENDIAN__ 177 176 … … 183 182 } fake; // FakeHeader 184 183 } kind; // Kind 184 size_t size; // allocation size in bytes 185 185 } header; // Header 186 186 char pad[libAlign() - sizeof( Header )]; … … 191 191 192 192 struct FreeHeader { 193 #if BUCK ETLOCK == SPINLOCK193 #if BUCKLOCK == SPINLOCK 194 194 __spinlock_t lock; // must be first field for alignment 195 195 Storage * freeList; 196 #elif BUCKLOCK == LOCKFREE 197 // future code 198 StackLF<Storage> freeList; 196 199 #else 197 StackLF(Storage) freeList;198 #endif // BUCKETLOCK200 #error undefined lock type for bucket lock 201 #endif // SPINLOCK 199 202 size_t blockSize; // size of allocations on this list 200 203 }; // FreeHeader … … 208 211 size_t heapRemaining; // amount of storage not allocated in the current chunk 209 212 }; // HeapManager 210 211 #if BUCKETLOCK == LOCKFREE212 static inline Link(HeapManager.Storage) * getNext( HeapManager.Storage * this ) { return &this->header.kind.real.next; }213 static inline void ?{}( HeapManager.FreeHeader & ) {}214 static inline void ^?{}( HeapManager.FreeHeader & ) {}215 #endif // LOCKFREE216 213 217 214 static inline size_t getKey( const HeapManager.FreeHeader & freeheader ) { return freeheader.blockSize; } … … 254 251 static bool heapBoot = 0; // detect recursion during boot 255 252 #endif // __CFA_DEBUG__ 256 257 // The constructor for heapManager is called explicitly in memory_startup.258 253 static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing 259 254 … … 359 354 360 355 356 // static inline void noMemory() { 357 // abort( "Heap memory exhausted at %zu bytes.\n" 358 // "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.", 359 // ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) ); 360 // } // noMemory 361 362 361 363 // thunk problem 362 364 size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) { … … 404 406 405 407 406 // static inline void noMemory() {407 // abort( "Heap memory exhausted at %zu bytes.\n"408 // "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",409 // ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );410 // } // noMemory411 412 413 408 static inline void checkAlign( size_t alignment ) { 414 409 if ( alignment < libAlign() || ! libPow2( alignment ) ) { … … 438 433 439 434 440 static inline bool headers( const char name[] __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, 441 size_t & size, size_t & alignment ) with( heapManager ) { 435 static inline bool headers( const char name[] __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) { 442 436 header = headerAddr( addr ); 443 437 … … 471 465 472 466 473 static inline void * extend( size_t size ) with ( heapManager ) {467 static inline void * extend( size_t size ) with ( heapManager ) { 474 468 lock( extlock __cfaabi_dbg_ctx2 ); 475 469 ptrdiff_t rem = heapRemaining - size; … … 502 496 503 497 504 static inline void * doMalloc( size_t size ) with ( heapManager ) {498 static inline void * doMalloc( size_t size ) with ( heapManager ) { 505 499 HeapManager.Storage * block; // pointer to new block of storage 506 500 … … 535 529 // Spin until the lock is acquired for this particular size of block. 536 530 537 #if BUCKETLOCK == SPINLOCK531 #if defined( SPINLOCK ) 538 532 lock( freeElem->lock __cfaabi_dbg_ctx2 ); 539 533 block = freeElem->freeList; // remove node from stack 540 534 #else 541 block = pop( freeElem->freeList);542 #endif // BUCKETLOCK535 block = freeElem->freeList.pop(); 536 #endif // SPINLOCK 543 537 if ( unlikely( block == 0p ) ) { // no free block ? 544 #if BUCKETLOCK == SPINLOCK538 #if defined( SPINLOCK ) 545 539 unlock( freeElem->lock ); 546 #endif // BUCKETLOCK540 #endif // SPINLOCK 547 541 548 542 // Freelist for that size was empty, so carve it out of the heap if there's enough left, or get some more … … 550 544 551 545 block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call 552 if ( unlikely( block == 0p ) ) return 0p;553 #if BUCKETLOCK == SPINLOCK546 if ( unlikely( block == 0p ) ) return 0p; 547 #if defined( SPINLOCK ) 554 548 } else { 555 549 freeElem->freeList = block->header.kind.real.next; 556 550 unlock( freeElem->lock ); 557 #endif // BUCKETLOCK551 #endif // SPINLOCK 558 552 } // if 559 553 … … 578 572 } // if 579 573 580 block->header. kind.real.size = size;// store allocation size574 block->header.size = size; // store allocation size 581 575 void * addr = &(block->data); // adjust off header to user bytes 582 576 … … 597 591 598 592 599 static inline void doFree( void * addr ) with ( heapManager ) {593 static inline void doFree( void * addr ) with ( heapManager ) { 600 594 #ifdef __CFA_DEBUG__ 601 595 if ( unlikely( heapManager.heapBegin == 0p ) ) { … … 629 623 free_storage += size; 630 624 #endif // __STATISTICS__ 631 #if BUCKETLOCK == SPINLOCK625 #if defined( SPINLOCK ) 632 626 lock( freeElem->lock __cfaabi_dbg_ctx2 ); // acquire spin lock 633 627 header->kind.real.next = freeElem->freeList; // push on stack … … 635 629 unlock( freeElem->lock ); // release spin lock 636 630 #else 637 push( freeElem->freeList,*(HeapManager.Storage *)header );638 #endif // BUCKETLOCK631 freeElem->freeList.push( *(HeapManager.Storage *)header ); 632 #endif // SPINLOCK 639 633 } // if 640 634 … … 651 645 652 646 653 size_t prtFree( HeapManager & manager ) with ( manager ) {647 size_t prtFree( HeapManager & manager ) with ( manager ) { 654 648 size_t total = 0; 655 649 #ifdef __STATISTICS__ … … 663 657 #endif // __STATISTICS__ 664 658 665 #if BUCKETLOCK == SPINLOCK659 #if defined( SPINLOCK ) 666 660 for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) { 667 661 #else 668 for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) { 669 typeof(p) temp = getNext( p )->top; // FIX ME: direct assignent fails, initialization works 670 p = temp; 671 #endif // BUCKETLOCK 662 for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0p; p = p->header.kind.real.next.top ) { 663 #endif // SPINLOCK 672 664 total += size; 673 665 #ifdef __STATISTICS__ … … 689 681 690 682 691 static void ?{}( HeapManager & manager ) with ( manager ) {683 static void ?{}( HeapManager & manager ) with ( manager ) { 692 684 pageSize = sysconf( _SC_PAGESIZE ); 693 685 … … 1103 1095 header = realHeader( header ); // backup from fake to real header 1104 1096 } // if 1105 return header-> kind.real.size;1097 return header->size; 1106 1098 } // malloc_size 1107 1099 … … 1113 1105 header = realHeader( header ); // backup from fake to real header 1114 1106 } // if 1115 size_t ret = header-> kind.real.size;1116 header-> kind.real.size = size;1107 size_t ret = header->size; 1108 header->size = size; 1117 1109 return ret; 1118 1110 } // $malloc_size_set -
libcfa/src/stdlib.hfa
r0e4df2e r2802824 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed May 13 17:23:51202013 // Update Count : 43 512 // Last Modified On : Thu Apr 16 22:44:05 2020 13 // Update Count : 432 14 14 // 15 15 … … 23 23 // Reduce includes by explicitly defining these routines. 24 24 extern "C" { 25 void * aalloc( size_t dim, size_t elemSize ); // CFA heap26 void * resize( void * oaddr, size_t size ); // CFA heap27 25 void * memalign( size_t align, size_t size ); // malloc.h 28 void * amemalign( size_t align, size_t dim, size_t elemSize ); // CFA heap 29 void * cmemalign( size_t align, size_t noOfElems, size_t elemSize ); // CFA heap 26 size_t malloc_usable_size( void * ptr ); // malloc.h 30 27 size_t malloc_size( void * addr ); // CFA heap 31 size_t malloc_usable_size( void * ptr ); // malloc.h28 void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ); // CFA heap 32 29 void * memset( void * dest, int fill, size_t size ); // string.h 33 30 void * memcpy( void * dest, const void * src, size_t size ); // string.h 31 void * resize( void * oaddr, size_t size ); // CFA heap 34 32 } // extern "C" 35 33 … … 54 52 } // malloc 55 53 56 T * aalloc( size_t dim ) {57 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)aalloc( dim, (size_t)sizeof(T) ); // CFA aalloc58 else return (T *)amemalign( _Alignof(T), dim, sizeof(T) );59 } // aalloc60 61 54 T * calloc( size_t dim ) { 62 55 if ( _Alignof(T) <= libAlign() )return (T *)(void *)calloc( dim, sizeof(T) ); // C calloc … … 64 57 } // calloc 65 58 66 T * resize( T * ptr, size_t size ) { // CFA realloc, eliminate return-type cast67 return (T *)(void *)resize( (void *)ptr, size ); // C realloc68 } // resize69 70 59 T * realloc( T * ptr, size_t size ) { // CFA realloc, eliminate return-type cast 71 60 return (T *)(void *)realloc( (void *)ptr, size ); // C realloc … … 76 65 } // memalign 77 66 78 T * amemalign( size_t align, size_t dim ) {79 return (T *)amemalign( align, dim, sizeof(T) ); // CFA amemalign80 } // amemalign81 82 67 T * cmemalign( size_t align, size_t dim ) { 83 68 return (T *)cmemalign( align, dim, sizeof(T) ); // CFA cmemalign … … 101 86 102 87 T * alloc( size_t dim ) { 103 return aalloc( dim ); 88 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)malloc( dim * (size_t)sizeof(T) ); 89 else return (T *)memalign( _Alignof(T), dim * sizeof(T) ); 104 90 } // alloc 105 91 … … 120 106 return (T *)(void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc 121 107 } else { 122 return resize( ptr, dim * sizeof(T) ); // resize 108 struct __Unknown {}; 109 return alloc( (__Unknown *)ptr, dim ); // reuse, cheat making T/S different types 123 110 } // if 124 111 } // alloc … … 161 148 } // alloc_align 162 149 163 T * alloc_align( T * ptr, size_t align ) { // aligned realloc array150 T * alloc_align( T ptr[], size_t align ) { // aligned realloc array 164 151 return (T *)(void *)realloc( (void *)ptr, align, sizeof(T) ); // CFA realloc 165 152 } // alloc_align -
src/ControlStruct/ExceptTranslate.cc
r0e4df2e r2802824 10 10 // Created On : Wed Jun 14 16:49:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr May 21 13:18:00 202013 // Update Count : 1 512 // Last Modified On : Fri Mar 27 11:58:00 2020 13 // Update Count : 13 14 14 // 15 15 … … 64 64 } 65 65 66 class ThrowMutatorCore : public WithGuards { 67 ObjectDecl * terminate_handler_except; 68 enum Context { NoHandler, TerHandler, ResHandler } cur_context; 69 70 // The helper functions for code/syntree generation. 71 Statement * create_either_throw( 72 ThrowStmt * throwStmt, const char * throwFunc ); 73 Statement * create_terminate_rethrow( ThrowStmt * throwStmt ); 74 Statement * create_resume_rethrow( ThrowStmt * throwStmt ); 75 76 public: 77 ThrowMutatorCore() : 78 terminate_handler_except( nullptr ), 79 cur_context( NoHandler ) 80 {} 81 82 void premutate( CatchStmt *catchStmt ); 83 Statement * postmutate( ThrowStmt *throwStmt ); 84 }; 85 86 // ThrowStmt Mutation Helpers 87 88 Statement * ThrowMutatorCore::create_either_throw( 89 ThrowStmt * throwStmt, const char * throwFunc ) { 90 // `throwFunc`( `throwStmt->get_name()` ); 91 UntypedExpr * call = new UntypedExpr( new NameExpr( throwFunc ) ); 92 call->get_args().push_back( throwStmt->get_expr() ); 93 throwStmt->set_expr( nullptr ); 94 delete throwStmt; 95 return new ExprStmt( call ); 96 } 97 98 Statement * ThrowMutatorCore::create_terminate_rethrow( 99 ThrowStmt *throwStmt ) { 100 // { `terminate_handler_except` = 0p; __rethrow_terminate(); } 101 assert( nullptr == throwStmt->get_expr() ); 102 assert( terminate_handler_except ); 103 104 CompoundStmt * result = new CompoundStmt(); 105 result->labels = throwStmt->labels; 106 result->push_back( new ExprStmt( UntypedExpr::createAssign( 107 nameOf( terminate_handler_except ), 108 new ConstantExpr( Constant::null( 109 //new PointerType( 110 // noQualifiers, 111 terminate_handler_except->get_type()->clone() 112 // ) 113 ) ) 114 ) ) ); 115 result->push_back( new ExprStmt( 116 new UntypedExpr( new NameExpr( "__cfaehm_rethrow_terminate" ) ) 117 ) ); 118 delete throwStmt; 119 return result; 120 } 121 122 Statement * ThrowMutatorCore::create_resume_rethrow( 123 ThrowStmt *throwStmt ) { 124 // return false; 125 Statement * result = new ReturnStmt( 126 new ConstantExpr( Constant::from_bool( false ) ) 127 ); 128 result->labels = throwStmt->labels; 129 delete throwStmt; 130 return result; 131 } 132 133 // Visiting/Mutating Functions 134 135 void ThrowMutatorCore::premutate( CatchStmt *catchStmt ) { 136 // Validate the statement's form. 137 ObjectDecl * decl = dynamic_cast<ObjectDecl *>( catchStmt->get_decl() ); 138 // Also checking the type would be nice. 139 if ( decl ) { 140 // Pass. 141 } else if ( CatchStmt::Terminate == catchStmt->get_kind() ) { 142 SemanticError(catchStmt->location, "catch must have exception type"); 143 } else { 144 SemanticError(catchStmt->location, "catchResume must have exception type"); 145 } 146 147 // Track the handler context. 148 GuardValue( cur_context ); 149 if ( CatchStmt::Terminate == catchStmt->get_kind() ) { 150 cur_context = TerHandler; 151 152 GuardValue( terminate_handler_except ); 153 terminate_handler_except = decl; 154 } else { 155 cur_context = ResHandler; 156 } 157 } 158 159 Statement * ThrowMutatorCore::postmutate( ThrowStmt *throwStmt ) { 160 // Ignoring throwStmt->get_target() for now. 161 if ( ThrowStmt::Terminate == throwStmt->get_kind() ) { 162 if ( throwStmt->get_expr() ) { 163 return create_either_throw( throwStmt, "$throw" ); 164 } else if ( TerHandler == cur_context ) { 165 return create_terminate_rethrow( throwStmt ); 166 } else { 167 abort("Invalid throw in %s at %i\n", 168 throwStmt->location.filename.c_str(), 169 throwStmt->location.first_line); 170 } 171 } else { 172 if ( throwStmt->get_expr() ) { 173 return create_either_throw( throwStmt, "$throwResume" ); 174 } else if ( ResHandler == cur_context ) { 175 return create_resume_rethrow( throwStmt ); 176 } else { 177 abort("Invalid throwResume in %s at %i\n", 178 throwStmt->location.filename.c_str(), 179 throwStmt->location.first_line); 180 } 181 } 182 } 183 184 class TryMutatorCore { 66 class ExceptionMutatorCore : public WithGuards { 67 enum Context { NoHandler, TerHandler, ResHandler }; 68 69 // Also need to handle goto, break & continue. 70 // They need to be cut off in a ResHandler, until we enter another 71 // loop, switch or the goto stays within the function. 72 73 Context cur_context; 74 75 // The current (innermost) termination handler exception declaration. 76 ObjectDecl * handler_except_decl; 77 185 78 // The built in types used in translation. 186 79 StructDecl * except_decl; … … 189 82 190 83 // The many helper functions for code/syntree generation. 84 Statement * create_given_throw( 85 const char * throwFunc, ThrowStmt * throwStmt ); 86 Statement * create_terminate_throw( ThrowStmt * throwStmt ); 87 Statement * create_terminate_rethrow( ThrowStmt * throwStmt ); 88 Statement * create_resume_throw( ThrowStmt * throwStmt ); 89 Statement * create_resume_rethrow( ThrowStmt * throwStmt ); 191 90 CompoundStmt * take_try_block( TryStmt * tryStmt ); 192 91 FunctionDecl * create_try_wrapper( CompoundStmt * body ); … … 222 121 223 122 public: 224 TryMutatorCore() : 123 ExceptionMutatorCore() : 124 cur_context( NoHandler ), 125 handler_except_decl( nullptr ), 225 126 except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr ), 226 127 try_func_t( noQualifiers, false ), … … 231 132 {} 232 133 134 void premutate( CatchStmt *catchStmt ); 233 135 void premutate( StructDecl *structDecl ); 234 136 Statement * postmutate( ThrowStmt *throwStmt ); … … 236 138 }; 237 139 238 void TryMutatorCore::init_func_types() {140 void ExceptionMutatorCore::init_func_types() { 239 141 assert( except_decl ); 240 142 … … 294 196 } 295 197 198 // ThrowStmt Mutation Helpers 199 200 Statement * ExceptionMutatorCore::create_given_throw( 201 const char * throwFunc, ThrowStmt * throwStmt ) { 202 // `throwFunc`( `throwStmt->get_name` ); 203 UntypedExpr * call = new UntypedExpr( new NameExpr( throwFunc ) ); 204 call->get_args().push_back( throwStmt->get_expr() ); 205 throwStmt->set_expr( nullptr ); 206 delete throwStmt; 207 return new ExprStmt( call ); 208 } 209 210 Statement * ExceptionMutatorCore::create_terminate_throw( 211 ThrowStmt *throwStmt ) { 212 // __throw_terminate( `throwStmt->get_name()` ); } 213 return create_given_throw( "__cfaehm_throw_terminate", throwStmt ); 214 } 215 216 Statement * ExceptionMutatorCore::create_terminate_rethrow( 217 ThrowStmt *throwStmt ) { 218 // { `handler_except_decl` = NULL; __rethrow_terminate(); } 219 assert( nullptr == throwStmt->get_expr() ); 220 assert( handler_except_decl ); 221 222 CompoundStmt * result = new CompoundStmt(); 223 result->labels = throwStmt->labels; 224 result->push_back( new ExprStmt( UntypedExpr::createAssign( 225 nameOf( handler_except_decl ), 226 new ConstantExpr( Constant::null( 227 new PointerType( 228 noQualifiers, 229 handler_except_decl->get_type()->clone() 230 ) 231 ) ) 232 ) ) ); 233 result->push_back( new ExprStmt( 234 new UntypedExpr( new NameExpr( "__cfaehm_rethrow_terminate" ) ) 235 ) ); 236 delete throwStmt; 237 return result; 238 } 239 240 Statement * ExceptionMutatorCore::create_resume_throw( 241 ThrowStmt *throwStmt ) { 242 // __throw_resume( `throwStmt->get_name` ); 243 return create_given_throw( "__cfaehm_throw_resume", throwStmt ); 244 } 245 246 Statement * ExceptionMutatorCore::create_resume_rethrow( 247 ThrowStmt *throwStmt ) { 248 // return false; 249 Statement * result = new ReturnStmt( 250 new ConstantExpr( Constant::from_bool( false ) ) 251 ); 252 result->labels = throwStmt->labels; 253 delete throwStmt; 254 return result; 255 } 256 296 257 // TryStmt Mutation Helpers 297 258 298 CompoundStmt * TryMutatorCore::take_try_block( TryStmt *tryStmt ) {259 CompoundStmt * ExceptionMutatorCore::take_try_block( TryStmt *tryStmt ) { 299 260 CompoundStmt * block = tryStmt->get_block(); 300 261 tryStmt->set_block( nullptr ); … … 302 263 } 303 264 304 FunctionDecl * TryMutatorCore::create_try_wrapper(265 FunctionDecl * ExceptionMutatorCore::create_try_wrapper( 305 266 CompoundStmt *body ) { 306 267 … … 309 270 } 310 271 311 FunctionDecl * TryMutatorCore::create_terminate_catch(272 FunctionDecl * ExceptionMutatorCore::create_terminate_catch( 312 273 CatchList &handlers ) { 313 274 std::list<CaseStmt *> handler_wrappers; … … 389 350 // Create a single check from a moddified handler. 390 351 // except_obj is referenced, modded_handler will be freed. 391 CompoundStmt * TryMutatorCore::create_single_matcher(352 CompoundStmt * ExceptionMutatorCore::create_single_matcher( 392 353 DeclarationWithType * except_obj, CatchStmt * modded_handler ) { 393 354 // { … … 427 388 } 428 389 429 FunctionDecl * TryMutatorCore::create_terminate_match(390 FunctionDecl * ExceptionMutatorCore::create_terminate_match( 430 391 CatchList &handlers ) { 431 392 // int match(exception * except) { … … 464 425 } 465 426 466 CompoundStmt * TryMutatorCore::create_terminate_caller(427 CompoundStmt * ExceptionMutatorCore::create_terminate_caller( 467 428 FunctionDecl * try_wrapper, 468 429 FunctionDecl * terminate_catch, … … 482 443 } 483 444 484 FunctionDecl * TryMutatorCore::create_resume_handler(445 FunctionDecl * ExceptionMutatorCore::create_resume_handler( 485 446 CatchList &handlers ) { 486 447 // bool handle(exception * except) { … … 519 480 } 520 481 521 CompoundStmt * TryMutatorCore::create_resume_wrapper(482 CompoundStmt * ExceptionMutatorCore::create_resume_wrapper( 522 483 Statement * wraps, 523 484 FunctionDecl * resume_handler ) { … … 563 524 } 564 525 565 FunctionDecl * TryMutatorCore::create_finally_wrapper(526 FunctionDecl * ExceptionMutatorCore::create_finally_wrapper( 566 527 TryStmt * tryStmt ) { 567 // void finally() { `finally->block`}528 // void finally() { <finally code> } 568 529 FinallyStmt * finally = tryStmt->get_finally(); 569 530 CompoundStmt * body = finally->get_block(); … … 576 537 } 577 538 578 ObjectDecl * TryMutatorCore::create_finally_hook(539 ObjectDecl * ExceptionMutatorCore::create_finally_hook( 579 540 FunctionDecl * finally_wrapper ) { 580 541 // struct __cfaehm_cleanup_hook __finally_hook 581 // __attribute__((cleanup( `finally_wrapper`)));542 // __attribute__((cleanup( finally_wrapper ))); 582 543 583 544 // Make Cleanup Attribute. … … 604 565 605 566 // Visiting/Mutating Functions 606 void TryMutatorCore::premutate( StructDecl *structDecl ) { 567 void ExceptionMutatorCore::premutate( CatchStmt *catchStmt ) { 568 // Validate the Statement's form. 569 ObjectDecl * decl = 570 dynamic_cast<ObjectDecl *>( catchStmt->get_decl() ); 571 if ( decl && true /* check decl->get_type() */ ) { 572 // Pass. 573 } else if ( CatchStmt::Terminate == catchStmt->get_kind() ) { 574 SemanticError(catchStmt->location, "catch must have exception type"); 575 } else { 576 SemanticError(catchStmt->location, "catchResume must have exception type"); 577 } 578 579 // Track the handler context. 580 GuardValue( cur_context ); 581 if ( CatchStmt::Terminate == catchStmt->get_kind() ) { 582 cur_context = TerHandler; 583 584 GuardValue( handler_except_decl ); 585 handler_except_decl = decl; 586 } else { 587 cur_context = ResHandler; 588 } 589 } 590 591 void ExceptionMutatorCore::premutate( StructDecl *structDecl ) { 607 592 if ( !structDecl->has_body() ) { 608 593 // Skip children? … … 619 604 hook_decl = structDecl; 620 605 } 621 } 622 623 Statement * TryMutatorCore::postmutate( ThrowStmt * ) { 624 // All throws should be removed by this point. 625 assert( false ); 626 } 627 628 Statement * TryMutatorCore::postmutate( TryStmt *tryStmt ) { 606 // Later we might get the exception type as well. 607 } 608 609 Statement * ExceptionMutatorCore::postmutate( ThrowStmt *throwStmt ) { 610 assert( except_decl ); 611 612 // Ignoring throwStmt->get_target() for now. 613 if ( ThrowStmt::Terminate == throwStmt->get_kind() ) { 614 if ( throwStmt->get_expr() ) { 615 return create_terminate_throw( throwStmt ); 616 } else if ( TerHandler == cur_context ) { 617 return create_terminate_rethrow( throwStmt ); 618 } else { 619 abort("Invalid throw in %s at %i\n", 620 throwStmt->location.filename.c_str(), 621 throwStmt->location.first_line); 622 } 623 } else { 624 if ( throwStmt->get_expr() ) { 625 return create_resume_throw( throwStmt ); 626 } else if ( ResHandler == cur_context ) { 627 return create_resume_rethrow( throwStmt ); 628 } else { 629 abort("Invalid throwResume in %s at %i\n", 630 throwStmt->location.filename.c_str(), 631 throwStmt->location.first_line); 632 } 633 } 634 } 635 636 Statement * ExceptionMutatorCore::postmutate( TryStmt *tryStmt ) { 629 637 assert( except_decl ); 630 638 assert( node_decl ); … … 680 688 } 681 689 682 void translate Throws( std::list< Declaration *> & translationUnit ) {683 PassVisitor< ThrowMutatorCore> translator;690 void translateEHM( std::list< Declaration *> & translationUnit ) { 691 PassVisitor<ExceptionMutatorCore> translator; 684 692 mutateAll( translationUnit, translator ); 685 693 } 686 687 void translateTries( std::list< Declaration *> & translationUnit ) {688 PassVisitor<TryMutatorCore> translator;689 mutateAll( translationUnit, translator );690 }691 694 } -
src/ControlStruct/ExceptTranslate.h
r0e4df2e r2802824 9 9 // Author : Andrew Beach 10 10 // Created On : Tus Jun 06 10:13:00 2017 11 // Last Modified By : Andrew Beach12 // Last Modified On : Tus May 19 11:47:00 202013 // Update Count : 511 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 22 09:19:23 2017 13 // Update Count : 4 14 14 // 15 15 … … 21 21 22 22 namespace ControlStruct { 23 void translateThrows( std::list< Declaration *> & translationUnit ); 24 /* Replaces all throw & throwResume statements with function calls. 25 * These still need to be resolved, so call this before the reslover. 26 */ 27 28 void translateTries( std::list< Declaration *> & translationUnit ); 29 /* Replaces all try blocks (and their many clauses) with function definitions and calls. 30 * This uses the exception built-ins to produce typed output and should take place after 31 * the resolver. 32 */ 23 void translateEHM( std::list< Declaration *> & translationUnit ); 24 // Converts exception handling structures into their underlying C code. Translation does use the exception 25 // handling header, make sure it is visible wherever translation occurs. 33 26 } 34 27 -
src/main.cc
r0e4df2e r2802824 9 9 // Author : Peter Buhr and Rob Schluntz 10 10 // Created On : Fri May 15 23:12:02 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Tue May 19 12:03:00 202013 // Update Count : 63 411 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Feb 8 08:33:50 2020 13 // Update Count : 633 14 14 // 15 15 … … 312 312 } // if 313 313 314 PASS( "Translate Throws", ControlStruct::translateThrows( translationUnit ) );315 314 PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) ); 316 315 PASS( "Fix Names", CodeGen::fixNames( translationUnit ) ); … … 355 354 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused 356 355 357 PASS( "Translate Tries" , ControlStruct::translateTries( translationUnit ) );356 PASS( "Translate EHM" , ControlStruct::translateEHM( translationUnit ) ); 358 357 359 358 PASS( "Gen Waitfor" , Concurrency::generateWaitFor( translationUnit ) ); -
tests/errors/.expect/completeType.txt
r0e4df2e r2802824 132 132 ?=?: pointer to function 133 133 ... with parameters 134 reference to instance of type _10 8_0_T (not function type)135 instance of type _10 8_0_T (not function type)134 reference to instance of type _104_0_T (not function type) 135 instance of type _104_0_T (not function type) 136 136 ... returning 137 _retval__operator_assign: instance of type _10 8_0_T (not function type)137 _retval__operator_assign: instance of type _104_0_T (not function type) 138 138 ... with attributes: 139 139 Attribute with name: unused -
tests/exceptions/conditional.cfa
r0e4df2e r2802824 56 56 57 57 try { 58 throw exc;58 throw &exc; 59 59 } catch (num_error * error ; 3 == error->virtual_table->code( error )) { 60 60 caught_num_error(3, error); … … 64 64 65 65 try { 66 throwResume exc;66 throwResume &exc; 67 67 } catchResume (num_error * error ; 3 == error->virtual_table->code( error )) { 68 68 caught_num_error(3, error); -
tests/exceptions/data-except.cfa
r0e4df2e r2802824 28 28 29 29 try { 30 throw except;30 throw &except; 31 31 } catch (paired * exc) { 32 32 printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second); … … 37 37 38 38 try { 39 throwResume except;39 throwResume &except; 40 40 } catchResume (paired * exc) { 41 41 printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second); -
tests/exceptions/finally.cfa
r0e4df2e r2802824 12 12 try { 13 13 printf("termination throw\n"); 14 throw exc;14 throw &exc; 15 15 } finally { 16 16 loud_exit a = "termination inner finally"; … … 28 28 try { 29 29 printf("resumption throw\n"); 30 throwResume exc;30 throwResume &exc; 31 31 } finally { 32 32 loud_exit a = "resumption inner finally"; -
tests/exceptions/interact.cfa
r0e4df2e r2802824 10 10 // Resume falls back to terminate. 11 11 try { 12 throwResume (star){};12 throwResume &(star){}; 13 13 } catch (star *) { 14 14 printf("caught as termination\n"); … … 17 17 try { 18 18 loud_region a = "try block with resume throw"; 19 throwResume (star){};19 throwResume &(star){}; 20 20 } catch (star *) { 21 21 printf("caught as termination\n"); … … 29 29 try { 30 30 try { 31 throw (star){};31 throw &(star){}; 32 32 } catchResume (star *) { 33 33 printf("resume catch on terminate\n"); … … 43 43 try { 44 44 try { 45 throwResume (star){};45 throwResume &(star){}; 46 46 } catch (star *) { 47 47 printf("terminate catch on resume\n"); … … 58 58 try { 59 59 try { 60 throw (star){};60 throw &(star){}; 61 61 } catchResume (star *) { 62 62 printf("inner resume catch (error)\n"); … … 64 64 } catch (star * error) { 65 65 printf("termination catch, will resume\n"); 66 throwResume *error;66 throwResume error; 67 67 } 68 68 } catchResume (star *) { … … 75 75 try { 76 76 try { 77 throwResume (star){};77 throwResume &(star){}; 78 78 } catch (star *) { 79 79 printf("inner termination catch\n"); … … 81 81 } catchResume (star * error) { 82 82 printf("resumption catch, will terminate\n"); 83 throw *error;83 throw error; 84 84 } 85 85 } catch (star *) { … … 94 94 try { 95 95 printf("throwing resume moon\n"); 96 throwResume (moon){};96 throwResume &(moon){}; 97 97 } catch (star *) { 98 98 printf("termination catch\n"); 99 99 } 100 100 printf("throwing resume star\n"); 101 throwResume (star){};101 throwResume &(star){}; 102 102 } catchResume (star *) { 103 103 printf("resumption star catch\n"); … … 105 105 } catchResume (moon *) { 106 106 printf("resumption moon catch, will terminate\n"); 107 throw (star){};107 throw &(star){}; 108 108 } 109 109 } catchResume (star *) { -
tests/exceptions/resume.cfa
r0e4df2e r2802824 14 14 loud_exit a = "simple try clause"; 15 15 printf("simple throw\n"); 16 throwResume (zen){};16 throwResume &(zen){}; 17 17 printf("end of try clause\n"); 18 18 } catchResume (zen * error) { … … 24 24 // Throw catch-all test. 25 25 try { 26 throwResume (zen){};26 throwResume &(zen){}; 27 27 } catchResume (exception_t * error) { 28 28 printf("catch-all\n"); … … 33 33 try { 34 34 printf("throwing child exception\n"); 35 throwResume (moment_of){};35 throwResume &(moment_of){}; 36 36 } catchResume (zen *) { 37 37 printf("inner parent match\n"); … … 44 44 try { 45 45 try { 46 throwResume (yin){};46 throwResume &(yin){}; 47 47 } catchResume (zen *) { 48 48 printf("caught yin as zen\n"); … … 60 60 loud_exit a = "rethrow inner try"; 61 61 printf("rethrow inner try\n"); 62 throwResume (zen){};62 throwResume &(zen){}; 63 63 } catchResume (zen *) { 64 64 loud_exit a = "rethrowing catch clause"; … … 75 75 try { 76 76 try { 77 throwResume (yin){};77 throwResume &(yin){}; 78 78 } catchResume (yin *) { 79 79 printf("caught yin, will throw yang\n"); 80 throwResume (yang){};80 throwResume &(yang){}; 81 81 } catchResume (yang *) { 82 82 printf("caught exception from same try\n"); … … 91 91 try { 92 92 printf("throwing first exception\n"); 93 throwResume (yin){};93 throwResume &(yin){}; 94 94 } catchResume (yin *) { 95 95 printf("caught first exception\n"); 96 96 try { 97 97 printf("throwing second exception\n"); 98 throwResume (yang){};98 throwResume &(yang){}; 99 99 } catchResume (yang *) { 100 100 printf("caught second exception\n"); … … 112 112 try { 113 113 try { 114 throwResume (zen){};115 throwResume (zen){};114 throwResume &(zen){}; 115 throwResume &(zen){}; 116 116 } catchResume (zen *) { 117 117 printf("inner catch\n"); 118 118 } 119 throwResume (zen){};119 throwResume &(zen){}; 120 120 } catchResume (zen *) { 121 121 printf("outer catch\n"); -
tests/exceptions/terminate.cfa
r0e4df2e r2802824 14 14 loud_exit a = "simple try clause"; 15 15 printf("simple throw\n"); 16 throw (zen){};16 throw &(zen){}; 17 17 printf("end of try clause\n"); 18 18 } catch (zen * error) { … … 24 24 // Throw catch-all test. 25 25 try { 26 throw (zen){};26 throw &(zen){}; 27 27 } catch (exception_t * error) { 28 28 printf("catch-all\n"); … … 33 33 try { 34 34 printf("throwing child exception\n"); 35 throw (moment_of){};35 throw &(moment_of){}; 36 36 } catch (zen *) { 37 37 printf("inner parent match\n"); … … 44 44 try { 45 45 try { 46 throw (yin){};46 throw &(yin){}; 47 47 } catch (zen *) { 48 48 printf("caught yin as zen\n"); … … 60 60 loud_exit a = "rethrow inner try"; 61 61 printf("rethrow inner try\n"); 62 throw (zen){};62 throw &(zen){}; 63 63 } catch (zen *) { 64 64 loud_exit a = "rethrowing catch clause"; … … 75 75 try { 76 76 try { 77 throw (yin){};77 throw &(yin){}; 78 78 } catch (yin *) { 79 79 printf("caught yin, will throw yang\n"); 80 throw (yang){};80 throw &(yang){}; 81 81 } catch (yang *) { 82 82 printf("caught exception from same try\n"); … … 91 91 try { 92 92 printf("throwing first exception\n"); 93 throw (yin){};93 throw &(yin){}; 94 94 } catch (yin *) { 95 95 printf("caught first exception\n"); 96 96 try { 97 97 printf("throwing second exception\n"); 98 throw (yang){};98 throw &(yang){}; 99 99 } catch (yang *) { 100 100 printf("caught second exception\n"); … … 112 112 try { 113 113 try { 114 throw (zen){};115 throw (zen){};114 throw &(zen){}; 115 throw &(zen){}; 116 116 } catch (zen *) { 117 117 printf("inner catch\n"); 118 118 } 119 throw (zen){};119 throw &(zen){}; 120 120 } catch (zen *) { 121 121 printf("outer catch\n"); -
tests/list/.expect/dlist-insert-remove.txt
r0e4df2e r2802824 1464 1464 0.7 1465 1465 - 1466 1467 ~~~~~~~~~~ End removal tests on Headed List: First ~~~~~~~~~~1468 1469 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1470 Test 16-i. Modifying Freds on MINE1471 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1472 ==== fred by MINE before1473 1.71474 2.71475 3.71476 -1477 1.71478 -1479 3.71480 -1481 3.71482 2.71483 1.71484 -1485 ==== fred by YOURS before1486 1.71487 2.71488 3.71489 -1490 1.71491 -1492 3.71493 -1494 3.71495 2.71496 1.71497 -1498 ==== fred by MINE after1499 2.71500 3.71501 -1502 2.71503 -1504 3.71505 -1506 3.71507 2.71508 -1509 ==== fred by YOURS after1510 1.71511 2.71512 3.71513 -1514 1.71515 -1516 3.71517 -1518 3.71519 2.71520 1.71521 -1522 ==== fred by MINE after1523 1.71524 -1525 1.71526 -1527 -1528 -1529 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1530 Test 16-ii. Modifying Freds on YOURS1531 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1532 ==== fred by MINE before1533 1.71534 2.71535 3.71536 -1537 1.71538 -1539 3.71540 -1541 3.71542 2.71543 1.71544 -1545 ==== fred by YOURS before1546 1.71547 2.71548 3.71549 -1550 1.71551 -1552 3.71553 -1554 3.71555 2.71556 1.71557 -1558 ==== fred by MINE after1559 1.71560 2.71561 3.71562 -1563 1.71564 -1565 3.71566 -1567 3.71568 2.71569 1.71570 -1571 ==== fred by YOURS after1572 2.71573 3.71574 -1575 2.71576 -1577 3.71578 -1579 3.71580 2.71581 -1582 ==== fred by YOURS after1583 1.71584 -1585 1.71586 -1587 -1588 -1589 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1590 Test 16-iii. Modifying Maries1591 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1592 ==== mary before1593 1.71594 2.71595 3.71596 -1597 1.71598 -1599 3.71600 -1601 3.71602 2.71603 1.71604 -1605 ==== mary after1606 2.71607 3.71608 -1609 2.71610 -1611 3.71612 -1613 3.71614 2.71615 -1616 ==== mary after1617 1.71618 -1619 1.71620 -1621 -1622 -1623 1624 ~~~~~~~~~~ End removal tests on Headed List: Last ~~~~~~~~~~1625 1626 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1627 Test 17-i. Modifying Freds on MINE1628 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1629 ==== fred by MINE before1630 1.71631 2.71632 3.71633 -1634 1.71635 -1636 3.71637 -1638 3.71639 2.71640 1.71641 -1642 ==== fred by YOURS before1643 1.71644 2.71645 3.71646 -1647 1.71648 -1649 3.71650 -1651 3.71652 2.71653 1.71654 -1655 ==== fred by MINE after1656 1.71657 2.71658 -1659 1.71660 -1661 2.71662 -1663 2.71664 1.71665 -1666 ==== fred by YOURS after1667 1.71668 2.71669 3.71670 -1671 1.71672 -1673 3.71674 -1675 3.71676 2.71677 1.71678 -1679 ==== fred by MINE after1680 3.71681 -1682 3.71683 -1684 -1685 -1686 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1687 Test 17-ii. Modifying Freds on YOURS1688 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1689 ==== fred by MINE before1690 1.71691 2.71692 3.71693 -1694 1.71695 -1696 3.71697 -1698 3.71699 2.71700 1.71701 -1702 ==== fred by YOURS before1703 1.71704 2.71705 3.71706 -1707 1.71708 -1709 3.71710 -1711 3.71712 2.71713 1.71714 -1715 ==== fred by MINE after1716 1.71717 2.71718 3.71719 -1720 1.71721 -1722 3.71723 -1724 3.71725 2.71726 1.71727 -1728 ==== fred by YOURS after1729 1.71730 2.71731 -1732 1.71733 -1734 2.71735 -1736 2.71737 1.71738 -1739 ==== fred by YOURS after1740 3.71741 -1742 3.71743 -1744 -1745 -1746 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1747 Test 17-iii. Modifying Maries1748 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1749 ==== mary before1750 1.71751 2.71752 3.71753 -1754 1.71755 -1756 3.71757 -1758 3.71759 2.71760 1.71761 -1762 ==== mary after1763 1.71764 2.71765 -1766 1.71767 -1768 2.71769 -1770 2.71771 1.71772 -1773 ==== mary after1774 3.71775 -1776 3.71777 -1778 -1779 - -
tests/list/dlist-insert-remove.cfa
r0e4df2e r2802824 1187 1187 //////////////////////////////////////////////////////////// 1188 1188 // 1189 // Section 4f1190 //1191 // Test cases of pop_first, pop_last1192 //1193 // Example of call-side user code1194 //1195 ////////////////////////////////////////////////////////////1196 1197 // These cases assume element removal at first-last is correct1198 1199 void test__pop_first__fred_mine() {1200 1201 fred f1 = {1.7};1202 fred f2 = {2.7};1203 fred f3 = {3.7};1204 1205 dlist(fred_in_mine, fred) flm;1206 insert_last(flm, f1);1207 insert_last(flm, f2);1208 insert_last(flm, f3);1209 1210 dlist(fred_in_yours, fred) fly;1211 insert_last(fly, f1);1212 insert_last(fly, f2);1213 insert_last(fly, f3);1214 1215 printMyFreddies(flm`first, flm`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.71216 printYourFreddies(fly`first, fly`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.71217 1218 verify(validate(fly));1219 verify(validate(flm));1220 1221 fred & popped = pop_first(flm);1222 1223 verify(validate(fly));1224 verify(validate(flm));1225 1226 printMyFreddies(flm`first, flm`last, 0); // 2.7, 3.7; 2.7; 3.7; 3.7, 2.7 (modified)1227 printYourFreddies(fly`first, fly`last, 0); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.7 (unmodified)1228 1229 // observe f1 is now solo in mine; in yours, it was just traversed1230 printMyFreddies(f1, *0p, 0); // 1.7; 1.7; ;1231 1232 assert( &popped == & f1 );1233 }1234 1235 void test__pop_first__fred_yours() {1236 1237 fred f1 = {1.7};1238 fred f2 = {2.7};1239 fred f3 = {3.7};1240 1241 dlist(fred_in_mine, fred) flm;1242 insert_last(flm, f1);1243 insert_last(flm, f2);1244 insert_last(flm, f3);1245 1246 dlist(fred_in_yours, fred) fly;1247 insert_last(fly, f1);1248 insert_last(fly, f2);1249 insert_last(fly, f3);1250 1251 printMyFreddies(flm`first, flm`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.71252 printYourFreddies(fly`first, fly`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.71253 1254 verify(validate(fly));1255 verify(validate(flm));1256 1257 fred & popped = pop_first(fly);1258 1259 verify(validate(fly));1260 verify(validate(flm));1261 1262 printMyFreddies(flm`first, flm`last, 0); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.7 (unmodified)1263 printYourFreddies(fly`first, fly`last, 0); // 2.7, 3.7; 2.7; 3.7; 3.7, 2.7 (modified)1264 1265 // observe f1 is now solo in yours; in mine, it was just traversed1266 printYourFreddies(f1, *0p, 0); // 1.7; 1.7; ;1267 1268 assert( &popped == &f1 );1269 }1270 1271 void test__pop_first__maries() {1272 1273 mary m1 = {1.7};1274 mary m2 = {2.7};1275 mary m3 = {3.7};1276 1277 dlist(mary, mary) ml;1278 insert_last(ml, m1);1279 insert_last(ml, m2);1280 insert_last(ml, m3);1281 1282 printMariatheotokos(ml`first, ml`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.71283 1284 verify(validate(ml));1285 1286 mary & popped = pop_first(ml);1287 1288 verify(validate(ml));1289 1290 printMariatheotokos(ml`first, ml`last, 0); // 2.7, 3.7; 2.7; 3.7; 3.7, 2.7 (modified)1291 1292 // observe m1 is now solo1293 printMariatheotokos(m1, *0p, 0); // 1.7; 1.7; ;1294 1295 assert( &popped == &m1 );1296 }1297 1298 void test__pop_last__fred_mine() {1299 1300 fred f1 = {1.7};1301 fred f2 = {2.7};1302 fred f3 = {3.7};1303 1304 dlist(fred_in_mine, fred) flm;1305 insert_last(flm, f1);1306 insert_last(flm, f2);1307 insert_last(flm, f3);1308 1309 dlist(fred_in_yours, fred) fly;1310 insert_last(fly, f1);1311 insert_last(fly, f2);1312 insert_last(fly, f3);1313 1314 printMyFreddies(flm`first, flm`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.71315 printYourFreddies(fly`first, fly`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.71316 1317 verify(validate(fly));1318 verify(validate(flm));1319 1320 fred & popped = pop_last(flm);1321 1322 verify(validate(fly));1323 verify(validate(flm));1324 1325 printMyFreddies(flm`first, flm`last, 0); // 1.7, 2.7; 1.7; 2.7; 2.7, 1.7 (modified)1326 printYourFreddies(fly`first, fly`last, 0); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.7 (unmodified)1327 1328 // observe f3 is now solo in mine; in yours, it was just traversed1329 printMyFreddies(f3, *0p, 0); // 3.7; 3.7; ;1330 1331 assert( &popped == & f3 );1332 }1333 1334 void test__pop_last__fred_yours() {1335 1336 fred f1 = {1.7};1337 fred f2 = {2.7};1338 fred f3 = {3.7};1339 1340 dlist(fred_in_mine, fred) flm;1341 insert_last(flm, f1);1342 insert_last(flm, f2);1343 insert_last(flm, f3);1344 1345 dlist(fred_in_yours, fred) fly;1346 insert_last(fly, f1);1347 insert_last(fly, f2);1348 insert_last(fly, f3);1349 1350 printMyFreddies(flm`first, flm`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.71351 printYourFreddies(fly`first, fly`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.71352 1353 verify(validate(fly));1354 verify(validate(flm));1355 1356 fred & popped = pop_last(fly);1357 1358 verify(validate(fly));1359 verify(validate(flm));1360 1361 printMyFreddies(flm`first, flm`last, 0); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.7 (unmodified)1362 printYourFreddies(fly`first, fly`last, 0); // 1.7, 2.7; 1.7; 2.7; 2.7, 1.7 (modified)1363 1364 // observe f3 is now solo in yours; in mine, it was just traversed1365 printYourFreddies(f3, *0p, 0); // 3.7; 3.7; ;1366 1367 assert( &popped == & f3 );1368 }1369 1370 void test__pop_last__maries() {1371 1372 mary m1 = {1.7};1373 mary m2 = {2.7};1374 mary m3 = {3.7};1375 1376 dlist(mary, mary) ml;1377 insert_last(ml, m1);1378 insert_last(ml, m2);1379 insert_last(ml, m3);1380 1381 printMariatheotokos(ml`first, ml`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.71382 1383 verify(validate(ml));1384 1385 mary & popped = pop_last(ml);1386 1387 verify(validate(ml));1388 1389 printMariatheotokos(ml`first, ml`last, 0); // 1.7, 1.7; 1.7; 2.7; 2.7, 1.7 (modified)1390 1391 // observe m1 is now solo1392 printMariatheotokos(m3, *0p, 0); // 3.7; 3.7; ;1393 1394 assert( &popped == &m3 );1395 }1396 1397 ////////////////////////////////////////////////////////////1398 //1399 1189 // Section 5 1400 1190 // … … 1632 1422 test__remove_of_sole__mary(); 1633 1423 1634 sout | "";1635 sout | "~~~~~~~~~~ End removal tests on Headed List: First ~~~~~~~~~~";1636 sout | "";1637 1638 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";1639 sout | "Test 16-i. Modifying Freds on MINE";1640 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";1641 test__pop_first__fred_mine();1642 1643 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";1644 sout | "Test 16-ii. Modifying Freds on YOURS";1645 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";1646 test__pop_first__fred_yours();1647 1648 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";1649 sout | "Test 16-iii. Modifying Maries";1650 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";1651 test__pop_first__maries();1652 1653 sout | "";1654 sout | "~~~~~~~~~~ End removal tests on Headed List: Last ~~~~~~~~~~";1655 sout | "";1656 1657 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";1658 sout | "Test 17-i. Modifying Freds on MINE";1659 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";1660 test__pop_last__fred_mine();1661 1662 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";1663 sout | "Test 17-ii. Modifying Freds on YOURS";1664 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";1665 test__pop_last__fred_yours();1666 1667 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";1668 sout | "Test 17-iii. Modifying Maries";1669 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";1670 test__pop_last__maries();1671 1672 1424 return 0; 1673 1425 }
Note:
See TracChangeset
for help on using the changeset viewer.