Changeset 0e4df2e
- Timestamp:
- May 22, 2020, 11:49:29 AM (5 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 95cb63b
- Parents:
- 2802824 (diff), 99fea48 (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. - Files:
-
- 3 added
- 24 edited
Legend:
- Unmodified
- Added
- Removed
-
driver/cfa.cc
r2802824 r0e4df2e 10 10 // Created On : Tue Aug 20 13:44:49 2002 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jan 31 16:48:03202013 // Update Count : 42 112 // Last Modified On : Mon May 18 13:26:26 2020 13 // Update Count : 424 14 14 // 15 15 … … 301 301 } // for 302 302 303 #ifdef __x86_64__304 args[nargs++] = "-mcx16"; // allow double-wide CAA305 #endif // __x86_64__306 307 303 #ifdef __DEBUG_H__ 308 304 cerr << "args:"; … … 419 415 args[nargs++] = "-lcfa"; 420 416 args[nargs++] = "-Wl,--pop-state"; 417 #ifdef __x86_64__ 418 args[nargs++] = "-mcx16"; // allow double-wide CAS 419 args[nargs++] = "-latomic"; 420 #endif // __x86_64__ 421 421 args[nargs++] = "-pthread"; 422 422 args[nargs++] = "-ldl"; -
libcfa/src/Makefile.am
r2802824 r0e4df2e 11 11 ## Created On : Sun May 31 08:54:01 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Mon Mar 16 18:07:59202014 ## Update Count : 24 213 ## Last Modified On : Sun May 17 21:10:26 2020 14 ## Update Count : 243 15 15 ############################################################################### 16 16 … … 39 39 #---------------------------------------------------------------------------------------------------------------- 40 40 if BUILDLIB 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 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 42 43 headers = fstream.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa time.hfa stdlib.hfa common.hfa \ 43 containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa44 containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/stackLockFree.hfa containers/vector.hfa 44 45 45 46 libsrc = startup.cfa interpose.cfa bits/debug.cfa assert.cfa exception.c virtual.c heap.cfa ${headers:.hfa=.cfa} -
libcfa/src/Makefile.in
r2802824 r0e4df2e 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 bits/align.hfa bits/containers.hfa bits/defs.hfa \243 clock.hfa 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 bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa containers/list.hfa 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 468 470 @BUILDLIB_FALSE@headers = 469 471 @BUILDLIB_TRUE@headers = fstream.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa time.hfa stdlib.hfa common.hfa \ 470 @BUILDLIB_TRUE@ 472 @BUILDLIB_TRUE@ containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa 471 473 472 474 @BUILDLIB_FALSE@libsrc = -
libcfa/src/concurrency/io.cfa
r2802824 r0e4df2e 124 124 125 125 // Like head/tail but not seen by the kernel 126 volatile uint32_t alloc;127 126 volatile uint32_t * ready; 128 127 uint32_t ready_cnt; … … 141 140 struct { 142 141 struct { 143 volatile unsigned long long int val; 142 volatile unsigned long long int rdy; 143 volatile unsigned long long int csm; 144 volatile unsigned long long int avl; 144 145 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; 152 157 } stats; 153 158 #endif … … 279 284 sq.dropped = ( uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped); 280 285 sq.array = ( uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.array); 281 sq.alloc = *sq.tail; 286 287 { 288 const uint32_t num = *sq.num; 289 for( i; num ) { 290 sq.sqes[i].user_data = 0ul64; 291 } 292 } 282 293 283 294 if( io_flags & CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS ) { … … 322 333 // Initialize statistics 323 334 #if !defined(__CFA_NO_STATISTICS__) 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; 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; 327 339 this.io->submit_q.stats.look_avg.val = 0; 328 340 this.io->submit_q.stats.look_avg.cnt = 0; 329 341 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; 330 345 this.io->completion_q.stats.completed_avg.val = 0; 331 346 this.io->completion_q.stats.completed_avg.slow_cnt = 0; … … 384 399 this.ready_queue.head = 1p; 385 400 thrd.next = 0p; 401 __cfaabi_dbg_debug_do( thrd.unpark_stale = true ); 386 402 387 403 // Fixup the thread state … … 426 442 if(this.print_stats) { 427 443 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 428 448 double lavgv = 0; 429 449 double lavgb = 0; … … 433 453 } 434 454 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 435 462 __cfaabi_bits_print_safe( STDOUT_FILENO, 436 463 "----- I/O uRing Stats -----\n" 437 464 "- total submit calls : %'15llu\n" 438 "- avg submit : %'18.2lf\n" 439 "- pre-submit block %% : %'18.2lf\n" 465 "- avg ready entries : %'18.2lf\n" 466 "- avg submitted entries : %'18.2lf\n" 467 "- avg available entries : %'18.2lf\n" 440 468 "- total ready search : %'15llu\n" 441 469 "- avg ready search len : %'18.2lf\n" 442 470 "- 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" 443 474 "- total wait calls : %'15llu (%'llu slow, %'llu fast)\n" 444 475 "- avg completion/wait : %'18.2lf\n", 445 476 submit_avg.cnt, 446 ((double)submit_avg.val) / submit_avg.cnt, 447 (100.0 * submit_avg.block) / submit_avg.cnt, 477 avgrdy, 478 avgcsm, 479 avgavl, 448 480 look_avg.cnt, 449 481 lavgv, 450 482 lavgb, 483 alloc_avg.cnt, 484 aavgv, 485 aavgb, 451 486 completed_avg.slow_cnt + completed_avg.fast_cnt, 452 487 completed_avg.slow_cnt, completed_avg.fast_cnt, … … 494 529 495 530 // If the poller thread also submits, then we need to aggregate the submissions which are ready 496 uint32_t * tail =ring.submit_q.tail;531 uint32_t tail = *ring.submit_q.tail; 497 532 const uint32_t mask = *ring.submit_q.mask; 498 533 … … 506 541 507 542 // If we got a real submission, append it to the list 508 ring.submit_q.array[ ( (*tail)+ to_submit) & mask ] = idx & mask;543 ring.submit_q.array[ (tail + to_submit) & mask ] = idx & mask; 509 544 to_submit++; 510 545 } 511 546 512 547 // Increment the tail based on how many we are ready to submit 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 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; 522 553 int ret = syscall( __NR_io_uring_enter, ring.fd, to_submit, waitcnt, IORING_ENTER_GETEVENTS, mask, _NSIG / 8); 523 554 if( ret < 0 ) { … … 531 562 } 532 563 564 verify( (shead + ret) == *ring.submit_q.head ); 565 566 // Release the consumed SQEs 567 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 statistics 579 #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 #endif 585 533 586 // Drain the queue 534 587 unsigned head = *ring.completion_q.head; 535 unsigned tail = __atomic_load_n(ring.completion_q.tail, __ATOMIC_ACQUIRE); 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 ); 536 593 537 594 // Nothing was new return 0 … … 542 599 uint32_t count = tail - head; 543 600 for(i; count) { 544 unsigned idx = (head + i) & (*ring.completion_q.mask);601 unsigned idx = (head + i) & mask; 545 602 struct io_uring_cqe & cqe = ring.completion_q.cqes[idx]; 546 603 … … 556 613 557 614 // Allow new submissions to happen 558 V(ring.submit, count);615 // V(ring.submit, count); 559 616 560 617 // Mark to the kernel that the cqe has been seen 561 618 // 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 ); 562 620 __atomic_fetch_add( ring.completion_q.head, count, __ATOMIC_RELAXED ); 563 621 … … 710 768 // 711 769 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]; 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 } 727 810 } 728 811 … … 742 825 __attribute((unused)) int len = 0; 743 826 __attribute((unused)) int block = 0; 744 uint32_t expected = -1ul32;745 827 uint32_t ready_mask = ring.submit_q.ready_cnt - 1; 746 828 uint32_t off = __tls_rand(); … … 748 830 for(i; ring.submit_q.ready_cnt) { 749 831 uint32_t ii = (i + off) & ready_mask; 832 uint32_t expected = -1ul32; 750 833 if( __atomic_compare_exchange_n( &ring.submit_q.ready[ii], &expected, idx, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) { 751 834 break LOOKING; 752 835 } 836 verify(expected != idx); 753 837 754 838 len ++; … … 792 876 // update statistics 793 877 #if !defined(__CFA_NO_STATISTICS__) 794 ring.submit_q.stats.submit_avg. val+= 1;878 ring.submit_q.stats.submit_avg.csm += 1; 795 879 ring.submit_q.stats.submit_avg.cnt += 1; 796 880 #endif … … 831 915 832 916 #define __submit_prelude \ 833 struct __io_data & ring = *active_cluster()->io; \ 917 io_user_data data = { 0, active_thread() }; \ 918 struct __io_data & ring = *data.thrd->curr_cluster->io; \ 834 919 struct io_uring_sqe * sqe; \ 835 920 uint32_t idx; \ 836 [sqe, idx] = __submit_alloc( ring );921 [sqe, idx] = __submit_alloc( ring, (uint64_t)&data ); 837 922 838 923 #define __submit_wait \ 839 io_user_data data = { 0, active_thread() }; \840 924 /*__cfaabi_bits_print_safe( STDERR_FILENO, "Preparing user data %p for %p\n", &data, data.thrd );*/ \ 841 sqe->user_data = (uint64_t)&data; \925 verify( sqe->user_data == (uint64_t)&data ); \ 842 926 __submit( ring, idx ); \ 843 927 park( __cfaabi_dbg_ctx ); \ -
libcfa/src/concurrency/kernel.cfa
r2802824 r0e4df2e 648 648 649 649 // record activity 650 __cfaabi_dbg_debug_do( char * old_caller = thrd->unpark_caller; ) 650 651 __cfaabi_dbg_record_thrd( *thrd, false, caller ); 651 652 -
libcfa/src/containers/list.hfa
r2802824 r0e4df2e 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 303 340 } 304 341 -
libcfa/src/exception.c
r2802824 r0e4df2e 10 10 // Created On : Mon Jun 26 15:13:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T ue Apr 14 12:01:00 202013 // Update Count : 1812 // Last Modified On : Thr May 21 12:18:00 2020 13 // Update Count : 20 14 14 // 15 15 … … 80 80 } 81 81 82 void __cfaehm_throw_resume(exception_t * except ) {82 void __cfaehm_throw_resume(exception_t * except, void (*defaultHandler)(exception_t *)) { 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. 98 99 __cfadbg_print_safe(exception, "Unhandled exception\n"); 99 100 // Fall back to termination: 101 __cfaehm_throw_terminate(except); 102 // TODO: Default handler for resumption. 100 defaultHandler(except); 103 101 } 104 102 … … 223 221 224 222 // Cancel the current stack, prefroming approprate clean-up and messaging. 225 static __attribute__((noreturn)) void __cfaehm_cancel_stack( 226 exception_t * exception ) { 223 void __cfaehm_cancel_stack( exception_t * exception ) { 227 224 // TODO: Detect current stack and pick a particular stop-function. 228 225 _Unwind_Reason_Code ret; … … 240 237 } 241 238 239 static void __cfaehm_cleanup_default( exception_t ** except ) { 240 __cfaehm_delete_exception( *except ); 241 *except = NULL; 242 } 243 242 244 // The exception that is being thrown must already be stored. 243 static __attribute__((noreturn)) void __cfaehm_begin_unwind(void) { 244 if ( ! this_exception_context()->current_exception ) { 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 ) { 245 249 printf("UNWIND ERROR missing exception in begin unwind\n"); 246 250 abort(); … … 248 252 249 253 // Call stdlibc to raise the exception 250 _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage ); 254 __cfadbg_print_safe(exception, "Begin unwinding (storage &p, context %p)\n", storage, context); 255 _Unwind_Reason_Code ret = _Unwind_RaiseException( storage ); 251 256 252 257 // If we reach here it means something happened. For resumption to work we need to find a way … … 257 262 // the whole stack. 258 263 264 // 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 259 270 // 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 267 // We did not simply reach the end of the stack without finding a handler. This is an error. 268 printf("UNWIND ERROR %d after raise exception\n", ret); 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 *) ) { 279 __cfadbg_print_safe(exception, "Throwing termination exception\n"); 280 281 __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; 269 288 abort(); 270 }271 272 void __cfaehm_throw_terminate( exception_t * val ) {273 __cfadbg_print_safe(exception, "Throwing termination exception\n");274 275 __cfaehm_allocate_exception( val );276 __cfaehm_begin_unwind();277 289 } 278 290 … … 280 292 __cfadbg_print_safe(exception, "Rethrowing termination exception\n"); 281 293 282 __cfaehm_begin_unwind(); 294 __cfaehm_begin_unwind( __cfaehm_rethrow_adapter ); 295 abort(); 283 296 } 284 297 -
libcfa/src/exception.h
r2802824 r0e4df2e 10 10 // Created On : Mon Jun 26 15:11:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Mar 27 10:16:00 202013 // Update Count : 912 // Last Modified On : Tue May 19 14:17:00 2020 13 // Update Count : 10 14 14 // 15 15 … … 38 38 39 39 40 void __cfaehm_cancel_stack(exception_t * except) __attribute__((noreturn)); 41 40 42 // Used in throw statement translation. 41 void __cfaehm_throw_terminate(exception_t * except ) __attribute__((noreturn));43 void __cfaehm_throw_terminate(exception_t * except, void (*)(exception_t *)); 42 44 void __cfaehm_rethrow_terminate() __attribute__((noreturn)); 43 void __cfaehm_throw_resume(exception_t * except );45 void __cfaehm_throw_resume(exception_t * except, void (*)(exception_t *)); 44 46 45 47 // Function catches termination exceptions. … … 70 72 #ifdef __cforall 71 73 } 74 75 // Not all the built-ins can be expressed in C. These can't be 76 // 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 *))defaultTerminationHandler 99 ); 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 *))defaultResumptionHandler 107 ); 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 72 125 #endif -
libcfa/src/exception.hfa
r2802824 r0e4df2e 10 10 // Created On : Thu Apr 7 10:25:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hu Apr 7 10:25:00 202013 // Update Count : 012 // Last Modified On : Tue May 19 14:17:00 2020 13 // Update Count : 2 14 14 // 15 15 … … 69 69 #define _VTABLE_DECLARATION(exception_name, parent_name, ...) \ 70 70 struct exception_name; \ 71 void mark_exception(exception_name *); \ 71 72 VTABLE_TYPE(exception_name); \ 72 73 extern VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name); \ … … 85 86 #define VTABLE_INSTANCE(...) _EXC_DISPATCH(_VTABLE_INSTANCE, __VA_ARGS__) 86 87 #define _VTABLE_INSTANCE(exception_name, parent_name, ...) \ 88 void mark_exception(exception_name *) {} \ 87 89 void _GLUE2(exception_name,_copy)(exception_name * this, exception_name * other) { \ 88 90 *this = *other; \ -
libcfa/src/executor.cfa
r2802824 r0e4df2e 4 4 // buffer. 5 5 6 #include < bits/containers.hfa>6 #include <containers/list.hfa> 7 7 #include <thread.hfa> 8 8 #include <stdio.h> 9 9 10 forall( dtype T )11 monitor Buffer { // unbounded buffer12 __queue_t( T ) queue; // unbounded list of work requests13 condition delay;14 }; // Buffer15 forall( dtype T | is_node(T) ) {16 void insert( Buffer( T ) & mutex buf, T * elem ) with(buf) {17 append( queue, elem ); // insert element into buffer18 signal( delay ); // restart19 } // insert20 21 T * remove( Buffer( T ) & mutex buf ) with(buf) {22 if ( queue.head != 0 ) wait( delay ); // no request to process ? => wait23 // return pop_head( queue );24 } // remove25 } // distribution26 27 10 struct WRequest { // client request, no return 28 11 void (* action)( void ); 29 WRequest * next; // intrusive queue field12 DLISTED_MGD_IMPL_IN(WRequest) 30 13 }; // WRequest 14 DLISTED_MGD_IMPL_OUT(WRequest) 31 15 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; } 16 void ?{}( WRequest & req ) with(req) { action = 0; } 17 void ?{}( WRequest & req, void (* action)( void ) ) with(req) { req.action = action; } 35 18 bool stop( WRequest & req ) { return req.action == 0; } 36 19 void doit( WRequest & req ) { req.action(); } 20 21 monitor WRBuffer { // unbounded buffer 22 dlist( WRequest, WRequest ) queue; // unbounded list of work requests 23 condition delay; 24 }; // WRBuffer 25 26 void insert( WRBuffer & mutex buf, WRequest * elem ) with(buf) { 27 insert_last( queue, *elem ); // insert element into buffer 28 signal( delay ); // restart 29 } // insert 30 31 WRequest * remove( WRBuffer & mutex buf ) with(buf) { 32 if ( queue`is_empty ) wait( delay ); // no request to process ? => wait 33 return & pop_first( queue ); 34 } // remove 37 35 38 36 // Each worker has its own work buffer to reduce contention between client and server. Hence, work requests arrive and … … 40 38 41 39 thread Worker { 42 Buffer( WRequest )* requests;40 WRBuffer * requests; 43 41 unsigned int start, range; 44 42 }; // Worker … … 54 52 } // Worker::main 55 53 56 void ?{}( Worker & worker, cluster * wc, Buffer( WRequest )* requests, unsigned int start, unsigned int range ) {54 void ?{}( Worker & worker, cluster * wc, WRBuffer * requests, unsigned int start, unsigned int range ) { 57 55 (*get_thread(worker)){ *wc }; // create on given cluster 58 56 worker.[requests, start, range] = [requests, start, range]; … … 62 60 cluster * cluster; // if workers execute on separate cluster 63 61 processor ** processors; // array of virtual processors adding parallelism for workers 64 Buffer( WRequest ) * requests;// list of work requests62 WRBuffer * requests; // list of work requests 65 63 Worker ** workers; // array of workers executing work requests 66 64 unsigned int nprocessors, nworkers, nmailboxes; // number of mailboxes/workers/processor tasks … … 79 77 cluster = sepClus ? new( "Executor" ) : active_cluster(); 80 78 processors = (processor **)anew( nprocessors ); 81 requests = anew( nmailboxes );79 requests = (WRBuffer *)anew( nmailboxes ); 82 80 workers = (Worker **)anew( nworkers ); 83 81 … … 141 139 for ( i; 3000 ) { 142 140 send( exector, workie ); 143 if ( i % 100 ) yield(); 141 if ( i % 100 == 0 ) { 142 // fprintf( stderr, "%d\n", i ); 143 yield(); 144 } 144 145 } // for 145 146 } -
libcfa/src/heap.cfa
r2802824 r0e4df2e 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed May 6 17:29:26202013 // Update Count : 7 2712 // Last Modified On : Sun May 17 20:58:17 2020 13 // Update Count : 762 14 14 // 15 15 … … 128 128 #define LOCKFREE 1 129 129 #define BUCKETLOCK SPINLOCK 130 #if BUCKETLOCK == LOCKFREE 131 #include <uStackLF.h> 130 #if BUCKETLOCK == SPINLOCK 131 #elif BUCKETLOCK == LOCKFREE 132 #include <stackLockFree.hfa> 133 #else 134 #error undefined lock type for bucket lock 132 135 #endif // LOCKFREE 133 136 … … 137 140 138 141 struct HeapManager { 139 // struct FreeHeader; // forward declaration140 141 142 struct Storage { 142 143 struct Header { // header … … 146 147 struct { // 4-byte word => 8-byte header, 8-byte word => 16-byte header 147 148 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4 148 uint 32_t padding; // unused, force home/blocksize to overlay alignment in fake header149 uint64_t padding; // unused, force home/blocksize to overlay alignment in fake header 149 150 #endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4 150 151 151 152 union { 152 //FreeHeader * home; // allocated block points back to home locations (must overlay alignment)153 // FreeHeader * home; // allocated block points back to home locations (must overlay alignment) 153 154 // 2nd low-order bit => zero filled 154 155 void * home; // allocated block points back to home locations (must overlay alignment) 155 156 size_t blockSize; // size for munmap (must overlay alignment) 156 #if BUCK LOCK == SPINLOCK157 #if BUCKETLOCK == SPINLOCK 157 158 Storage * next; // freed block points next freed block of same size 158 159 #endif // SPINLOCK 159 160 }; 161 size_t size; // allocation size in bytes 160 162 161 163 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4 162 uint 32_t padding; // unused, force home/blocksize to overlay alignment in fake header164 uint64_t padding; // unused, force home/blocksize to overlay alignment in fake header 163 165 #endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4 164 166 }; 165 // future code 166 #if BUCKLOCK == LOCKFREE 167 Stack<Storage>::Link next; // freed block points next freed block of same size (double-wide) 167 #if BUCKETLOCK == LOCKFREE 168 Link(Storage) next; // freed block points next freed block of same size (double-wide) 168 169 #endif // LOCKFREE 169 170 }; 170 171 } real; // RealHeader 172 171 173 struct FakeHeader { 172 174 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 173 // 1st low-order bit => fake header & alignment 174 uint32_t alignment; 175 uint32_t alignment; // 1st low-order bit => fake header & alignment 175 176 #endif // __ORDER_LITTLE_ENDIAN__ 176 177 … … 182 183 } fake; // FakeHeader 183 184 } kind; // Kind 184 size_t size; // allocation size in bytes185 185 } header; // Header 186 186 char pad[libAlign() - sizeof( Header )]; … … 191 191 192 192 struct FreeHeader { 193 #if BUCK LOCK == SPINLOCK193 #if BUCKETLOCK == SPINLOCK 194 194 __spinlock_t lock; // must be first field for alignment 195 195 Storage * freeList; 196 #elif BUCKLOCK == LOCKFREE197 // future code198 StackLF<Storage> freeList;199 196 #else 200 #error undefined lock type for bucket lock201 #endif // SPINLOCK197 StackLF(Storage) freeList; 198 #endif // BUCKETLOCK 202 199 size_t blockSize; // size of allocations on this list 203 200 }; // FreeHeader … … 211 208 size_t heapRemaining; // amount of storage not allocated in the current chunk 212 209 }; // HeapManager 210 211 #if BUCKETLOCK == LOCKFREE 212 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 // LOCKFREE 213 216 214 217 static inline size_t getKey( const HeapManager.FreeHeader & freeheader ) { return freeheader.blockSize; } … … 251 254 static bool heapBoot = 0; // detect recursion during boot 252 255 #endif // __CFA_DEBUG__ 256 257 // The constructor for heapManager is called explicitly in memory_startup. 253 258 static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing 254 259 … … 354 359 355 360 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 // } // noMemory361 362 363 361 // thunk problem 364 362 size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) { … … 406 404 407 405 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 // } // noMemory 411 412 408 413 static inline void checkAlign( size_t alignment ) { 409 414 if ( alignment < libAlign() || ! libPow2( alignment ) ) { … … 433 438 434 439 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 ) { 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 ) { 436 442 header = headerAddr( addr ); 437 443 … … 465 471 466 472 467 static inline void * extend( size_t size ) with 473 static inline void * extend( size_t size ) with( heapManager ) { 468 474 lock( extlock __cfaabi_dbg_ctx2 ); 469 475 ptrdiff_t rem = heapRemaining - size; … … 496 502 497 503 498 static inline void * doMalloc( size_t size ) with 504 static inline void * doMalloc( size_t size ) with( heapManager ) { 499 505 HeapManager.Storage * block; // pointer to new block of storage 500 506 … … 529 535 // Spin until the lock is acquired for this particular size of block. 530 536 531 #if defined( SPINLOCK )537 #if BUCKETLOCK == SPINLOCK 532 538 lock( freeElem->lock __cfaabi_dbg_ctx2 ); 533 539 block = freeElem->freeList; // remove node from stack 534 540 #else 535 block = freeElem->freeList.pop();536 #endif // SPINLOCK541 block = pop( freeElem->freeList ); 542 #endif // BUCKETLOCK 537 543 if ( unlikely( block == 0p ) ) { // no free block ? 538 #if defined( SPINLOCK )544 #if BUCKETLOCK == SPINLOCK 539 545 unlock( freeElem->lock ); 540 #endif // SPINLOCK546 #endif // BUCKETLOCK 541 547 542 548 // Freelist for that size was empty, so carve it out of the heap if there's enough left, or get some more … … 544 550 545 551 block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call 546 547 #if defined( SPINLOCK )552 if ( unlikely( block == 0p ) ) return 0p; 553 #if BUCKETLOCK == SPINLOCK 548 554 } else { 549 555 freeElem->freeList = block->header.kind.real.next; 550 556 unlock( freeElem->lock ); 551 #endif // SPINLOCK557 #endif // BUCKETLOCK 552 558 } // if 553 559 … … 572 578 } // if 573 579 574 block->header. size = size;// store allocation size580 block->header.kind.real.size = size; // store allocation size 575 581 void * addr = &(block->data); // adjust off header to user bytes 576 582 … … 591 597 592 598 593 static inline void doFree( void * addr ) with 599 static inline void doFree( void * addr ) with( heapManager ) { 594 600 #ifdef __CFA_DEBUG__ 595 601 if ( unlikely( heapManager.heapBegin == 0p ) ) { … … 623 629 free_storage += size; 624 630 #endif // __STATISTICS__ 625 #if defined( SPINLOCK )631 #if BUCKETLOCK == SPINLOCK 626 632 lock( freeElem->lock __cfaabi_dbg_ctx2 ); // acquire spin lock 627 633 header->kind.real.next = freeElem->freeList; // push on stack … … 629 635 unlock( freeElem->lock ); // release spin lock 630 636 #else 631 freeElem->freeList.push(*(HeapManager.Storage *)header );632 #endif // SPINLOCK637 push( freeElem->freeList, *(HeapManager.Storage *)header ); 638 #endif // BUCKETLOCK 633 639 } // if 634 640 … … 645 651 646 652 647 size_t prtFree( HeapManager & manager ) with 653 size_t prtFree( HeapManager & manager ) with( manager ) { 648 654 size_t total = 0; 649 655 #ifdef __STATISTICS__ … … 657 663 #endif // __STATISTICS__ 658 664 659 #if defined( SPINLOCK )665 #if BUCKETLOCK == SPINLOCK 660 666 for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) { 661 667 #else 662 for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0p; p = p->header.kind.real.next.top ) { 663 #endif // SPINLOCK 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 664 672 total += size; 665 673 #ifdef __STATISTICS__ … … 681 689 682 690 683 static void ?{}( HeapManager & manager ) with 691 static void ?{}( HeapManager & manager ) with( manager ) { 684 692 pageSize = sysconf( _SC_PAGESIZE ); 685 693 … … 1095 1103 header = realHeader( header ); // backup from fake to real header 1096 1104 } // if 1097 return header-> size;1105 return header->kind.real.size; 1098 1106 } // malloc_size 1099 1107 … … 1105 1113 header = realHeader( header ); // backup from fake to real header 1106 1114 } // if 1107 size_t ret = header-> size;1108 header-> size = size;1115 size_t ret = header->kind.real.size; 1116 header->kind.real.size = size; 1109 1117 return ret; 1110 1118 } // $malloc_size_set -
libcfa/src/stdlib.hfa
r2802824 r0e4df2e 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Apr 16 22:44:05202013 // Update Count : 43 212 // Last Modified On : Wed May 13 17:23:51 2020 13 // Update Count : 435 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 heap 26 void * resize( void * oaddr, size_t size ); // CFA heap 25 27 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 30 size_t malloc_size( void * addr ); // CFA heap 26 31 size_t malloc_usable_size( void * ptr ); // malloc.h 27 size_t malloc_size( void * addr ); // CFA heap28 void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ); // CFA heap29 32 void * memset( void * dest, int fill, size_t size ); // string.h 30 33 void * memcpy( void * dest, const void * src, size_t size ); // string.h 31 void * resize( void * oaddr, size_t size ); // CFA heap32 34 } // extern "C" 33 35 … … 52 54 } // malloc 53 55 56 T * aalloc( size_t dim ) { 57 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)aalloc( dim, (size_t)sizeof(T) ); // CFA aalloc 58 else return (T *)amemalign( _Alignof(T), dim, sizeof(T) ); 59 } // aalloc 60 54 61 T * calloc( size_t dim ) { 55 62 if ( _Alignof(T) <= libAlign() )return (T *)(void *)calloc( dim, sizeof(T) ); // C calloc … … 57 64 } // calloc 58 65 66 T * resize( T * ptr, size_t size ) { // CFA realloc, eliminate return-type cast 67 return (T *)(void *)resize( (void *)ptr, size ); // C realloc 68 } // resize 69 59 70 T * realloc( T * ptr, size_t size ) { // CFA realloc, eliminate return-type cast 60 71 return (T *)(void *)realloc( (void *)ptr, size ); // C realloc … … 65 76 } // memalign 66 77 78 T * amemalign( size_t align, size_t dim ) { 79 return (T *)amemalign( align, dim, sizeof(T) ); // CFA amemalign 80 } // amemalign 81 67 82 T * cmemalign( size_t align, size_t dim ) { 68 83 return (T *)cmemalign( align, dim, sizeof(T) ); // CFA cmemalign … … 86 101 87 102 T * alloc( size_t 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) ); 103 return aalloc( dim ); 90 104 } // alloc 91 105 … … 106 120 return (T *)(void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc 107 121 } else { 108 struct __Unknown {}; 109 return alloc( (__Unknown *)ptr, dim ); // reuse, cheat making T/S different types 122 return resize( ptr, dim * sizeof(T) ); // resize 110 123 } // if 111 124 } // alloc … … 148 161 } // alloc_align 149 162 150 T * alloc_align( T ptr[], size_t align ) { // aligned realloc array163 T * alloc_align( T * ptr, size_t align ) { // aligned realloc array 151 164 return (T *)(void *)realloc( (void *)ptr, align, sizeof(T) ); // CFA realloc 152 165 } // alloc_align -
src/ControlStruct/ExceptTranslate.cc
r2802824 r0e4df2e 10 10 // Created On : Wed Jun 14 16:49:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Mar 27 11:58:00 202013 // Update Count : 1 312 // Last Modified On : Thr May 21 13:18:00 2020 13 // Update Count : 15 14 14 // 15 15 … … 64 64 } 65 65 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 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 { 78 185 // The built in types used in translation. 79 186 StructDecl * except_decl; … … 82 189 83 190 // 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 );90 191 CompoundStmt * take_try_block( TryStmt * tryStmt ); 91 192 FunctionDecl * create_try_wrapper( CompoundStmt * body ); … … 121 222 122 223 public: 123 ExceptionMutatorCore() : 124 cur_context( NoHandler ), 125 handler_except_decl( nullptr ), 224 TryMutatorCore() : 126 225 except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr ), 127 226 try_func_t( noQualifiers, false ), … … 132 231 {} 133 232 134 void premutate( CatchStmt *catchStmt );135 233 void premutate( StructDecl *structDecl ); 136 234 Statement * postmutate( ThrowStmt *throwStmt ); … … 138 236 }; 139 237 140 void ExceptionMutatorCore::init_func_types() {238 void TryMutatorCore::init_func_types() { 141 239 assert( except_decl ); 142 240 … … 196 294 } 197 295 198 // ThrowStmt Mutation Helpers199 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 257 296 // TryStmt Mutation Helpers 258 297 259 CompoundStmt * ExceptionMutatorCore::take_try_block( TryStmt *tryStmt ) {298 CompoundStmt * TryMutatorCore::take_try_block( TryStmt *tryStmt ) { 260 299 CompoundStmt * block = tryStmt->get_block(); 261 300 tryStmt->set_block( nullptr ); … … 263 302 } 264 303 265 FunctionDecl * ExceptionMutatorCore::create_try_wrapper(304 FunctionDecl * TryMutatorCore::create_try_wrapper( 266 305 CompoundStmt *body ) { 267 306 … … 270 309 } 271 310 272 FunctionDecl * ExceptionMutatorCore::create_terminate_catch(311 FunctionDecl * TryMutatorCore::create_terminate_catch( 273 312 CatchList &handlers ) { 274 313 std::list<CaseStmt *> handler_wrappers; … … 350 389 // Create a single check from a moddified handler. 351 390 // except_obj is referenced, modded_handler will be freed. 352 CompoundStmt * ExceptionMutatorCore::create_single_matcher(391 CompoundStmt * TryMutatorCore::create_single_matcher( 353 392 DeclarationWithType * except_obj, CatchStmt * modded_handler ) { 354 393 // { … … 388 427 } 389 428 390 FunctionDecl * ExceptionMutatorCore::create_terminate_match(429 FunctionDecl * TryMutatorCore::create_terminate_match( 391 430 CatchList &handlers ) { 392 431 // int match(exception * except) { … … 425 464 } 426 465 427 CompoundStmt * ExceptionMutatorCore::create_terminate_caller(466 CompoundStmt * TryMutatorCore::create_terminate_caller( 428 467 FunctionDecl * try_wrapper, 429 468 FunctionDecl * terminate_catch, … … 443 482 } 444 483 445 FunctionDecl * ExceptionMutatorCore::create_resume_handler(484 FunctionDecl * TryMutatorCore::create_resume_handler( 446 485 CatchList &handlers ) { 447 486 // bool handle(exception * except) { … … 480 519 } 481 520 482 CompoundStmt * ExceptionMutatorCore::create_resume_wrapper(521 CompoundStmt * TryMutatorCore::create_resume_wrapper( 483 522 Statement * wraps, 484 523 FunctionDecl * resume_handler ) { … … 524 563 } 525 564 526 FunctionDecl * ExceptionMutatorCore::create_finally_wrapper(565 FunctionDecl * TryMutatorCore::create_finally_wrapper( 527 566 TryStmt * tryStmt ) { 528 // void finally() { <finally code>}567 // void finally() { `finally->block` } 529 568 FinallyStmt * finally = tryStmt->get_finally(); 530 569 CompoundStmt * body = finally->get_block(); … … 537 576 } 538 577 539 ObjectDecl * ExceptionMutatorCore::create_finally_hook(578 ObjectDecl * TryMutatorCore::create_finally_hook( 540 579 FunctionDecl * finally_wrapper ) { 541 580 // struct __cfaehm_cleanup_hook __finally_hook 542 // __attribute__((cleanup( finally_wrapper)));581 // __attribute__((cleanup( `finally_wrapper` ))); 543 582 544 583 // Make Cleanup Attribute. … … 565 604 566 605 // Visiting/Mutating Functions 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 ) { 606 void TryMutatorCore::premutate( StructDecl *structDecl ) { 592 607 if ( !structDecl->has_body() ) { 593 608 // Skip children? … … 604 619 hook_decl = structDecl; 605 620 } 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 ) { 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 ) { 637 629 assert( except_decl ); 638 630 assert( node_decl ); … … 688 680 } 689 681 690 void translate EHM( std::list< Declaration *> & translationUnit ) {691 PassVisitor< ExceptionMutatorCore> translator;682 void translateThrows( std::list< Declaration *> & translationUnit ) { 683 PassVisitor<ThrowMutatorCore> translator; 692 684 mutateAll( translationUnit, translator ); 693 685 } 686 687 void translateTries( std::list< Declaration *> & translationUnit ) { 688 PassVisitor<TryMutatorCore> translator; 689 mutateAll( translationUnit, translator ); 690 } 694 691 } -
src/ControlStruct/ExceptTranslate.h
r2802824 r0e4df2e 9 9 // Author : Andrew Beach 10 10 // Created On : Tus Jun 06 10:13:00 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:19:23 201713 // Update Count : 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Tus May 19 11:47:00 2020 13 // Update Count : 5 14 14 // 15 15 … … 21 21 22 22 namespace ControlStruct { 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. 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 */ 26 33 } 27 34 -
src/main.cc
r2802824 r0e4df2e 9 9 // Author : Peter Buhr and Rob Schluntz 10 10 // Created On : Fri May 15 23:12:02 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Feb 8 08:33:50 202013 // Update Count : 63 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue May 19 12:03:00 2020 13 // Update Count : 634 14 14 // 15 15 … … 312 312 } // if 313 313 314 PASS( "Translate Throws", ControlStruct::translateThrows( translationUnit ) ); 314 315 PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) ); 315 316 PASS( "Fix Names", CodeGen::fixNames( translationUnit ) ); … … 354 355 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 355 356 356 PASS( "Translate EHM" , ControlStruct::translateEHM( translationUnit ) );357 PASS( "Translate Tries" , ControlStruct::translateTries( translationUnit ) ); 357 358 358 359 PASS( "Gen Waitfor" , Concurrency::generateWaitFor( translationUnit ) ); -
tests/errors/.expect/completeType.txt
r2802824 r0e4df2e 132 132 ?=?: pointer to function 133 133 ... with parameters 134 reference to instance of type _10 4_0_T (not function type)135 instance of type _10 4_0_T (not function type)134 reference to instance of type _108_0_T (not function type) 135 instance of type _108_0_T (not function type) 136 136 ... returning 137 _retval__operator_assign: instance of type _10 4_0_T (not function type)137 _retval__operator_assign: instance of type _108_0_T (not function type) 138 138 ... with attributes: 139 139 Attribute with name: unused -
tests/exceptions/conditional.cfa
r2802824 r0e4df2e 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
r2802824 r0e4df2e 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
r2802824 r0e4df2e 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
r2802824 r0e4df2e 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
r2802824 r0e4df2e 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
r2802824 r0e4df2e 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
r2802824 r0e4df2e 1464 1464 0.7 1465 1465 - 1466 1467 ~~~~~~~~~~ End removal tests on Headed List: First ~~~~~~~~~~ 1468 1469 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1470 Test 16-i. Modifying Freds on MINE 1471 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1472 ==== fred by MINE before 1473 1.7 1474 2.7 1475 3.7 1476 - 1477 1.7 1478 - 1479 3.7 1480 - 1481 3.7 1482 2.7 1483 1.7 1484 - 1485 ==== fred by YOURS before 1486 1.7 1487 2.7 1488 3.7 1489 - 1490 1.7 1491 - 1492 3.7 1493 - 1494 3.7 1495 2.7 1496 1.7 1497 - 1498 ==== fred by MINE after 1499 2.7 1500 3.7 1501 - 1502 2.7 1503 - 1504 3.7 1505 - 1506 3.7 1507 2.7 1508 - 1509 ==== fred by YOURS after 1510 1.7 1511 2.7 1512 3.7 1513 - 1514 1.7 1515 - 1516 3.7 1517 - 1518 3.7 1519 2.7 1520 1.7 1521 - 1522 ==== fred by MINE after 1523 1.7 1524 - 1525 1.7 1526 - 1527 - 1528 - 1529 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1530 Test 16-ii. Modifying Freds on YOURS 1531 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1532 ==== fred by MINE before 1533 1.7 1534 2.7 1535 3.7 1536 - 1537 1.7 1538 - 1539 3.7 1540 - 1541 3.7 1542 2.7 1543 1.7 1544 - 1545 ==== fred by YOURS before 1546 1.7 1547 2.7 1548 3.7 1549 - 1550 1.7 1551 - 1552 3.7 1553 - 1554 3.7 1555 2.7 1556 1.7 1557 - 1558 ==== fred by MINE after 1559 1.7 1560 2.7 1561 3.7 1562 - 1563 1.7 1564 - 1565 3.7 1566 - 1567 3.7 1568 2.7 1569 1.7 1570 - 1571 ==== fred by YOURS after 1572 2.7 1573 3.7 1574 - 1575 2.7 1576 - 1577 3.7 1578 - 1579 3.7 1580 2.7 1581 - 1582 ==== fred by YOURS after 1583 1.7 1584 - 1585 1.7 1586 - 1587 - 1588 - 1589 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1590 Test 16-iii. Modifying Maries 1591 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1592 ==== mary before 1593 1.7 1594 2.7 1595 3.7 1596 - 1597 1.7 1598 - 1599 3.7 1600 - 1601 3.7 1602 2.7 1603 1.7 1604 - 1605 ==== mary after 1606 2.7 1607 3.7 1608 - 1609 2.7 1610 - 1611 3.7 1612 - 1613 3.7 1614 2.7 1615 - 1616 ==== mary after 1617 1.7 1618 - 1619 1.7 1620 - 1621 - 1622 - 1623 1624 ~~~~~~~~~~ End removal tests on Headed List: Last ~~~~~~~~~~ 1625 1626 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1627 Test 17-i. Modifying Freds on MINE 1628 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1629 ==== fred by MINE before 1630 1.7 1631 2.7 1632 3.7 1633 - 1634 1.7 1635 - 1636 3.7 1637 - 1638 3.7 1639 2.7 1640 1.7 1641 - 1642 ==== fred by YOURS before 1643 1.7 1644 2.7 1645 3.7 1646 - 1647 1.7 1648 - 1649 3.7 1650 - 1651 3.7 1652 2.7 1653 1.7 1654 - 1655 ==== fred by MINE after 1656 1.7 1657 2.7 1658 - 1659 1.7 1660 - 1661 2.7 1662 - 1663 2.7 1664 1.7 1665 - 1666 ==== fred by YOURS after 1667 1.7 1668 2.7 1669 3.7 1670 - 1671 1.7 1672 - 1673 3.7 1674 - 1675 3.7 1676 2.7 1677 1.7 1678 - 1679 ==== fred by MINE after 1680 3.7 1681 - 1682 3.7 1683 - 1684 - 1685 - 1686 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1687 Test 17-ii. Modifying Freds on YOURS 1688 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1689 ==== fred by MINE before 1690 1.7 1691 2.7 1692 3.7 1693 - 1694 1.7 1695 - 1696 3.7 1697 - 1698 3.7 1699 2.7 1700 1.7 1701 - 1702 ==== fred by YOURS before 1703 1.7 1704 2.7 1705 3.7 1706 - 1707 1.7 1708 - 1709 3.7 1710 - 1711 3.7 1712 2.7 1713 1.7 1714 - 1715 ==== fred by MINE after 1716 1.7 1717 2.7 1718 3.7 1719 - 1720 1.7 1721 - 1722 3.7 1723 - 1724 3.7 1725 2.7 1726 1.7 1727 - 1728 ==== fred by YOURS after 1729 1.7 1730 2.7 1731 - 1732 1.7 1733 - 1734 2.7 1735 - 1736 2.7 1737 1.7 1738 - 1739 ==== fred by YOURS after 1740 3.7 1741 - 1742 3.7 1743 - 1744 - 1745 - 1746 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1747 Test 17-iii. Modifying Maries 1748 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1749 ==== mary before 1750 1.7 1751 2.7 1752 3.7 1753 - 1754 1.7 1755 - 1756 3.7 1757 - 1758 3.7 1759 2.7 1760 1.7 1761 - 1762 ==== mary after 1763 1.7 1764 2.7 1765 - 1766 1.7 1767 - 1768 2.7 1769 - 1770 2.7 1771 1.7 1772 - 1773 ==== mary after 1774 3.7 1775 - 1776 3.7 1777 - 1778 - 1779 - -
tests/list/dlist-insert-remove.cfa
r2802824 r0e4df2e 1187 1187 //////////////////////////////////////////////////////////// 1188 1188 // 1189 // Section 4f 1190 // 1191 // Test cases of pop_first, pop_last 1192 // 1193 // Example of call-side user code 1194 // 1195 //////////////////////////////////////////////////////////// 1196 1197 // These cases assume element removal at first-last is correct 1198 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.7 1216 printYourFreddies(fly`first, fly`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.7 1217 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 traversed 1230 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.7 1252 printYourFreddies(fly`first, fly`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.7 1253 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 traversed 1266 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.7 1283 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 solo 1293 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.7 1315 printYourFreddies(fly`first, fly`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.7 1316 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 traversed 1329 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.7 1351 printYourFreddies(fly`first, fly`last, 1); // 1.7, 2.7, 3.7; 1.7; 3.7; 3.7, 2.7, 1.7 1352 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 traversed 1365 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.7 1382 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 solo 1392 printMariatheotokos(m3, *0p, 0); // 3.7; 3.7; ; 1393 1394 assert( &popped == &m3 ); 1395 } 1396 1397 //////////////////////////////////////////////////////////// 1398 // 1189 1399 // Section 5 1190 1400 // … … 1422 1632 test__remove_of_sole__mary(); 1423 1633 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 1424 1672 return 0; 1425 1673 }
Note: See TracChangeset
for help on using the changeset viewer.