Changeset 47e000c
- Timestamp:
- Apr 13, 2021, 8:02:56 PM (3 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- e56cfb41
- Parents:
- 0effb6a (diff), 7f5683e (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
- 52 edited
Legend:
- Unmodified
- Added
- Removed
-
benchmark/basic/ttst_lock.c
r0effb6a r47e000c 9 9 #define CALIGN __attribute__(( aligned (CACHE_ALIGN) )) 10 10 #define CACHE_ALIGN 128 11 #define Pause() __asm__ __volatile__ ( "pause" : : : ) 11 #if defined( __i386 ) || defined( __x86_64 ) 12 #define Pause() __asm__ __volatile__ ( "pause" : : : ) 13 #elif defined( __ARM_ARCH ) 14 #define Pause() __asm__ __volatile__ ( "YIELD" : : : ) 15 #else 16 #error unsupported architecture 17 #endif 12 18 13 19 typedef uintptr_t TYPE; // addressable word-size -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list.hpp
r0effb6a r47e000c 39 39 while( __builtin_expect(ll.exchange(true),false) ) { 40 40 while(ll.load(std::memory_order_relaxed)) 41 asm volatile("pause");41 Pause(); 42 42 } 43 43 /* paranoid */ assert(ll); … … 93 93 && ready.compare_exchange_weak(copy, n + 1) ) 94 94 break; 95 asm volatile("pause");95 Pause(); 96 96 } 97 97 … … 133 133 // Step 1 : make sure no writer are in the middle of the critical section 134 134 while(lock.load(std::memory_order_relaxed)) 135 asm volatile("pause");135 Pause(); 136 136 137 137 // Fence needed because we don't want to start trying to acquire the lock … … 195 195 // to simply lock their own lock and enter. 196 196 while(lock.load(std::memory_order_relaxed)) 197 asm volatile("pause");197 Pause(); 198 198 199 199 // Step 2 : lock per-proc lock … … 204 204 for(uint_fast32_t i = 0; i < s; i++) { 205 205 while(data[i].lock.load(std::memory_order_relaxed)) 206 asm volatile("pause");206 Pause(); 207 207 } 208 208 -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list_good.cpp
r0effb6a r47e000c 21 21 target = (target - (target % total)) + total; 22 22 while(waiting < target) 23 asm volatile("pause");23 Pause(); 24 24 25 25 assert(waiting < (1ul << 60)); -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/randbit.cpp
r0effb6a r47e000c 123 123 target = (target - (target % total)) + total; 124 124 while(waiting < target) 125 asm volatile("pause");125 Pause(); 126 126 127 127 assert(waiting < (1ul << 60)); -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/relaxed_list.cpp
r0effb6a r47e000c 206 206 std::cout << "Total ops : " << ops << "(" << global.in << "i, " << global.out << "o, " << global.empty << "e)\n"; 207 207 #ifndef NO_STATS 208 LIST_VARIANT<Node>::stats_print(std::cout );208 LIST_VARIANT<Node>::stats_print(std::cout, duration); 209 209 #endif 210 210 } … … 368 368 369 369 for(Node * & node : nodes) { 370 node = list.pop(); 371 assert(node); 370 node = nullptr; 371 while(!node) { 372 node = list.pop(); 373 } 372 374 local.crc_out += node->value; 373 375 local.out++; … … 691 693 692 694 for(const auto & n : nodes) { 693 local.valmax = max(local.valmax, size_t(n.value));694 local.valmin = min(local.valmin, size_t(n.value));695 local.valmax = std::max(local.valmax, size_t(n.value)); 696 local.valmin = std::min(local.valmin, size_t(n.value)); 695 697 } 696 698 … … 773 775 try { 774 776 arg = optarg = argv[optind]; 775 nnodes = st oul(optarg, &len);777 nnodes = std::stoul(optarg, &len); 776 778 if(len != arg.size()) { throw std::invalid_argument(""); } 777 779 } catch(std::invalid_argument &) { … … 792 794 try { 793 795 arg = optarg = argv[optind]; 794 nnodes = st oul(optarg, &len);796 nnodes = std::stoul(optarg, &len); 795 797 if(len != arg.size()) { throw std::invalid_argument(""); } 796 798 } catch(std::invalid_argument &) { … … 812 814 try { 813 815 arg = optarg = argv[optind]; 814 nnodes = st oul(optarg, &len);816 nnodes = std::stoul(optarg, &len); 815 817 if(len != arg.size()) { throw std::invalid_argument(""); } 816 818 nslots = nnodes; … … 823 825 try { 824 826 arg = optarg = argv[optind]; 825 nnodes = st oul(optarg, &len);827 nnodes = std::stoul(optarg, &len); 826 828 if(len != arg.size()) { throw std::invalid_argument(""); } 827 829 } catch(std::invalid_argument &) { … … 831 833 try { 832 834 arg = optarg = argv[optind + 1]; 833 nslots = st oul(optarg, &len);835 nslots = std::stoul(optarg, &len); 834 836 if(len != arg.size()) { throw std::invalid_argument(""); } 835 837 } catch(std::invalid_argument &) { … … 884 886 case 'd': 885 887 try { 886 duration = st od(optarg, &len);888 duration = std::stod(optarg, &len); 887 889 if(len != arg.size()) { throw std::invalid_argument(""); } 888 890 } catch(std::invalid_argument &) { … … 893 895 case 't': 894 896 try { 895 nthreads = st oul(optarg, &len);897 nthreads = std::stoul(optarg, &len); 896 898 if(len != arg.size()) { throw std::invalid_argument(""); } 897 899 } catch(std::invalid_argument &) { … … 902 904 case 'q': 903 905 try { 904 nqueues = st oul(optarg, &len);906 nqueues = std::stoul(optarg, &len); 905 907 if(len != arg.size()) { throw std::invalid_argument(""); } 906 908 } catch(std::invalid_argument &) { -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi-packed.hpp
r0effb6a r47e000c 168 168 for(int i = 0; i < width; i++) { 169 169 int idx = i % hwdith; 170 std::cout << i << " -> " << idx + width << std::endl;171 170 leafs[i].parent = &nodes[ idx ]; 172 171 } … … 174 173 for(int i = 0; i < root; i++) { 175 174 int idx = (i / 2) + hwdith; 176 std::cout << i + width << " -> " << idx + width << std::endl;177 175 nodes[i].parent = &nodes[ idx ]; 178 176 } -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi.hpp
r0effb6a r47e000c 159 159 std::cout << "SNZI: " << depth << "x" << width << "(" << mask - 1 << ") " << (sizeof(snzi_t::node) * (root + 1)) << " bytes" << std::endl; 160 160 for(int i = 0; i < root; i++) { 161 std::cout << i << " -> " << (i / base) + width << std::endl;162 161 nodes[i].parent = &nodes[(i / base) + width]; 163 162 } -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/utils.hpp
r0effb6a r47e000c 12 12 13 13 #include <x86intrin.h> 14 15 // Barrier from16 class barrier_t {17 public:18 barrier_t(size_t total)19 : waiting(0)20 , total(total)21 {}22 23 void wait(unsigned) {24 size_t target = waiting++;25 target = (target - (target % total)) + total;26 while(waiting < target)27 asm volatile("pause");28 29 assert(waiting < (1ul << 60));30 }31 32 private:33 std::atomic<size_t> waiting;34 size_t total;35 };36 14 37 15 // class Random { … … 102 80 }; 103 81 104 static inline long long rdtscl(void) { 105 unsigned int lo, hi; 106 __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); 107 return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); 108 } 82 static inline long long int rdtscl(void) { 83 #if defined( __i386 ) || defined( __x86_64 ) 84 unsigned int lo, hi; 85 __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); 86 return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); 87 #elif defined( __aarch64__ ) || defined( __arm__ ) 88 // https://github.com/google/benchmark/blob/v1.1.0/src/cycleclock.h#L116 89 long long int virtual_timer_value; 90 asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value)); 91 return virtual_timer_value; 92 #else 93 #error unsupported hardware architecture 94 #endif 95 } 96 97 #if defined( __i386 ) || defined( __x86_64 ) 98 #define Pause() __asm__ __volatile__ ( "pause" : : : ) 99 #elif defined( __ARM_ARCH ) 100 #define Pause() __asm__ __volatile__ ( "YIELD" : : : ) 101 #else 102 #error unsupported architecture 103 #endif 109 104 110 105 static inline void affinity(int tid) { … … 195 190 } 196 191 192 // Barrier from 193 class barrier_t { 194 public: 195 barrier_t(size_t total) 196 : waiting(0) 197 , total(total) 198 {} 199 200 void wait(unsigned) { 201 size_t target = waiting++; 202 target = (target - (target % total)) + total; 203 while(waiting < target) 204 Pause(); 205 206 assert(waiting < (1ul << 60)); 207 } 208 209 private: 210 std::atomic<size_t> waiting; 211 size_t total; 212 }; 213 197 214 struct spinlock_t { 198 215 std::atomic_bool ll = { false }; … … 201 218 while( __builtin_expect(ll.exchange(true),false) ) { 202 219 while(ll.load(std::memory_order_relaxed)) 203 asm volatile("pause");220 Pause(); 204 221 } 205 222 } -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/work_stealing.hpp
r0effb6a r47e000c 6 6 #include <memory> 7 7 #include <mutex> 8 #include <thread> 8 9 #include <type_traits> 9 10 … … 11 12 #include "utils.hpp" 12 13 #include "links.hpp" 14 #include "links2.hpp" 13 15 #include "snzi.hpp" 14 16 17 #include <x86intrin.h> 18 15 19 using namespace std; 20 21 static const long long lim = 2000; 22 static const unsigned nqueues = 2; 23 24 struct __attribute__((aligned(128))) timestamp_t { 25 volatile unsigned long long val = 0; 26 }; 27 28 template<typename node_t> 29 struct __attribute__((aligned(128))) localQ_t { 30 mpsc_queue<node_t> queue = {}; 31 spinlock_t lock = {}; 32 bool needs_help = true; 33 }; 16 34 17 35 template<typename node_t> … … 25 43 26 44 work_stealing(unsigned _numThreads, unsigned) 27 : numThreads(_numThreads )45 : numThreads(_numThreads * nqueues) 28 46 , lists(new intrusive_queue_t<node_t>[numThreads]) 29 , snzi( std::log2( numThreads / 2 ), 2 ) 47 , times(new timestamp_t[numThreads]) 48 // , snzi( std::log2( numThreads / 2 ), 2 ) 30 49 31 50 { … … 39 58 40 59 __attribute__((noinline, hot)) void push(node_t * node) { 41 node->_links.ts = rdtscl(); 42 if( node->_links.hint > numThreads ) { 43 node->_links.hint = tls.rng.next() % numThreads; 44 tls.stat.push.nhint++; 45 } 46 47 unsigned i = node->_links.hint; 60 // node->_links.ts = rdtscl(); 61 node->_links.ts = 1; 62 63 auto & list = *({ 64 unsigned i; 65 do { 66 tls.stats.push.attempt++; 67 // unsigned r = tls.rng1.next(); 68 unsigned r = tls.it++; 69 if(tls.my_queue == outside) { 70 i = r % numThreads; 71 } else { 72 i = tls.my_queue + (r % nqueues); 73 } 74 } while(!lists[i].lock.try_lock()); 75 &lists[i]; 76 }); 77 78 list.push( node ); 79 list.lock.unlock(); 80 // tls.rng2.set_raw_state( tls.rng1.get_raw_state()); 81 // count++; 82 tls.stats.push.success++; 83 } 84 85 __attribute__((noinline, hot)) node_t * pop() { 86 if( tls.myfriend == outside ) { 87 auto r = tls.rng1.next(); 88 tls.myfriend = r % numThreads; 89 times[tls.myfriend].val = 0; 90 } 91 else if(times[tls.myfriend].val == 0) { 92 node_t * n = try_pop(tls.myfriend, tls.stats.pop.help); 93 tls.stats.help++; 94 tls.myfriend = outside; 95 if(n) return n; 96 } 97 98 if(tls.my_queue != outside) { 99 node_t * n = local(); 100 if(n) return n; 101 } 102 103 // try steal 104 for(int i = 0; i < 25; i++) { 105 node_t * n = steal(); 106 if(n) return n; 107 } 108 109 return search(); 110 } 111 112 private: 113 inline node_t * local() { 114 // unsigned i = (tls.rng2.prev() % 4) + tls.my_queue; 115 unsigned i = (--tls.it % nqueues) + tls.my_queue; 116 return try_pop(i, tls.stats.pop.local); 117 } 118 119 inline node_t * steal() { 120 unsigned i = tls.rng2.prev() % numThreads; 121 return try_pop(i, tls.stats.pop.steal); 122 } 123 124 inline node_t * search() { 125 unsigned offset = tls.rng2.prev(); 126 for(unsigned i = 0; i < numThreads; i++) { 127 unsigned idx = (offset + i) % numThreads; 128 node_t * thrd = try_pop(idx, tls.stats.pop.search); 129 if(thrd) { 130 return thrd; 131 } 132 } 133 134 return nullptr; 135 } 136 137 private: 138 struct attempt_stat_t { 139 std::size_t attempt = { 0 }; 140 std::size_t elock = { 0 }; 141 std::size_t eempty = { 0 }; 142 std::size_t espec = { 0 }; 143 std::size_t success = { 0 }; 144 }; 145 146 node_t * try_pop(unsigned i, attempt_stat_t & stat) { 147 assert(i < numThreads); 48 148 auto & list = lists[i]; 49 list.lock.lock(); 50 51 if(list.push( node )) { 52 snzi.arrive(i); 53 } 54 55 list.lock.unlock(); 56 } 57 58 __attribute__((noinline, hot)) node_t * pop() { 59 node_t * node; 60 while(true) { 61 if(!snzi.query()) { 62 return nullptr; 63 } 64 65 { 66 unsigned i = tls.my_queue; 67 auto & list = lists[i]; 68 if( list.ts() != 0 ) { 69 list.lock.lock(); 70 if((node = try_pop(i))) { 71 tls.stat.pop.local.success++; 72 break; 73 } 74 else { 75 tls.stat.pop.local.elock++; 76 } 77 } 78 else { 79 tls.stat.pop.local.espec++; 80 } 81 } 82 83 tls.stat.pop.steal.tried++; 84 85 int i = tls.rng.next() % numThreads; 86 auto & list = lists[i]; 87 if( list.ts() == 0 ) { 88 tls.stat.pop.steal.empty++; 89 continue; 90 } 91 92 if( !list.lock.try_lock() ) { 93 tls.stat.pop.steal.locked++; 94 continue; 95 } 96 97 if((node = try_pop(i))) { 98 tls.stat.pop.steal.success++; 99 break; 100 } 101 } 102 103 #if defined(READ) 104 const unsigned f = READ; 105 if(0 == (tls.it % f)) { 106 unsigned i = tls.it / f; 107 lists[i % numThreads].ts(); 108 } 109 // lists[tls.it].ts(); 110 tls.it++; 111 #endif 112 113 114 return node; 115 } 116 117 private: 118 node_t * try_pop(unsigned i) { 119 auto & list = lists[i]; 149 stat.attempt++; 150 151 // If the list is empty, don't try 152 if(list.ts() == 0) { stat.espec++; return nullptr; } 153 154 // If we can't get the lock, move on 155 if( !list.lock.try_lock() ) { stat.elock++; return nullptr; } 156 120 157 121 158 // If list is empty, unlock and retry 122 159 if( list.ts() == 0 ) { 123 160 list.lock.unlock(); 161 stat.eempty++; 124 162 return nullptr; 125 163 } 126 164 127 // Actually pop the list 128 node_t * node; 129 bool emptied; 130 std::tie(node, emptied) = list.pop(); 131 assert(node); 132 133 if(emptied) { 134 snzi.depart(i); 135 } 136 137 // Unlock and return 165 auto node = list.pop(); 138 166 list.lock.unlock(); 139 return node; 167 stat.success++; 168 times[i].val = 1; //node.first->_links.ts; 169 // count--; 170 // _mm_stream_si64((long long int*)×[i].val, node.first->_links.ts); 171 return node.first; 140 172 } 141 173 … … 144 176 145 177 static std::atomic_uint32_t ticket; 178 static const unsigned outside = 0xFFFFFFFF; 179 180 static inline unsigned calc_preferred() { 181 unsigned t = ticket++; 182 if(t == 0) return outside; 183 unsigned i = (t - 1) * nqueues; 184 return i; 185 } 186 146 187 static __attribute__((aligned(128))) thread_local struct TLS { 147 Random rng = { int(rdtscl()) }; 148 unsigned my_queue = ticket++; 188 Random rng1 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) }; 189 Random rng2 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) }; 190 unsigned it = 0; 191 unsigned my_queue = calc_preferred(); 192 unsigned myfriend = outside; 149 193 #if defined(READ) 150 194 unsigned it = 0; … … 152 196 struct { 153 197 struct { 154 std::size_t nhint = { 0 }; 198 std::size_t attempt = { 0 }; 199 std::size_t success = { 0 }; 155 200 } push; 156 201 struct { 157 struct { 158 std::size_t success = { 0 }; 159 std::size_t espec = { 0 }; 160 std::size_t elock = { 0 }; 161 } local; 162 struct { 163 std::size_t tried = { 0 }; 164 std::size_t locked = { 0 }; 165 std::size_t empty = { 0 }; 166 std::size_t success = { 0 }; 167 } steal; 202 attempt_stat_t help; 203 attempt_stat_t local; 204 attempt_stat_t steal; 205 attempt_stat_t search; 168 206 } pop; 169 } stat; 207 std::size_t help = { 0 }; 208 } stats; 170 209 } tls; 171 210 … … 173 212 const unsigned numThreads; 174 213 std::unique_ptr<intrusive_queue_t<node_t> []> lists; 175 __attribute__((aligned(64))) snzi_t snzi; 214 std::unique_ptr<timestamp_t []> times; 215 __attribute__((aligned(128))) std::atomic_size_t count; 176 216 177 217 #ifndef NO_STATS … … 179 219 static struct GlobalStats { 180 220 struct { 181 std::atomic_size_t nhint = { 0 }; 221 std::atomic_size_t attempt = { 0 }; 222 std::atomic_size_t success = { 0 }; 182 223 } push; 183 224 struct { 184 225 struct { 226 std::atomic_size_t attempt = { 0 }; 227 std::atomic_size_t elock = { 0 }; 228 std::atomic_size_t eempty = { 0 }; 229 std::atomic_size_t espec = { 0 }; 185 230 std::atomic_size_t success = { 0 }; 186 std::atomic_size_t espec = { 0 }; 187 std::atomic_size_t elock = { 0 }; 231 } help; 232 struct { 233 std::atomic_size_t attempt = { 0 }; 234 std::atomic_size_t elock = { 0 }; 235 std::atomic_size_t eempty = { 0 }; 236 std::atomic_size_t espec = { 0 }; 237 std::atomic_size_t success = { 0 }; 188 238 } local; 189 239 struct { 190 std::atomic_size_t tried = { 0 }; 191 std::atomic_size_t locked = { 0 }; 192 std::atomic_size_t empty = { 0 }; 240 std::atomic_size_t attempt = { 0 }; 241 std::atomic_size_t elock = { 0 }; 242 std::atomic_size_t eempty = { 0 }; 243 std::atomic_size_t espec = { 0 }; 193 244 std::atomic_size_t success = { 0 }; 194 245 } steal; 246 struct { 247 std::atomic_size_t attempt = { 0 }; 248 std::atomic_size_t elock = { 0 }; 249 std::atomic_size_t eempty = { 0 }; 250 std::atomic_size_t espec = { 0 }; 251 std::atomic_size_t success = { 0 }; 252 } search; 195 253 } pop; 254 std::atomic_size_t help = { 0 }; 196 255 } global_stats; 197 256 198 257 public: 199 258 static void stats_tls_tally() { 200 global_stats.push.nhint += tls.stat.push.nhint; 201 global_stats.pop.local.success += tls.stat.pop.local.success; 202 global_stats.pop.local.espec += tls.stat.pop.local.espec ; 203 global_stats.pop.local.elock += tls.stat.pop.local.elock ; 204 global_stats.pop.steal.tried += tls.stat.pop.steal.tried ; 205 global_stats.pop.steal.locked += tls.stat.pop.steal.locked ; 206 global_stats.pop.steal.empty += tls.stat.pop.steal.empty ; 207 global_stats.pop.steal.success += tls.stat.pop.steal.success; 208 } 209 210 static void stats_print(std::ostream & os ) { 259 global_stats.push.attempt += tls.stats.push.attempt; 260 global_stats.push.success += tls.stats.push.success; 261 global_stats.pop.help .attempt += tls.stats.pop.help .attempt; 262 global_stats.pop.help .elock += tls.stats.pop.help .elock ; 263 global_stats.pop.help .eempty += tls.stats.pop.help .eempty ; 264 global_stats.pop.help .espec += tls.stats.pop.help .espec ; 265 global_stats.pop.help .success += tls.stats.pop.help .success; 266 global_stats.pop.local .attempt += tls.stats.pop.local .attempt; 267 global_stats.pop.local .elock += tls.stats.pop.local .elock ; 268 global_stats.pop.local .eempty += tls.stats.pop.local .eempty ; 269 global_stats.pop.local .espec += tls.stats.pop.local .espec ; 270 global_stats.pop.local .success += tls.stats.pop.local .success; 271 global_stats.pop.steal .attempt += tls.stats.pop.steal .attempt; 272 global_stats.pop.steal .elock += tls.stats.pop.steal .elock ; 273 global_stats.pop.steal .eempty += tls.stats.pop.steal .eempty ; 274 global_stats.pop.steal .espec += tls.stats.pop.steal .espec ; 275 global_stats.pop.steal .success += tls.stats.pop.steal .success; 276 global_stats.pop.search.attempt += tls.stats.pop.search.attempt; 277 global_stats.pop.search.elock += tls.stats.pop.search.elock ; 278 global_stats.pop.search.eempty += tls.stats.pop.search.eempty ; 279 global_stats.pop.search.espec += tls.stats.pop.search.espec ; 280 global_stats.pop.search.success += tls.stats.pop.search.success; 281 global_stats.help += tls.stats.help; 282 } 283 284 static void stats_print(std::ostream & os, double duration ) { 211 285 std::cout << "----- Work Stealing Stats -----" << std::endl; 212 286 213 double stealSucc = double(global_stats.pop.steal.success) / global_stats.pop.steal.tried; 214 os << "Push to new Q : " << std::setw(15) << global_stats.push.nhint << "\n"; 215 os << "Local Pop : " << std::setw(15) << global_stats.pop.local.success << "\n"; 216 os << "Steal Pop : " << std::setw(15) << global_stats.pop.steal.success << "(" << global_stats.pop.local.espec << "s, " << global_stats.pop.local.elock << "l)\n"; 217 os << "Steal Success : " << std::setw(15) << stealSucc << "(" << global_stats.pop.steal.tried << " tries)\n"; 218 os << "Steal Fails : " << std::setw(15) << global_stats.pop.steal.empty << "e, " << global_stats.pop.steal.locked << "l\n"; 287 double push_suc = (100.0 * double(global_stats.push.success) / global_stats.push.attempt); 288 double push_len = double(global_stats.push.attempt ) / global_stats.push.success; 289 os << "Push Pick : " << push_suc << " %, len " << push_len << " (" << global_stats.push.attempt << " / " << global_stats.push.success << ")\n"; 290 291 double hlp_suc = (100.0 * double(global_stats.pop.help.success) / global_stats.pop.help.attempt); 292 double hlp_len = double(global_stats.pop.help.attempt ) / global_stats.pop.help.success; 293 os << "Help : " << hlp_suc << " %, len " << hlp_len << " (" << global_stats.pop.help.attempt << " / " << global_stats.pop.help.success << ")\n"; 294 os << "Help Fail : " << global_stats.pop.help.espec << "s, " << global_stats.pop.help.eempty << "e, " << global_stats.pop.help.elock << "l\n"; 295 296 double pop_suc = (100.0 * double(global_stats.pop.local.success) / global_stats.pop.local.attempt); 297 double pop_len = double(global_stats.pop.local.attempt ) / global_stats.pop.local.success; 298 os << "Local : " << pop_suc << " %, len " << pop_len << " (" << global_stats.pop.local.attempt << " / " << global_stats.pop.local.success << ")\n"; 299 os << "Local Fail : " << global_stats.pop.local.espec << "s, " << global_stats.pop.local.eempty << "e, " << global_stats.pop.local.elock << "l\n"; 300 301 double stl_suc = (100.0 * double(global_stats.pop.steal.success) / global_stats.pop.steal.attempt); 302 double stl_len = double(global_stats.pop.steal.attempt ) / global_stats.pop.steal.success; 303 os << "Steal : " << stl_suc << " %, len " << stl_len << " (" << global_stats.pop.steal.attempt << " / " << global_stats.pop.steal.success << ")\n"; 304 os << "Steal Fail : " << global_stats.pop.steal.espec << "s, " << global_stats.pop.steal.eempty << "e, " << global_stats.pop.steal.elock << "l\n"; 305 306 double srh_suc = (100.0 * double(global_stats.pop.search.success) / global_stats.pop.search.attempt); 307 double srh_len = double(global_stats.pop.search.attempt ) / global_stats.pop.search.success; 308 os << "Search : " << srh_suc << " %, len " << srh_len << " (" << global_stats.pop.search.attempt << " / " << global_stats.pop.search.success << ")\n"; 309 os << "Search Fail : " << global_stats.pop.search.espec << "s, " << global_stats.pop.search.eempty << "e, " << global_stats.pop.search.elock << "l\n"; 310 os << "Helps : " << std::setw(15) << std::scientific << global_stats.help / duration << "/sec (" << global_stats.help << ")\n"; 219 311 } 220 312 private: -
libcfa/src/concurrency/coroutine.cfa
r0effb6a r47e000c 46 46 47 47 //----------------------------------------------------------------------------- 48 FORALL_DATA_INSTANCE(CoroutineCancelled, (coroutine_t &), (coroutine_t)) 49 50 forall(T &) 51 void mark_exception(CoroutineCancelled(T) *) {} 48 EHM_VIRTUAL_TABLE(SomeCoroutineCancelled, std_coroutine_cancelled); 52 49 53 50 forall(T &) … … 71 68 72 69 // TODO: Remove explitate vtable set once trac#186 is fixed. 73 CoroutineCancelled(T)except;74 except.virtual_table = & get_exception_vtable(&except);70 SomeCoroutineCancelled except; 71 except.virtual_table = &std_coroutine_cancelled; 75 72 except.the_coroutine = &cor; 76 73 except.the_exception = except; 77 throwResume except; 74 // Why does this need a cast? 75 throwResume (SomeCoroutineCancelled &)except; 78 76 79 77 except->virtual_table->free( except ); -
libcfa/src/concurrency/coroutine.hfa
r0effb6a r47e000c 22 22 //----------------------------------------------------------------------------- 23 23 // Exception thrown from resume when a coroutine stack is cancelled. 24 FORALL_DATA_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) ( 24 EHM_EXCEPTION(SomeCoroutineCancelled)( 25 void * the_coroutine; 26 exception_t * the_exception; 27 ); 28 29 EHM_EXTERN_VTABLE(SomeCoroutineCancelled, std_coroutine_cancelled); 30 31 EHM_FORALL_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) ( 25 32 coroutine_t * the_coroutine; 26 33 exception_t * the_exception; … … 37 44 // Anything that implements this trait can be resumed. 38 45 // Anything that is resumed is a coroutine. 39 trait is_coroutine(T & | IS_RESUMPTION_EXCEPTION( CoroutineCancelled, (T))) {46 trait is_coroutine(T & | IS_RESUMPTION_EXCEPTION(SomeCoroutineCancelled)) { 40 47 void main(T & this); 41 48 $coroutine * get_coroutine(T & this); -
libcfa/src/concurrency/kernel.cfa
r0effb6a r47e000c 359 359 #if !defined(__CFA_NO_STATISTICS__) 360 360 __tls_stats()->ready.threads.threads++; 361 __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this ); 361 362 #endif 362 363 // This is case 2, the racy case, someone tried to run this thread before it finished blocking … … 376 377 #if !defined(__CFA_NO_STATISTICS__) 377 378 __tls_stats()->ready.threads.threads--; 379 __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this ); 378 380 #endif 379 381 … … 455 457 if( kernelTLS().this_stats ) { 456 458 __tls_stats()->ready.threads.threads++; 459 __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", kernelTLS().this_processor ); 457 460 } 458 461 else { 459 462 __atomic_fetch_add(&cl->stats->ready.threads.threads, 1, __ATOMIC_RELAXED); 463 __push_stat( cl->stats, cl->stats->ready.threads.threads, true, "Cluster", cl ); 460 464 } 461 465 #endif -
libcfa/src/concurrency/kernel/startup.cfa
r0effb6a r47e000c 268 268 __print_stats( st, mainProcessor->print_stats, "Processor ", mainProcessor->name, (void*)mainProcessor ); 269 269 } 270 #if defined(CFA_STATS_ARRAY) 271 __flush_stat( st, "Processor", mainProcessor ); 272 #endif 270 273 #endif 271 274 … … 348 351 __print_stats( &local_stats, proc->print_stats, "Processor ", proc->name, (void*)proc ); 349 352 } 353 #if defined(CFA_STATS_ARRAY) 354 __flush_stat( &local_stats, "Processor", proc ); 355 #endif 350 356 #endif 351 357 … … 615 621 __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this ); 616 622 } 623 #if defined(CFA_STATS_ARRAY) 624 __flush_stat( this.stats, "Cluster", &this ); 625 #endif 617 626 free( this.stats ); 618 627 #endif -
libcfa/src/concurrency/stats.cfa
r0effb6a r47e000c 5 5 #include <inttypes.h> 6 6 #include "bits/debug.hfa" 7 #include "bits/locks.hfa" 7 8 #include "stats.hfa" 8 9 … … 44 45 stats->io.calls.errors.busy = 0; 45 46 stats->io.poller.sleeps = 0; 47 #endif 48 49 #if defined(CFA_STATS_ARRAY) 50 stats->array.values = alloc(CFA_STATS_ARRAY); 51 stats->array.cnt = 0; 46 52 #endif 47 53 } … … 151 157 #endif 152 158 } 159 160 #if defined(CFA_STATS_ARRAY) 161 extern "C" { 162 #include <stdio.h> 163 #include <errno.h> 164 #include <sys/stat.h> 165 #include <fcntl.h> 166 } 167 168 void __flush_stat( struct __stats_t * this, const char * name, void * handle) { 169 int ret = mkdir(".cfadata", 0755); 170 if(ret < 0 && errno != EEXIST) abort("Failed to create directory .cfadata: %d\n", errno); 171 172 char filename[100]; 173 snprintf(filename, 100, ".cfadata/%s%p.data", name, handle); 174 175 int fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0644); 176 if(fd < 0) abort("Failed to create file %s: %d\n", filename, errno); 177 178 for(i; this->array.cnt) { 179 char line[100]; 180 size_t n = snprintf(line, 100, "%llu, %lld\n", this->array.values[i].ts, this->array.values[i].value); 181 write(fd, line, n); 182 } 183 184 this->array.cnt = 0; 185 close(fd); 186 } 187 188 static __spinlock_t stats_lock; 189 190 void __push_stat( struct __stats_t * this, int64_t value, bool external, const char * name, void * handle ) { 191 if(external) lock(stats_lock __cfaabi_dbg_ctx2); 192 193 if( this->array.cnt >= CFA_STATS_ARRAY ) __flush_stat( this, name, handle ); 194 195 size_t idx = this->array.cnt; 196 this->array.cnt++; 197 198 if(external) unlock(stats_lock); 199 200 this->array.values[idx].ts = rdtscl(); 201 this->array.values[idx].value = value; 202 } 203 #endif 153 204 #endif -
libcfa/src/concurrency/stats.hfa
r0effb6a r47e000c 1 1 #pragma once 2 3 // #define CFA_STATS_ARRAY 10000 2 4 3 5 #include <stdint.h> … … 109 111 #endif 110 112 113 #if defined(CFA_STATS_ARRAY) 114 struct __stats_elem_t { 115 long long int ts; 116 int64_t value; 117 }; 118 #endif 119 111 120 struct __attribute__((aligned(128))) __stats_t { 112 121 __stats_readQ_t ready; … … 114 123 __stats_io_t io; 115 124 #endif 125 126 #if defined(CFA_STATS_ARRAY) 127 struct { 128 __stats_elem_t * values; 129 volatile size_t cnt; 130 } array; 131 #endif 132 116 133 }; 117 134 … … 119 136 void __tally_stats( struct __stats_t *, struct __stats_t * ); 120 137 void __print_stats( struct __stats_t *, int, const char *, const char *, void * ); 138 #if defined(CFA_STATS_ARRAY) 139 void __push_stat ( struct __stats_t *, int64_t value, bool external, const char * name, void * handle); 140 void __flush_stat( struct __stats_t *, const char *, void * ); 141 #else 142 static inline void __push_stat ( struct __stats_t *, int64_t, bool, const char *, void * ) {} 143 static inline void __flush_stat( struct __stats_t *, const char *, void * ) {} 144 #endif 121 145 #endif 122 146 -
libcfa/src/concurrency/thread.cfa
r0effb6a r47e000c 62 62 } 63 63 64 FORALL_DATA_INSTANCE(ThreadCancelled, (thread_t &), (thread_t)) 64 EHM_VIRTUAL_TABLE(SomeThreadCancelled, std_thread_cancelled); 65 65 66 66 forall(T &) … … 73 73 forall(T &) 74 74 const char * msg(ThreadCancelled(T) *) { 75 return "ThreadCancelled ";75 return "ThreadCancelled(...)"; 76 76 } 77 77 78 78 forall(T &) 79 79 static void default_thread_cancel_handler(ThreadCancelled(T) & ) { 80 // Improve this error message, can I do formatting? 80 81 abort( "Unhandled thread cancellation.\n" ); 81 82 } 82 83 83 forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T))) 84 static void default_thread_cancel_handler(SomeThreadCancelled & ) { 85 // Improve this error message, can I do formatting? 86 abort( "Unhandled thread cancellation.\n" ); 87 } 88 89 forall(T & | is_thread(T) | IS_EXCEPTION(SomeThreadCancelled)) 84 90 void ?{}( thread_dtor_guard_t & this, 85 T & thrd, void(*cancelHandler)( ThreadCancelled(T)&)) {86 91 T & thrd, void(*cancelHandler)(SomeThreadCancelled &)) { 92 $monitor * m = get_monitor(thrd); 87 93 $thread * desc = get_thread(thrd); 88 94 89 95 // Setup the monitor guard 90 96 void (*dtor)(T& mutex this) = ^?{}; 91 bool join = cancelHandler != (void(*)( ThreadCancelled(T)&))0;97 bool join = cancelHandler != (void(*)(SomeThreadCancelled&))0; 92 98 (this.mg){&m, (void(*)())dtor, join}; 93 99 … … 103 109 } 104 110 desc->state = Cancelled; 105 void(*defaultResumptionHandler)( ThreadCancelled(T) &) =111 void(*defaultResumptionHandler)(SomeThreadCancelled &) = 106 112 join ? cancelHandler : default_thread_cancel_handler; 107 113 108 ThreadCancelled(T) except;109 114 // TODO: Remove explitate vtable set once trac#186 is fixed. 110 except.virtual_table = &get_exception_vtable(&except); 115 SomeThreadCancelled except; 116 except.virtual_table = &std_thread_cancelled; 111 117 except.the_thread = &thrd; 112 118 except.the_exception = __cfaehm_cancellation_exception( cancellation ); 113 throwResume except; 119 // Why is this cast required? 120 throwResume (SomeThreadCancelled &)except; 114 121 115 122 except.the_exception->virtual_table->free( except.the_exception ); … … 158 165 159 166 //----------------------------------------------------------------------------- 160 forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION( ThreadCancelled, (T)))167 forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(SomeThreadCancelled)) 161 168 T & join( T & this ) { 162 169 thread_dtor_guard_t guard = { this, defaultResumptionHandler }; -
libcfa/src/concurrency/thread.hfa
r0effb6a r47e000c 32 32 }; 33 33 34 FORALL_DATA_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) ( 34 EHM_EXCEPTION(SomeThreadCancelled) ( 35 void * the_thread; 36 exception_t * the_exception; 37 ); 38 39 EHM_EXTERN_VTABLE(SomeThreadCancelled, std_thread_cancelled); 40 41 EHM_FORALL_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) ( 35 42 thread_t * the_thread; 36 43 exception_t * the_exception; … … 79 86 }; 80 87 81 forall( T & | is_thread(T) | IS_EXCEPTION( ThreadCancelled, (T)) )82 void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)( ThreadCancelled(T)&) );88 forall( T & | is_thread(T) | IS_EXCEPTION(SomeThreadCancelled) ) 89 void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(SomeThreadCancelled &) ); 83 90 void ^?{}( thread_dtor_guard_t & this ); 84 91 … … 125 132 //---------- 126 133 // join 127 forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION( ThreadCancelled, (T)) )134 forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(SomeThreadCancelled) ) 128 135 T & join( T & this ); 129 136 -
libcfa/src/exception.c
r0effb6a r47e000c 10 10 // Created On : Mon Jun 26 15:13:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 27 16:27:00 202013 // Update Count : 3 512 // Last Modified On : Wed Feb 24 13:40:00 2021 13 // Update Count : 36 14 14 // 15 15 … … 26 26 #include "concurrency/invoke.h" 27 27 #include "stdhdr/assert.h" 28 #include "virtual.h" 28 29 29 30 #if defined( __ARM_ARCH ) … … 46 47 const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643; 47 48 48 // Base exception vtable is abstract, you should not have base exceptions. 49 struct __cfaehm_base_exception_t_vtable 50 ___cfaehm_base_exception_t_vtable_instance = { 51 .parent = NULL, 52 .size = 0, 53 .copy = NULL, 54 .free = NULL, 55 .msg = NULL 49 // Base Exception type id: 50 struct __cfa__parent_vtable __cfatid_exception_t = { 51 NULL, 56 52 }; 57 53 -
libcfa/src/exception.h
r0effb6a r47e000c 10 10 // Created On : Mon Jun 26 15:11:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T ue Oct 27 14:45:00 202013 // Update Count : 1 112 // Last Modified On : Thr Apr 8 15:20:00 2021 13 // Update Count : 12 14 14 // 15 15 … … 29 29 struct __cfaehm_base_exception_t; 30 30 typedef struct __cfaehm_base_exception_t exception_t; 31 struct __cfa__parent_vtable; 31 32 struct __cfaehm_base_exception_t_vtable { 32 const struct __cfa ehm_base_exception_t_vtable * parent;33 const struct __cfa__parent_vtable * __cfavir_typeid; 33 34 size_t size; 34 35 void (*copy)(struct __cfaehm_base_exception_t *this, … … 40 41 struct __cfaehm_base_exception_t_vtable const * virtual_table; 41 42 }; 42 extern struct __cfaehm_base_exception_t_vtable 43 ___cfaehm_base_exception_t_vtable_instance; 43 extern struct __cfa__parent_vtable __cfatid_exception_t; 44 44 45 45 … … 104 104 /* The first field must be a pointer to a virtual table. 105 105 * That virtual table must be a decendent of the base exception virtual table. 106 * The virtual table must point at the prober type-id. 107 * None of these can be enforced in an assertion. 106 108 */ 107 virtualT const & get_exception_vtable(exceptT *);108 // Always returns the virtual table for this type (associated types hack).109 109 }; 110 110 -
libcfa/src/exception.hfa
r0effb6a r47e000c 10 10 // Created On : Thu Apr 7 10:25:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T ue Aug 4 16:22:00 202013 // Update Count : 312 // Last Modified On : Thr Apr 8 15:16:00 2021 13 // Update Count : 4 14 14 // 15 15 … … 18 18 // ----------------------------------------------------------------------------------------------- 19 19 20 // TRIVIAL_EXCEPTION_DECLARATION(exception_name); 21 // Declare a trivial exception, one that adds no fields or features. 22 // This will make the exception visible and may go in a .hfa or .cfa file. 23 #define TRIVIAL_EXCEPTION_DECLARATION(...) \ 24 _EXC_DISPATCH(_TRIVIAL_EXCEPTION_DECLARATION, __VA_ARGS__) 20 // EHM_EXCEPTION(exception_name)(fields...); 21 // Create an exception (a virtual structure that inherits from exception_t) 22 // with the given name and fields. 23 #define EHM_EXCEPTION(exception_name) \ 24 _EHM_TYPE_ID_STRUCT(exception_name, ); \ 25 _EHM_TYPE_ID_VALUE(exception_name, ); \ 26 _EHM_VIRTUAL_TABLE_STRUCT(exception_name, , ); \ 27 _EHM_EXCEPTION_STRUCT(exception_name, , ) 25 28 26 // TRIVIAL_EXCEPTION_INSTANCE(exception_name);27 // Create the trival exception. This must be used exactly once and should be used in a .cfa file,28 // as it creates the unique instance of the virtual table. 29 #define TRIVIAL_EXCEPTION_INSTANCE(...) _EXC_DISPATCH(_TRIVIAL_EXCEPTION_INSTANCE, __VA_ARGS__)29 // EHM_EXTERN_VTABLE(exception_name, table_name); 30 // Forward declare a virtual table called table_name for exception_name type. 31 #define EHM_EXTERN_VTABLE(exception_name, table_name) \ 32 _EHM_EXTERN_VTABLE(exception_name, , table_name) 30 33 31 // TRIVIAL_EXCEPTION(exception_name[, parent_name]); 32 // Does both of the above, a short hand if the exception is only used in one .cfa file. 33 // For legacy reasons this is the only one that official supports having a parent other than the 34 // base exception. This feature may be removed or changed. 35 #define TRIVIAL_EXCEPTION(...) \ 36 _EXC_DISPATCH(_TRIVIAL_EXCEPTION_DECLARATION, __VA_ARGS__); \ 37 _EXC_DISPATCH(_TRIVIAL_EXCEPTION_INSTANCE, __VA_ARGS__) 34 // EHM_VIRTUAL_TABLE(exception_name, table_name); 35 // Define a virtual table called table_name for exception_name type. 36 #define EHM_VIRTUAL_TABLE(exception_name, table_name) \ 37 _EHM_DEFINE_COPY(exception_name, ) \ 38 _EHM_DEFINE_MSG(exception_name, ) \ 39 _EHM_VIRTUAL_TABLE(exception_name, , table_name) 38 40 39 // FORALL_TRIVIAL_EXCEPTION(exception_name, (assertions...), (parameters...)); 40 // Forward declare a polymorphic but otherwise trivial exception type. You must provide the entire 41 // assertion list (exactly what would go in the forall clause) and parameters list (only the 42 // parameter names from the assertion list, same order and comma seperated). This should be 43 // visible where ever use the exception. This just generates the polymorphic framework, see 44 // POLY_VTABLE_DECLARATION to allow instantiations. 45 #define FORALL_TRIVIAL_EXCEPTION(exception_name, assertions, parameters) \ 46 _FORALL_TRIVIAL_EXCEPTION(exception_name, __cfaehm_base_exception_t, assertions, parameters, ) 41 // EHM_FORALL_EXCEPTION(exception_name, (assertions), (parameters))(fields...); 42 // As EHM_EXCEPTION but for polymorphic types instead of monomorphic ones. 43 // The assertions list should include all polymorphic parameters and 44 // assertions inside a parentisized list. Parameters should include all the 45 // polymorphic parameter names inside a parentisized list (same order). 46 #define EHM_FORALL_EXCEPTION(exception_name, assertions, parameters) \ 47 _EHM_TYPE_ID_STRUCT(exception_name, forall assertions); \ 48 _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall assertions, parameters); \ 49 _EHM_EXCEPTION_STRUCT(exception_name, forall assertions, parameters) 47 50 48 // FORALL_TRIVIAL_INSTANCE(exception_name, (assertions...), (parameters...)) 49 // Create the forall trivial exception. The assertion list and parameters must match. 50 // There must be exactly one use of this in a program for each exception type. This just 51 // generates the polymorphic framework, see POLY_VTABLE_INSTANCE to allow instantiations. 52 #define FORALL_TRIVIAL_INSTANCE(exception_name, assertions, parameters) \ 53 _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters) 51 // EHM_FORALL_EXTERN_VTABLE(exception_name, (arguments), table_name); 52 // As EHM_EXTERN_VTABLE but for polymorphic types instead of monomorphic ones. 53 // Arguments should be the parentisized list of polymorphic arguments. 54 #define EHM_FORALL_EXTERN_VTABLE(exception_name, arguments, table_name) \ 55 _EHM_EXTERN_VTABLE(exception_name, arguments, table_name) 54 56 55 // DATA_EXCEPTION(exception_name)(fields...); 56 // Forward declare an exception that adds fields but no features. The added fields go in the 57 // second argument list. The virtual table instance must be provided later (see VTABLE_INSTANCE). 58 #define DATA_EXCEPTION(...) _EXC_DISPATCH(_DATA_EXCEPTION, __VA_ARGS__) 57 // EHM_FORALL_VIRTUAL_TABLE(exception_name, (arguments), table_name); 58 // As EHM_VIRTUAL_TABLE but for polymorphic types instead of monomorphic ones. 59 // Arguments should be the parentisized list of polymorphic arguments. 60 #define EHM_FORALL_VIRTUAL_TABLE(exception_name, arguments, table_name) \ 61 _EHM_TYPE_ID_VALUE(exception_name, arguments); \ 62 _EHM_DEFINE_COPY(exception_name, arguments) \ 63 _EHM_DEFINE_MSG(exception_name, arguments) \ 64 _EHM_VIRTUAL_TABLE(exception_name, arguments, table_name) 59 65 60 // FORALL_DATA_EXCEPTION(exception_name, (assertions...), (parameters...))(fields...); 61 // Define a polymorphic exception that adds fields but no additional features. The assertion list 62 // and matching parameters must match. Then you can give the list of fields. This should be 63 // visible where ever you use the exception. This just generates the polymorphic framework, see 64 // POLY_VTABLE_DECLARATION to allow instantiations. 65 #define FORALL_DATA_EXCEPTION(exception_name, assertions, parameters) \ 66 _FORALL_DATA_EXCEPTION(exception_name, __cfaehm_base_exception_t, assertions, parameters, ) 66 #define EHM_TYPE_ID(exception_name) _EHM_TYPE_ID_TYPE(exception_name) 67 67 68 // FORALL_DATA_INSTANCE(exception_name, (assertions...), (parameters...)) 69 // Create a polymorphic data exception. The assertion list and parameters must match. This should 70 // appear once in each program. This just generates the polymorphic framework, see 71 // POLY_VTABLE_INSTANCE to allow instantiations. 72 #define FORALL_DATA_INSTANCE(exception_name, assertions, parameters) \ 73 _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters) 74 75 // VTABLE_DECLARATION(exception_name)([new_features...]); 76 // Declare a virtual table type for an exception with exception_name. You may also add features 77 // (fields on the virtual table) by including them in the second list. 78 #define VTABLE_DECLARATION(...) _EXC_DISPATCH(_VTABLE_DECLARATION, __VA_ARGS__) 79 80 // VTABLE_INSTANCE(exception_name)(msg [, others...]); 81 // Create the instance of the virtual table. There must be exactly one instance of a virtual table 82 // for each exception type. This fills in most of the fields of the virtual table (uses ?=? and 83 // ^?{}) but you must provide the message function and any other fields added in the declaration. 84 #define VTABLE_INSTANCE(...) _EXC_DISPATCH(_VTABLE_INSTANCE, __VA_ARGS__) 85 86 // FORALL_VTABLE_DECLARATION(exception_name, (assertions...), (parameters...))([new_features...]); 87 // Declare a polymorphic virtual table type for an exception with exception_name, the given 88 // assertions and parameters. You may also add features (fields on the virtual table). This just 89 // generates the polymorphic framework, see POLY_VTABLE_DECLARATION to allow instantiations. 90 #define FORALL_VTABLE_DECLARATION(exception_name, assertions, parameters) \ 91 _FORALL_VTABLE_DECLARATION(exception_name, __cfaehm_base_exception_t, assertions, parameters, ) 92 93 // POLY_VTABLE_DECLARATION(exception_name, types...); 94 // Declares that an instantiation for this exception exists for the given types. This should be 95 // visible anywhere you use the instantiation of the exception is used. 96 #define POLY_VTABLE_DECLARATION(exception_name, ...) \ 97 VTABLE_TYPE(exception_name)(__VA_ARGS__) const & get_exception_vtable(exception_name(__VA_ARGS__) *); \ 98 extern VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name) 99 100 // POLY_VTABLE_INSTANCE(exception_name, types...)(msg [, others...]); 101 // Creates an instantiation for the given exception for the given types. This should occur only 102 // once in the entire program. You must fill in all features, message and any others given in the 103 // initial declaration. 104 #define POLY_VTABLE_INSTANCE(exception_name, ...) \ 105 _POLY_VTABLE_INSTANCE(exception_name, __cfaehm_base_exception_t, __VA_ARGS__) 106 107 // VTABLE_TYPE(exception_name) | VTABLE_NAME(exception_name) 108 // Get the name of the vtable type or the name of the vtable instance for an exception type. 109 #define VTABLE_TYPE(exception_name) struct _GLUE2(exception_name,_vtable) 110 #define VTABLE_NAME(exception_name) _GLUE3(_,exception_name,_vtable_instance) 111 112 // VTABLE_FIELD(exception_name); 113 // FORALL_VTABLE_FIELD(exception_name, (parameters-or-types)); 114 // The declaration of the virtual table field. Should be the first declaration in a virtual type. 115 #define VTABLE_FIELD(exception_name) VTABLE_TYPE(exception_name) const * virtual_table 116 #define FORALL_VTABLE_FIELD(exception_name, parameters) \ 117 VTABLE_TYPE(exception_name) parameters const * virtual_table 118 119 // VTABLE_INIT(object_reference, exception_name); 120 // Sets a virtual table field on an object to the virtual table instance for the type. 121 #define VTABLE_INIT(this, exception_name) (this).virtual_table = &VTABLE_NAME(exception_name) 122 123 // VTABLE_ASSERTION(exception_name, (parameters...)) 124 // The assertion that there is an instantiation of the vtable for the exception and types. 125 #define VTABLE_ASSERTION(exception_name, parameters) \ 126 { VTABLE_TYPE(exception_name) parameters VTABLE_NAME(exception_name); } 68 #define EHM_MATCH_ALL __cfa__parent_vtable 127 69 128 70 // IS_EXCEPTION(exception_name [, (...parameters)]) … … 135 77 #define IS_TERMINATION_EXCEPTION(...) _IS_EXCEPTION(is_termination_exception, __VA_ARGS__, , ~) 136 78 137 // All internal helper macros begin with an underscore. 138 #define _CLOSE(...) __VA_ARGS__ } 139 #define _GLUE2(left, right) left##right 140 #define _GLUE3(left, middle, right) left##middle##right 141 #define _EXC_DISPATCH(to, ...) to(__VA_ARGS__,__cfaehm_base_exception_t,) 142 #define _UNPACK(...) __VA_ARGS__ 79 // Macros starting with a leading underscore are internal. 143 80 144 #define _TRIVIAL_EXCEPTION_DECLARATION(exception_name, parent_name, ...) \ 145 _VTABLE_DECLARATION(exception_name, parent_name)(); \ 146 struct exception_name { \ 147 VTABLE_FIELD(exception_name); \ 148 }; \ 149 void ?{}(exception_name & this); \ 150 const char * _GLUE2(exception_name,_msg)(exception_name * this) 81 // Create an exception type definition. must be tailing, can be polymorphic. 82 #define _EHM_EXCEPTION_STRUCT(exception_name, forall_clause, parameters) \ 83 forall_clause struct exception_name { \ 84 _EHM_VTABLE_TYPE(exception_name) parameters const * virtual_table; \ 85 _CLOSE 151 86 152 #define _TRIVIAL_EXCEPTION_INSTANCE(exception_name, parent_name, ...) \ 153 void ?{}(exception_name & this) { \ 154 VTABLE_INIT(this, exception_name); \ 155 } \ 156 const char * _GLUE2(exception_name,_msg)(exception_name * this) { \ 157 return #exception_name; \ 158 } \ 159 _VTABLE_INSTANCE(exception_name, parent_name,)(_GLUE2(exception_name,_msg)) 87 // Create a (possibly polymorphic) virtual table forward declaration. 88 #define _EHM_EXTERN_VTABLE(exception_name, arguments, table_name) \ 89 extern const _EHM_VTABLE_TYPE(exception_name) arguments table_name 160 90 161 #define _FORALL_TRIVIAL_EXCEPTION(exception_name, parent_name, assertions, \ 162 parameters, parent_parameters) \ 163 _FORALL_VTABLE_DECLARATION(exception_name, parent_name, assertions, \ 164 parameters, parent_parameters)(); \ 165 forall assertions struct exception_name { \ 166 FORALL_VTABLE_FIELD(exception_name, parameters); \ 167 }; \ 168 _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) 169 170 #define _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) \ 171 forall(_UNPACK assertions | \ 172 is_exception(exception_name parameters, VTABLE_TYPE(exception_name) parameters)) \ 173 void ?{}(exception_name parameters & this) 174 175 #define _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters) \ 176 _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) { \ 177 (this).virtual_table = &get_exception_vtable(&this); \ 91 // Create a (possibly polymorphic) virtual table definition. 92 #define _EHM_VIRTUAL_TABLE(exception_type, arguments, table_name) \ 93 const _EHM_VTABLE_TYPE(exception_type) arguments table_name @= { \ 94 .__cfavir_typeid : &_EHM_TYPE_ID_NAME(exception_type), \ 95 .size : sizeof(struct exception_type arguments), \ 96 .copy : copy, \ 97 .^?{} : ^?{}, \ 98 .msg : msg, \ 178 99 } 179 100 180 #define _DATA_EXCEPTION(exception_name, parent_name, ...) \ 181 _VTABLE_DECLARATION(exception_name, parent_name)(); \ 182 struct exception_name { \ 183 VTABLE_FIELD(exception_name); \ 184 _CLOSE 101 // Create a (possibly polymorphic) copy function from an assignment operator. 102 #define _EHM_DEFINE_FORALL_COPY(exception_name, forall_clause, parameters) \ 103 forall_clause void copy(exception_name parameters * this, \ 104 exception_name parameters * that) { \ 105 *this = *that; \ 106 } 185 107 186 #define _FORALL_DATA_EXCEPTION(exception_name, parent_name, \ 187 assertions, parameters, parent_parameters) \ 188 _FORALL_VTABLE_DECLARATION(exception_name, parent_name, \ 189 assertions, parameters, parent_parameters)(); \ 190 _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters); \ 191 forall assertions struct exception_name { \ 192 FORALL_VTABLE_FIELD(exception_name, parameters); \ 193 _CLOSE 108 #define _EHM_DEFINE_COPY(exception_name, arguments) \ 109 void copy(exception_name arguments * this, exception_name arguments * that) { \ 110 *this = *that; \ 111 } 194 112 195 #define _VTABLE_DECLARATION(exception_name, parent_name, ...) \ 196 struct exception_name; \ 197 VTABLE_TYPE(exception_name); \ 198 VTABLE_TYPE(exception_name) const & get_exception_vtable(exception_name *); \ 199 extern VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name); \ 200 VTABLE_TYPE(exception_name) { \ 201 VTABLE_TYPE(parent_name) const * parent; \ 202 size_t size; \ 203 void (*copy)(exception_name * this, exception_name * other); \ 204 void (*^?{})(exception_name & this); \ 205 const char * (*msg)(exception_name * this); \ 206 _CLOSE 113 // Create a (possibly polymorphic) msg function 114 #define _EHM_DEFINE_FORALL_MSG(exception_name, forall_clause, parameters) \ 115 forall_clause const char * msg(exception_name parameters * this) { \ 116 return #exception_name #parameters; \ 117 } 207 118 208 #define _VTABLE_INSTANCE(exception_name, parent_name, ...) \ 209 VTABLE_TYPE(exception_name) const & get_exception_vtable(exception_name *) { \ 210 return VTABLE_NAME(exception_name); \ 211 } \ 212 void _GLUE2(exception_name,_copy)(exception_name * this, exception_name * other) { \ 213 *this = *other; \ 214 } \ 215 VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name) @= { \ 216 &VTABLE_NAME(parent_name), sizeof(exception_name), \ 217 _GLUE2(exception_name,_copy), ^?{}, \ 218 _CLOSE 119 #define _EHM_DEFINE_MSG(exception_name, arguments) \ 120 const char * msg(exception_name arguments * this) { \ 121 return #exception_name #arguments; \ 122 } 219 123 220 #define _FORALL_VTABLE_DECLARATION(exception_name, parent_name, assertions, \ 221 parameters, parent_parameters) \ 222 forall assertions struct exception_name; \ 223 forall assertions VTABLE_TYPE(exception_name) { \ 224 VTABLE_TYPE(parent_name) parent_parameters const * parent; \ 124 // Produces the C compatable name of the virtual table type for a virtual type. 125 #define _EHM_VTABLE_TYPE(type_name) struct _GLUE2(type_name,_vtable) 126 127 // Create the vtable type for exception name. 128 #define _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall_clause, parameters) \ 129 forall_clause struct exception_name; \ 130 forall_clause _EHM_VTABLE_TYPE(exception_name) { \ 131 _EHM_TYPE_ID_TYPE(exception_name) parameters const * __cfavir_typeid; \ 225 132 size_t size; \ 226 133 void (*copy)(exception_name parameters * this, exception_name parameters * other); \ 227 134 void (*^?{})(exception_name parameters & this); \ 228 135 const char * (*msg)(exception_name parameters * this); \ 229 _CLOSE136 } 230 137 231 #define _POLY_VTABLE_INSTANCE(exception_name, parent_name, ...) \ 232 extern VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name); \ 233 VTABLE_TYPE(exception_name)(__VA_ARGS__) const & get_exception_vtable( \ 234 exception_name(__VA_ARGS__) *) { \ 235 return VTABLE_NAME(exception_name); \ 236 } \ 237 void _GLUE2(exception_name,_copy)( \ 238 exception_name(__VA_ARGS__) * this, exception_name(__VA_ARGS__) * other) { \ 239 *this = *other; \ 240 } \ 241 VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name) @= { \ 242 &VTABLE_NAME(parent_name), sizeof(exception_name(__VA_ARGS__)), \ 243 _GLUE2(exception_name,_copy), ^?{}, \ 244 _CLOSE 138 // Define the function required to satify the trait for exceptions. 139 #define _EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \ 140 forall_clause inline void mark_exception( \ 141 exception_name parameters const &, \ 142 _EHM_VTABLE_TYPE(exception_name) parameters const &) {} \ 143 144 #define _EHM_TRAIT_FUNCTION2(exception_name, forall_clause, parameters) \ 145 forall_clause _EHM_VTABLE_TYPE(exception_name) parameters const & \ 146 get_exception_vtable(exception_name parameters const & this) 147 148 #define __EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \ 149 forall_clause inline _EHM_VTABLE_TYPE(exception_name) parameters const & \ 150 get_exception_vtable(exception_name parameters const & this) { \ 151 /* This comes before the structure definition, but we know the offset. */ \ 152 /* return (_EHM_VTABLE_TYPE(exception_name) parameters const &)this; */ \ 153 assert(false); \ 154 } 155 156 // Generates a new type-id structure. This is used to mangle the name of the 157 // type-id instance so it also includes polymorphic information. Must be the 158 // direct decendent of exception_t. 159 // The second field is used to recover type information about the exception. 160 #define _EHM_TYPE_ID_STRUCT(exception_name, forall_clause) \ 161 forall_clause _EHM_TYPE_ID_TYPE(exception_name) { \ 162 __cfa__parent_vtable const * parent; \ 163 } 164 165 // Generate a new type-id value. 166 #define _EHM_TYPE_ID_VALUE(exception_name, arguments) \ 167 __attribute__(( section(".gnu.linkonce." "__cfatid_" #exception_name) )) \ 168 _EHM_TYPE_ID_TYPE(exception_name) arguments const \ 169 _EHM_TYPE_ID_NAME(exception_name) = { \ 170 &__cfatid_exception_t, \ 171 } 172 173 // _EHM_TYPE_ID_STRUCT and _EHM_TYPE_ID_VALUE are the two that would need to 174 // be updated to extend the hierarchy if we are still using macros when that 175 // is added. 176 177 // Produce the C compatable name of the type-id type for an exception type. 178 #define _EHM_TYPE_ID_TYPE(exception_name) \ 179 struct _GLUE2(__cfatid_struct_, exception_name) 180 181 // Produce the name of the instance of the type-id for an exception type. 182 #define _EHM_TYPE_ID_NAME(exception_name) _GLUE2(__cfatid_,exception_name) 245 183 246 184 #define _IS_EXCEPTION(kind, exception_name, parameters, ...) \ 247 kind(exception_name parameters, VTABLE_TYPE(exception_name) parameters) 185 kind(exception_name parameters, _EHM_VTABLE_TYPE(exception_name) parameters) 186 187 // Internal helper macros: 188 #define _CLOSE(...) __VA_ARGS__ } 189 #define _GLUE2(left, right) left##right -
libcfa/src/fstream.cfa
r0effb6a r47e000c 321 321 322 322 323 EHM_VIRTUAL_TABLE(Open_Failure, Open_Failure_main_table); 323 324 void ?{}( Open_Failure & this, ofstream & ostream ) { 324 VTABLE_INIT(this, Open_Failure);325 this.virtual_table = &Open_Failure_main_table; 325 326 this.ostream = &ostream; 326 327 this.tag = 1; 327 328 } 328 329 void ?{}( Open_Failure & this, ifstream & istream ) { 329 VTABLE_INIT(this, Open_Failure);330 this.virtual_table = &Open_Failure_main_table; 330 331 this.istream = &istream; 331 332 this.tag = 0; 332 333 } 333 const char * Open_Failure_msg(Open_Failure * this) {334 return "Open_Failure";335 }336 VTABLE_INSTANCE(Open_Failure)(Open_Failure_msg);337 334 void throwOpen_Failure( ofstream & ostream ) { 338 335 Open_Failure exc = { ostream }; -
libcfa/src/fstream.hfa
r0effb6a r47e000c 133 133 134 134 135 DATA_EXCEPTION(Open_Failure)(135 EHM_EXCEPTION(Open_Failure)( 136 136 union { 137 137 ofstream * ostream; -
libcfa/src/virtual.c
r0effb6a r47e000c 15 15 16 16 #include "virtual.h" 17 #include "assert.h" 17 18 18 19 int __cfa__is_parent( struct __cfa__parent_vtable const * parent, 19 20 struct __cfa__parent_vtable const * child ) { 21 assert( child ); 20 22 do { 21 23 if ( parent == child ) … … 28 30 void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent, 29 31 struct __cfa__parent_vtable const * const * child ) { 32 assert( child ); 30 33 return (__cfa__is_parent(parent, *child)) ? (void *)child : (void *)0; 31 34 } -
src/AST/Expr.cpp
r0effb6a r47e000c 260 260 } 261 261 262 ConstantExpr * ConstantExpr::from_string( const CodeLocation & loc, const std::string & str ) { 263 const Type * charType = new BasicType( BasicType::Char ); 264 // Adjust the length of the string for the terminator. 265 const Expr * strSize = from_ulong( loc, str.size() + 1 ); 266 const Type * strType = new ArrayType( charType, strSize, FixedLen, StaticDim ); 267 const std::string strValue = "\"" + str + "\""; 268 return new ConstantExpr( loc, strType, strValue, std::nullopt ); 269 } 270 262 271 ConstantExpr * ConstantExpr::null( const CodeLocation & loc, const Type * ptrType ) { 263 272 return new ConstantExpr{ -
src/AST/Expr.hpp
r0effb6a r47e000c 438 438 long long int intValue() const; 439 439 440 /// generates a boolean constant of the given bool440 /// Generates a boolean constant of the given bool. 441 441 static ConstantExpr * from_bool( const CodeLocation & loc, bool b ); 442 /// generates an integer constant of the given int442 /// Generates an integer constant of the given int. 443 443 static ConstantExpr * from_int( const CodeLocation & loc, int i ); 444 /// generates an integer constant of the given unsigned long int444 /// Generates an integer constant of the given unsigned long int. 445 445 static ConstantExpr * from_ulong( const CodeLocation & loc, unsigned long i ); 446 /// generates a null pointer value for the given type. void * if omitted. 446 /// Generates a string constant from the given string (char type, unquoted string). 447 static ConstantExpr * from_string( const CodeLocation & loc, const std::string & string ); 448 /// Generates a null pointer value for the given type. void * if omitted. 447 449 static ConstantExpr * null( const CodeLocation & loc, const Type * ptrType = nullptr ); 448 450 -
src/Concurrency/Keywords.cc
r0effb6a r47e000c 42 42 43 43 namespace Concurrency { 44 inline static std::string getTypeIdName( std::string const & exception_name ) { 45 return exception_name.empty() ? std::string() : Virtual::typeIdType( exception_name ); 46 } 44 47 inline static std::string getVTableName( std::string const & exception_name ) { 45 return exception_name.empty() ? std::string() : Virtual::vtableTypeName( exception_name);48 return exception_name.empty() ? std::string() : Virtual::vtableTypeName( exception_name ); 46 49 } 47 50 … … 75 78 type_name( type_name ), field_name( field_name ), getter_name( getter_name ), 76 79 context_error( context_error ), exception_name( exception_name ), 80 typeid_name( getTypeIdName( exception_name ) ), 77 81 vtable_name( getVTableName( exception_name ) ), 78 82 needs_main( needs_main ), cast_target( cast_target ) {} … … 84 88 85 89 void handle( StructDecl * ); 90 void addTypeId( StructDecl * ); 86 91 void addVtableForward( StructDecl * ); 87 92 FunctionDecl * forwardDeclare( StructDecl * ); … … 99 104 const std::string context_error; 100 105 const std::string exception_name; 106 const std::string typeid_name; 101 107 const std::string vtable_name; 102 108 bool needs_main; … … 106 112 FunctionDecl * dtor_decl = nullptr; 107 113 StructDecl * except_decl = nullptr; 114 StructDecl * typeid_decl = nullptr; 108 115 StructDecl * vtable_decl = nullptr; 109 116 }; … … 392 399 else if ( !except_decl && exception_name == decl->name && decl->body ) { 393 400 except_decl = decl; 401 } 402 else if ( !typeid_decl && typeid_name == decl->name && decl->body ) { 403 typeid_decl = decl; 394 404 } 395 405 else if ( !vtable_decl && vtable_name == decl->name && decl->body ) { … … 448 458 if( !dtor_decl ) SemanticError( decl, context_error ); 449 459 450 addVtableForward( decl ); 460 if ( !exception_name.empty() ) { 461 if( !typeid_decl ) SemanticError( decl, context_error ); 462 if( !vtable_decl ) SemanticError( decl, context_error ); 463 464 addTypeId( decl ); 465 addVtableForward( decl ); 466 } 451 467 FunctionDecl * func = forwardDeclare( decl ); 452 468 ObjectDecl * field = addField( decl ); … … 454 470 } 455 471 472 void ConcurrentSueKeyword::addTypeId( StructDecl * decl ) { 473 assert( typeid_decl ); 474 StructInstType typeid_type( Type::Const, typeid_decl ); 475 typeid_type.parameters.push_back( new TypeExpr( 476 new StructInstType( noQualifiers, decl ) 477 ) ); 478 declsToAddBefore.push_back( Virtual::makeTypeIdInstance( &typeid_type ) ); 479 } 480 456 481 void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) { 457 if ( vtable_decl ) { 458 std::list< Expression * > poly_args = { 459 new TypeExpr( new StructInstType( noQualifiers, decl ) ), 460 }; 461 declsToAddBefore.push_back( Virtual::makeGetExceptionForward( 462 vtable_decl->makeInst( poly_args ), 463 except_decl->makeInst( poly_args ) 464 ) ); 465 declsToAddBefore.push_back( Virtual::makeVtableForward( 466 vtable_decl->makeInst( move( poly_args ) ) ) ); 467 // Its only an error if we want a vtable and don't have one. 468 } else if ( ! vtable_name.empty() ) { 469 SemanticError( decl, context_error ); 470 } 482 assert( vtable_decl ); 483 std::list< Expression * > poly_args = { 484 new TypeExpr( new StructInstType( noQualifiers, decl ) ), 485 }; 486 declsToAddBefore.push_back( Virtual::makeGetExceptionForward( 487 vtable_decl->makeInst( poly_args ), 488 except_decl->makeInst( poly_args ) 489 ) ); 490 declsToAddBefore.push_back( Virtual::makeVtableForward( 491 vtable_decl->makeInst( move( poly_args ) ) ) ); 471 492 } 472 493 -
src/SynTree/Constant.cc
r0effb6a r47e000c 42 42 } 43 43 44 Constant Constant::from_string( const std::string & str ) { 45 Type * charType = new BasicType( noQualifiers, BasicType::Char ); 46 // Adjust the length of the string for the terminator. 47 Expression * strSize = new ConstantExpr( Constant::from_ulong( str.size() + 1 ) ); 48 Type * strType = new ArrayType( noQualifiers, charType, strSize, false, false ); 49 const std::string strValue = "\"" + str + "\""; 50 return Constant( strType, strValue, std::nullopt ); 51 } 52 44 53 Constant Constant::null( Type * ptrtype ) { 45 54 if ( nullptr == ptrtype ) { -
src/SynTree/Constant.h
r0effb6a r47e000c 47 47 /// generates an integer constant of the given unsigned long int 48 48 static Constant from_ulong( unsigned long i ); 49 /// generates a string constant from the given string (char type, unquoted string) 50 static Constant from_string( const std::string & string ); 49 51 50 52 /// generates a null pointer value for the given type. void * if omitted. -
src/Virtual/ExpandCasts.cc
r0effb6a r47e000c 32 32 namespace Virtual { 33 33 34 static bool is_prefix( const std::string & prefix, const std::string& entire ) { 35 size_t const p_size = prefix.size(); 36 return (p_size < entire.size() && prefix == entire.substr(0, p_size)); 37 } 38 39 static bool is_type_id_object( const ObjectDecl * objectDecl ) { 40 const std::string & objectName = objectDecl->name; 41 return is_prefix( "__cfatid_", objectName ); 42 } 43 34 44 // Indented until the new ast code gets added. 35 45 … … 66 76 }; 67 77 68 /* Currently virtual depends on the rather brittle name matching between69 * a (strict/explicate) virtual type, its vtable type and the vtable70 * instance.71 * A stronger implementation, would probably keep track of those triads72 * and use that information to create better error messages.73 */74 75 namespace {76 77 std::string get_vtable_name( std::string const & name ) {78 return name + "_vtable";79 }80 81 std::string get_vtable_inst_name( std::string const & name ) {82 return std::string("_") + get_vtable_name( name ) + "_instance";83 }84 85 std::string get_vtable_name_root( std::string const & name ) {86 return name.substr(0, name.size() - 7 );87 }88 89 std::string get_vtable_inst_name_root( std::string const & name ) {90 return get_vtable_name_root( name.substr(1, name.size() - 10 ) );91 }92 93 bool is_vtable_inst_name( std::string const & name ) {94 return 17 < name.size() &&95 name == get_vtable_inst_name( get_vtable_inst_name_root( name ) );96 }97 98 } // namespace99 100 78 class VirtualCastCore { 101 Type * pointer_to_pvt(int level_of_indirection) {79 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) { 102 80 Type * type = new StructInstType( 103 81 Type::Qualifiers( Type::Const ), pvt_decl ); … … 105 83 type = new PointerType( noQualifiers, type ); 106 84 } 107 return type;85 return new CastExpr( expr, type ); 108 86 } 109 87 … … 141 119 142 120 void VirtualCastCore::premutate( ObjectDecl * objectDecl ) { 143 if ( is_vtable_inst_name( objectDecl->get_name() ) ) { 144 if ( ObjectDecl * existing = indexer.insert( objectDecl ) ) { 145 std::string msg = "Repeated instance of virtual table, original found at: "; 146 msg += existing->location.filename; 147 msg += ":" + toString( existing->location.first_line ); 148 SemanticError( objectDecl->location, msg ); 149 } 121 if ( is_type_id_object( objectDecl ) ) { 122 // Multiple definitions should be fine because of linkonce. 123 indexer.insert( objectDecl ); 150 124 } 151 125 } … … 170 144 } 171 145 172 /// Get the virtual table type used in a virtual cast. 173 Type * getVirtualTableType( const VirtualCastExpr * castExpr ) { 174 const Type * objectType; 175 if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) { 176 objectType = target->base; 177 } else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) { 178 objectType = target->base; 146 /// Get the base type from a pointer or reference. 147 const Type * getBaseType( const Type * type ) { 148 if ( auto target = dynamic_cast<const PointerType *>( type ) ) { 149 return target->base; 150 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) { 151 return target->base; 179 152 } else { 180 castError( castExpr, "Virtual cast type must be a pointer or reference type." ); 181 } 182 assert( objectType ); 183 184 const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType ); 185 if ( nullptr == structType ) { 186 castError( castExpr, "Virtual cast type must refer to a structure type." ); 187 } 188 const StructDecl * structDecl = structType->baseStruct; 189 assert( structDecl ); 190 191 const ObjectDecl * fieldDecl = nullptr; 192 if ( 0 < structDecl->members.size() ) { 193 const Declaration * memberDecl = structDecl->members.front(); 153 return nullptr; 154 } 155 } 156 157 /* Attempt to follow the "head" field of the structure to get the... 158 * Returns nullptr on error, otherwise owner must free returned node. 159 */ 160 StructInstType * followHeadPointerType( 161 const StructInstType * oldType, 162 const std::string& fieldName, 163 const CodeLocation& errorLocation ) { 164 165 // First section of the function is all about trying to fill this variable in. 166 StructInstType * newType = nullptr; 167 { 168 const StructDecl * oldDecl = oldType->baseStruct; 169 assert( oldDecl ); 170 171 // Helper function for throwing semantic errors. 172 auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) { 173 const std::string& context = "While following head pointer of " + 174 oldDecl->name + " named '" + fieldName + "': "; 175 SemanticError( errorLocation, context + message ); 176 }; 177 178 if ( oldDecl->members.empty() ) { 179 throwError( "Type has no fields." ); 180 } 181 const Declaration * memberDecl = oldDecl->members.front(); 194 182 assert( memberDecl ); 195 fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl ); 196 if ( fieldDecl && fieldDecl->name != "virtual_table" ) { 197 fieldDecl = nullptr; 198 } 199 } 200 if ( nullptr == fieldDecl ) { 201 castError( castExpr, "Virtual cast type must have a leading virtual_table field." ); 202 } 203 const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type ); 204 if ( nullptr == fieldType ) { 205 castError( castExpr, "Virtual cast type virtual_table field is not a pointer." ); 206 } 207 assert( fieldType->base ); 208 auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base ); 209 assert( virtualStructType ); 210 211 // Here is the type, but if it is polymorphic it will have lost information. 212 // (Always a clone so that it may always be deleted.) 213 StructInstType * virtualType = virtualStructType->clone(); 214 if ( ! structType->parameters.empty() ) { 215 deleteAll( virtualType->parameters ); 216 virtualType->parameters.clear(); 217 cloneAll( structType->parameters, virtualType->parameters ); 218 } 219 return virtualType; 183 const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl ); 184 assert( fieldDecl ); 185 if ( fieldName != fieldDecl->name ) { 186 throwError( "Head field did not have expected name." ); 187 } 188 189 const Type * fieldType = fieldDecl->type; 190 if ( nullptr == fieldType ) { 191 throwError( "Could not get head field." ); 192 } 193 const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType ); 194 if ( nullptr == ptrType ) { 195 throwError( "First field is not a pointer type." ); 196 } 197 assert( ptrType->base ); 198 newType = dynamic_cast<StructInstType *>( ptrType->base ); 199 if ( nullptr == newType ) { 200 throwError( "First field does not point to a structure type." ); 201 } 202 } 203 204 // Now we can look into copying it. 205 newType = newType->clone(); 206 if ( ! oldType->parameters.empty() ) { 207 deleteAll( newType->parameters ); 208 newType->parameters.clear(); 209 cloneAll( oldType->parameters, newType->parameters ); 210 } 211 return newType; 212 } 213 214 /// Get the type-id type from a virtual type. 215 StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) { 216 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type ); 217 if ( nullptr == typeInst ) { 218 return nullptr; 219 } 220 StructInstType * tableInst = 221 followHeadPointerType( typeInst, "virtual_table", errorLocation ); 222 if ( nullptr == tableInst ) { 223 return nullptr; 224 } 225 StructInstType * typeIdInst = 226 followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation ); 227 delete tableInst; 228 return typeIdInst; 220 229 } 221 230 … … 228 237 assert( pvt_decl ); 229 238 230 const Type * vtable_type = getVirtualTableType( castExpr ); 231 ObjectDecl * table = indexer.lookup( vtable_type ); 232 if ( nullptr == table ) { 233 SemanticError( castLocation( castExpr ), 234 "Could not find virtual table instance." ); 239 const Type * base_type = getBaseType( castExpr->result ); 240 if ( nullptr == base_type ) { 241 castError( castExpr, "Virtual cast target must be a pointer or reference type." ); 242 } 243 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) ); 244 if ( nullptr == type_id_type ) { 245 castError( castExpr, "Ill formed virtual cast target type." ); 246 } 247 ObjectDecl * type_id = indexer.lookup( type_id_type ); 248 delete type_id_type; 249 if ( nullptr == type_id ) { 250 castError( castExpr, "Virtual cast does not target a virtual type." ); 235 251 } 236 252 237 253 Expression * result = new CastExpr( 238 254 new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), { 239 new CastExpr( 240 new AddressExpr( new VariableExpr( table ) ), 241 pointer_to_pvt(1) 242 ), 243 new CastExpr( 244 castExpr->get_arg(), 245 pointer_to_pvt(2) 246 ) 255 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ), 256 cast_to_type_id( castExpr->get_arg(), 2 ), 247 257 } ), 248 258 castExpr->get_result()->clone() … … 252 262 castExpr->set_result( nullptr ); 253 263 delete castExpr; 254 delete vtable_type;255 264 return result; 256 265 } -
src/Virtual/Tables.cc
r0effb6a r47e000c 10 10 // Created On : Mon Aug 31 11:11:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T ue Sep 3 14:56:00 202013 // Update Count : 012 // Last Modified On : Thr Apr 8 15:51:00 2021 13 // Update Count : 1 14 14 // 15 15 … … 22 22 namespace Virtual { 23 23 24 std::string typeIdType( std::string const & type_name ) { 25 return "__cfatid_struct_" + type_name; 26 } 27 28 std::string typeIdName( std::string const & type_name ) { 29 return "__cfatid_" + type_name; 30 } 31 32 static std::string typeIdTypeToInstance( std::string const & type_name ) { 33 return typeIdName(type_name.substr(16)); 34 } 35 24 36 std::string vtableTypeName( std::string const & name ) { 25 37 return name + "_vtable"; 38 } 39 40 std::string baseTypeName( std::string const & vtable_type_name ) { 41 return vtable_type_name.substr(0, vtable_type_name.size() - 7); 26 42 } 27 43 … … 81 97 inits.push_back( 82 98 new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) ); 99 } else if ( std::string( "__cfavir_typeid" ) == field->name ) { 100 std::string const & baseType = baseTypeName( vtableType->name ); 101 std::string const & typeId = typeIdName( baseType ); 102 inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) ); 83 103 } else if ( std::string( "size" ) == field->name ) { 84 104 inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) ); … … 147 167 } 148 168 169 ObjectDecl * makeTypeIdForward() { 170 return nullptr; 149 171 } 172 173 Attribute * linkonce( const std::string & subsection ) { 174 const std::string section = ".gnu.linkonce." + subsection; 175 return new Attribute( "section", { 176 new ConstantExpr( Constant::from_string( section ) ), 177 } ); 178 } 179 180 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) { 181 assert( typeIdType ); 182 StructInstType * type = typeIdType->clone(); 183 type->tq.is_const = true; 184 std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name ); 185 return new ObjectDecl( 186 typeid_name, 187 noStorageClasses, 188 LinkageSpec::Cforall, 189 /* bitfieldWidth */ nullptr, 190 type, 191 new ListInit( { new SingleInit( 192 new AddressExpr( new NameExpr( "__cfatid_exception_t" ) ) 193 ) } ), 194 { linkonce( typeid_name ) }, 195 noFuncSpecifiers 196 ); 197 } 198 199 } -
src/Virtual/Tables.h
r0effb6a r47e000c 10 10 // Created On : Mon Aug 31 11:07:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T ue Sep 1 14:29:00 202013 // Update Count : 012 // Last Modified On : Thr Apr 8 15:55:00 2021 13 // Update Count : 1 14 14 // 15 15 … … 22 22 namespace Virtual { 23 23 24 std::string typeIdType( std::string const & type_name ); 25 std::string typeIdName( std::string const & type_name ); 24 26 std::string vtableTypeName( std::string const & type_name ); 25 27 std::string instanceName( std::string const & vtable_name ); … … 50 52 */ 51 53 54 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ); 55 /* Build an instance of the type-id from the type of the type-id. 56 * TODO: Should take the parent type. Currently locked to the exception_t. 57 */ 58 52 59 } -
tests/exceptions/.expect/resume-threads.txt
r0effb6a r47e000c 6 6 7 7 catch-all 8 9 throwing child exception10 inner parent match11 8 12 9 caught yin as yin -
tests/exceptions/.expect/resume.txt
r0effb6a r47e000c 6 6 7 7 catch-all 8 9 throwing child exception10 inner parent match11 8 12 9 caught yin as yin -
tests/exceptions/.expect/terminate-threads.txt
r0effb6a r47e000c 5 5 6 6 catch-all 7 8 throwing child exception9 inner parent match10 7 11 8 caught yin as yin -
tests/exceptions/.expect/terminate.txt
r0effb6a r47e000c 5 5 6 6 catch-all 7 8 throwing child exception9 inner parent match10 7 11 8 caught yin as yin -
tests/exceptions/cancel/coroutine.cfa
r0effb6a r47e000c 4 4 #include <exception.hfa> 5 5 6 TRIVIAL_EXCEPTION(internal_error); 6 EHM_EXCEPTION(internal_error)(); 7 EHM_VIRTUAL_TABLE(internal_error, internal_vt); 7 8 8 9 coroutine WillCancel {}; … … 14 15 void main(WillCancel & wc) { 15 16 printf("1"); 16 cancel_stack((internal_error){ });17 cancel_stack((internal_error){&internal_vt}); 17 18 printf("!"); 18 19 } … … 24 25 resume(cancel); 25 26 printf("4"); 26 } catchResume ( CoroutineCancelled(WillCancel)* error) {27 } catchResume (SomeCoroutineCancelled * error) { 27 28 printf("2"); 28 29 if ((virtual internal_error *)error->the_exception) { -
tests/exceptions/cancel/thread.cfa
r0effb6a r47e000c 4 4 #include <exception.hfa> 5 5 6 TRIVIAL_EXCEPTION(internal_error); 6 EHM_EXCEPTION(internal_error)(); 7 EHM_VIRTUAL_TABLE(internal_error, internal_vt); 7 8 8 9 thread WillCancel {}; … … 14 15 void main(WillCancel &) { 15 16 printf("1"); 16 cancel_stack((internal_error){ });17 cancel_stack((internal_error){&internal_vt}); 17 18 printf("!"); 18 19 } … … 25 26 join(cancel); 26 27 printf("4"); 27 } catchResume ( ThreadCancelled(WillCancel)* error) {28 } catchResume (SomeThreadCancelled * error) { 28 29 printf("2"); 29 30 if ((virtual internal_error *)error->the_exception) { … … 42 43 } 43 44 printf("4"); 44 } catchResume ( ThreadCancelled(WillCancel)* error) {45 } catchResume (SomeThreadCancelled * error) { 45 46 printf("2"); 46 47 if ((virtual internal_error *)error->the_exception) { -
tests/exceptions/conditional.cfa
r0effb6a r47e000c 6 6 #include <exception.hfa> 7 7 8 VTABLE_DECLARATION(num_error)(9 int (*code)(num_error *this);8 EHM_EXCEPTION(num_error)( 9 int num; 10 10 ); 11 11 12 struct num_error { 13 VTABLE_FIELD(num_error); 14 char * msg; 15 int num; 16 }; 17 18 const char * num_error_msg(num_error * this) { 19 if ( ! this->msg ) { 20 static const char * base = "Num Error with code: X"; 21 this->msg = (char *)malloc(22); 22 for (int i = 0 ; (this->msg[i] = base[i]) ; ++i); 23 } 24 this->msg[21] = '0' + this->num; 25 return this->msg; 26 } 27 void ?{}(num_error & this, int num) { 28 VTABLE_INIT(this, num_error); 29 this.msg = 0; 30 this.num = num; 31 } 32 void ?{}(num_error & this, num_error & other) { 33 this.virtual_table = other.virtual_table; 34 this.msg = 0; 35 this.num = other.num; 36 } 37 void ^?{}(num_error & this) { 38 if( this.msg ) free( this.msg ); 39 } 40 int num_error_code( num_error * this ) { 41 return this->num; 42 } 43 44 VTABLE_INSTANCE(num_error)( 45 num_error_msg, 46 num_error_code, 47 ); 12 EHM_VIRTUAL_TABLE(num_error, num_error_vt); 48 13 49 14 void caught_num_error(int expect, num_error * actual) { … … 52 17 53 18 int main(int argc, char * argv[]) { 54 num_error exc = 2;19 num_error exc = {&num_error_vt, 2}; 55 20 56 21 try { 57 22 throw exc; 58 } catch (num_error * error ; 3 == error-> virtual_table->code( error )) {23 } catch (num_error * error ; 3 == error->num ) { 59 24 caught_num_error(3, error); 60 } catch (num_error * error ; 2 == error-> virtual_table->code( error )) {25 } catch (num_error * error ; 2 == error->num ) { 61 26 caught_num_error(2, error); 62 27 } … … 64 29 try { 65 30 throwResume exc; 66 } catchResume (num_error * error ; 3 == error-> virtual_table->code( error )) {31 } catchResume (num_error * error ; 3 == error->num ) { 67 32 caught_num_error(3, error); 68 } catchResume (num_error * error ; 2 == error-> virtual_table->code( error )) {33 } catchResume (num_error * error ; 2 == error->num ) { 69 34 caught_num_error(2, error); 70 35 } -
tests/exceptions/data-except.cfa
r0effb6a r47e000c 3 3 #include <exception.hfa> 4 4 5 DATA_EXCEPTION(paired)(5 EHM_EXCEPTION(paired)( 6 6 int first; 7 7 int second; 8 8 ); 9 9 10 void ?{}(paired & this, int first, int second) { 11 VTABLE_INIT(this, paired); 12 this.first = first; 13 this.second = second; 14 } 10 EHM_VIRTUAL_TABLE(paired, paired_vt); 15 11 16 const char * paired_msg(paired * this) { 17 return "paired"; 18 } 19 20 VTABLE_INSTANCE(paired)(paired_msg); 21 22 void throwPaired(int first, int second) { 23 paired exc = {first, second}; 12 const char * virtual_msg(paired * this) { 13 return this->virtual_table->msg(this); 24 14 } 25 15 26 16 int main(int argc, char * argv[]) { 27 paired except = { 3, 13};17 paired except = {&paired_vt, 3, 13}; 28 18 29 19 try { 30 20 throw except; 31 21 } catch (paired * exc) { 32 printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second);22 printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second); 33 23 ++exc->first; 34 24 } 35 25 36 printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second);26 printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second); 37 27 38 28 try { 39 29 throwResume except; 40 30 } catchResume (paired * exc) { 41 printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second);31 printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second); 42 32 ++exc->first; 43 33 } 44 34 45 printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second);35 printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second); 46 36 } -
tests/exceptions/defaults.cfa
r0effb6a r47e000c 4 4 #include <exception.hfa> 5 5 6 DATA_EXCEPTION(log_message)(6 EHM_EXCEPTION(log_message)( 7 7 char * msg; 8 8 ); 9 9 10 void ?{}(log_message & this, char * msg) { 11 VTABLE_INIT(this, log_message); 12 this.msg = msg; 13 } 14 15 const char * get_log_message(log_message * this) { 10 _EHM_DEFINE_COPY(log_message, ) 11 const char * msg(log_message * this) { 16 12 return this->msg; 17 13 } 18 19 VTABLE_INSTANCE(log_message)(get_log_message); 14 _EHM_VIRTUAL_TABLE(log_message, , log_vt); 20 15 21 16 // Logging messages don't have to be handled. … … 28 23 // We can catch log: 29 24 try { 30 throwResume (log_message){ "Should be printed.\n"};25 throwResume (log_message){&log_vt, "Should be printed.\n"}; 31 26 } catchResume (log_message * this) { 32 27 printf("%s", this->virtual_table->msg(this)); 33 28 } 34 29 // But we don't have to: 35 throwResume (log_message){ "Should not be printed.\n"};30 throwResume (log_message){&log_vt, "Should not be printed.\n"}; 36 31 } 37 32 38 33 // I don't have a good use case for doing the same with termination. 39 TRIVIAL_EXCEPTION(jump);34 EHM_EXCEPTION(jump)(); 40 35 void defaultTerminationHandler(jump &) { 41 36 printf("jump default handler.\n"); 42 37 } 43 38 39 EHM_VIRTUAL_TABLE(jump, jump_vt); 40 44 41 void jump_test(void) { 45 42 try { 46 throw (jump){ };43 throw (jump){&jump_vt}; 47 44 } catch (jump * this) { 48 45 printf("jump catch handler.\n"); 49 46 } 50 throw (jump){ };47 throw (jump){&jump_vt}; 51 48 } 52 49 53 TRIVIAL_EXCEPTION(first); 54 TRIVIAL_EXCEPTION(unhandled_exception); 50 EHM_EXCEPTION(first)(); 51 EHM_VIRTUAL_TABLE(first, first_vt); 52 53 EHM_EXCEPTION(unhandled_exception)(); 54 EHM_VIRTUAL_TABLE(unhandled_exception, unhandled_vt); 55 55 56 56 void unhandled_test(void) { 57 57 forall(T &, V & | is_exception(T, V)) 58 58 void defaultTerminationHandler(T &) { 59 throw (unhandled_exception){ };59 throw (unhandled_exception){&unhandled_vt}; 60 60 } 61 61 void defaultTerminationHandler(unhandled_exception &) { … … 63 63 } 64 64 try { 65 throw (first){ };65 throw (first){&first_vt}; 66 66 } catch (unhandled_exception * t) { 67 67 printf("Catch unhandled_exception.\n"); … … 69 69 } 70 70 71 TRIVIAL_EXCEPTION(second); 71 EHM_EXCEPTION(second)(); 72 EHM_VIRTUAL_TABLE(second, second_vt); 72 73 73 74 void cross_test(void) { 74 75 void defaultTerminationHandler(first &) { 75 76 printf("cross terminate default\n"); 76 throw (second){ };77 throw (second){&second_vt}; 77 78 } 78 79 void defaultResumptionHandler(first &) { 79 80 printf("cross resume default\n"); 80 throwResume (second){ };81 throwResume (second){&second_vt}; 81 82 } 82 83 try { 83 84 printf("cross terminate throw\n"); 84 throw (first){ };85 throw (first){&first_vt}; 85 86 } catch (second *) { 86 87 printf("cross terminate catch\n"); … … 88 89 try { 89 90 printf("cross resume throw\n"); 90 throwResume (first){ };91 throwResume (first){&first_vt}; 91 92 } catchResume (second *) { 92 93 printf("cross resume catch\n"); -
tests/exceptions/finally.cfa
r0effb6a r47e000c 4 4 #include "except-io.hfa" 5 5 6 TRIVIAL_EXCEPTION(myth); 6 EHM_EXCEPTION(myth)(); 7 8 EHM_VIRTUAL_TABLE(myth, myth_vt); 7 9 8 10 int main(int argc, char * argv[]) { 9 myth exc ;11 myth exc = {&myth_vt}; 10 12 11 13 try { -
tests/exceptions/interact.cfa
r0effb6a r47e000c 4 4 #include "except-io.hfa" 5 5 6 TRIVIAL_EXCEPTION(star); 7 TRIVIAL_EXCEPTION(moon); 6 EHM_EXCEPTION(star)(); 7 EHM_EXCEPTION(moon)(); 8 9 EHM_VIRTUAL_TABLE(star, star_vt); 10 EHM_VIRTUAL_TABLE(moon, moon_vt); 8 11 9 12 int main(int argc, char * argv[]) { 10 13 // Resume falls back to terminate. 11 14 try { 12 throwResume (star){ };15 throwResume (star){&star_vt}; 13 16 } catch (star *) { 14 17 printf("caught as termination\n"); … … 17 20 try { 18 21 loud_region a = "try block with resume throw"; 19 throwResume (star){ };22 throwResume (star){&star_vt}; 20 23 } catch (star *) { 21 24 printf("caught as termination\n"); … … 29 32 try { 30 33 try { 31 throw (star){ };34 throw (star){&star_vt}; 32 35 } catchResume (star *) { 33 36 printf("resume catch on terminate\n"); … … 43 46 try { 44 47 try { 45 throwResume (star){ };48 throwResume (star){&star_vt}; 46 49 } catch (star *) { 47 50 printf("terminate catch on resume\n"); … … 58 61 try { 59 62 try { 60 throw (star){ };63 throw (star){&star_vt}; 61 64 } catchResume (star *) { 62 65 printf("inner resume catch (error)\n"); … … 75 78 try { 76 79 try { 77 throwResume (star){ };80 throwResume (star){&star_vt}; 78 81 } catch (star *) { 79 82 printf("inner termination catch\n"); … … 94 97 try { 95 98 printf("throwing resume moon\n"); 96 throwResume (moon){ };99 throwResume (moon){&moon_vt}; 97 100 } catch (star *) { 98 101 printf("termination catch\n"); 99 102 } 100 103 printf("throwing resume star\n"); 101 throwResume (star){ };104 throwResume (star){&star_vt}; 102 105 } catchResume (star *) { 103 106 printf("resumption star catch\n"); … … 105 108 } catchResume (moon *) { 106 109 printf("resumption moon catch, will terminate\n"); 107 throw (star){ };110 throw (star){&star_vt}; 108 111 } 109 112 } catchResume (star *) { -
tests/exceptions/polymorphic.cfa
r0effb6a r47e000c 3 3 #include <exception.hfa> 4 4 5 FORALL_TRIVIAL_EXCEPTION(proxy, (T), (T)); 6 FORALL_TRIVIAL_INSTANCE(proxy, (U), (U)) 5 EHM_FORALL_EXCEPTION(proxy, (T&), (T))(); 7 6 8 const char * msg(proxy(int) * this) { return "proxy(int)"; } 9 const char * msg(proxy(char) * this) { return "proxy(char)"; } 10 POLY_VTABLE_INSTANCE(proxy, int)(msg); 11 POLY_VTABLE_INSTANCE(proxy, char)(msg); 7 EHM_FORALL_VIRTUAL_TABLE(proxy, (int), proxy_int); 8 EHM_FORALL_VIRTUAL_TABLE(proxy, (char), proxy_char); 12 9 13 10 void proxy_test(void) { 11 proxy(int) an_int = {&proxy_int}; 12 proxy(char) a_char = {&proxy_char}; 13 14 14 try { 15 throw (proxy(int)){};15 throw an_int; 16 16 } catch (proxy(int) *) { 17 17 printf("terminate catch\n"); … … 19 19 20 20 try { 21 throwResume (proxy(char)){};21 throwResume a_char; 22 22 } catchResume (proxy(char) *) { 23 23 printf("resume catch\n"); … … 25 25 26 26 try { 27 throw (proxy(char)){};27 throw a_char; 28 28 } catch (proxy(int) *) { 29 29 printf("caught proxy(int)\n"); … … 33 33 } 34 34 35 FORALL_DATA_EXCEPTION(cell, (T), (T))(35 EHM_FORALL_EXCEPTION(cell, (T), (T))( 36 36 T data; 37 37 ); 38 38 39 FORALL_DATA_INSTANCE(cell, (T), (T)) 40 41 const char * msg(cell(int) * this) { return "cell(int)"; } 42 const char * msg(cell(char) * this) { return "cell(char)"; } 43 const char * msg(cell(bool) * this) { return "cell(bool)"; } 44 POLY_VTABLE_INSTANCE(cell, int)(msg); 45 POLY_VTABLE_INSTANCE(cell, char)(msg); 46 POLY_VTABLE_INSTANCE(cell, bool)(msg); 39 EHM_FORALL_VIRTUAL_TABLE(cell, (int), int_cell); 40 EHM_FORALL_VIRTUAL_TABLE(cell, (char), char_cell); 41 EHM_FORALL_VIRTUAL_TABLE(cell, (bool), bool_cell); 47 42 48 43 void cell_test(void) { 49 44 try { 50 cell(int) except; 51 except.data = -7; 45 cell(int) except = {&int_cell, -7}; 52 46 throw except; 53 47 } catch (cell(int) * error) { … … 56 50 57 51 try { 58 cell(bool) ball; 59 ball.data = false; 52 cell(bool) ball = {&bool_cell, false}; 60 53 throwResume ball; 61 54 printf("%i\n", ball.data); -
tests/exceptions/resume.cfa
r0effb6a r47e000c 4 4 #include "except-io.hfa" 5 5 6 TRIVIAL_EXCEPTION(yin); 7 TRIVIAL_EXCEPTION(yang); 8 TRIVIAL_EXCEPTION(zen); 9 TRIVIAL_EXCEPTION(moment_of, zen); 6 EHM_EXCEPTION(yin)(); 7 EHM_EXCEPTION(yang)(); 8 EHM_EXCEPTION(zen)(); 9 10 EHM_VIRTUAL_TABLE(yin, yin_vt); 11 EHM_VIRTUAL_TABLE(yang, yang_vt); 12 EHM_VIRTUAL_TABLE(zen, zen_vt); 10 13 11 14 void in_void(void); 12 15 13 16 int main(int argc, char * argv[]) { 17 yin a_yin = {&yin_vt}; 18 yang a_yang = {&yang_vt}; 19 zen a_zen = {&zen_vt}; 20 14 21 // The simple throw catchResume test. 15 22 try { 16 23 loud_exit a = "simple try clause"; 17 24 printf("simple throw\n"); 18 throwResume (zen){};25 throwResume a_zen; 19 26 printf("end of try clause\n"); 20 27 } catchResume (zen * error) { … … 26 33 // Throw catch-all test. 27 34 try { 28 throwResume (zen){};35 throwResume a_zen; 29 36 } catchResume (exception_t * error) { 30 37 printf("catch-all\n"); 31 }32 printf("\n");33 34 // Catch a parent of the given exception.35 try {36 printf("throwing child exception\n");37 throwResume (moment_of){};38 } catchResume (zen *) {39 printf("inner parent match\n");40 } catchResume (moment_of *) {41 printf("outer exact match\n");42 38 } 43 39 printf("\n"); … … 46 42 try { 47 43 try { 48 throwResume (yin){};44 throwResume a_yin; 49 45 } catchResume (zen *) { 50 46 printf("caught yin as zen\n"); … … 62 58 loud_exit a = "rethrow inner try"; 63 59 printf("rethrow inner try\n"); 64 throwResume (zen){};60 throwResume a_zen; 65 61 } catchResume (zen *) { 66 62 loud_exit a = "rethrowing catch clause"; … … 77 73 try { 78 74 try { 79 throwResume (yin){};75 throwResume a_yin; 80 76 } catchResume (yin *) { 81 77 printf("caught yin, will throw yang\n"); 82 throwResume (yang){};78 throwResume a_yang; 83 79 } catchResume (yang *) { 84 80 printf("caught exception from same try\n"); … … 93 89 try { 94 90 printf("throwing first exception\n"); 95 throwResume (yin){};91 throwResume a_yin; 96 92 } catchResume (yin *) { 97 93 printf("caught first exception\n"); 98 94 try { 99 95 printf("throwing second exception\n"); 100 throwResume (yang){};96 throwResume a_yang; 101 97 } catchResume (yang *) { 102 98 printf("caught second exception\n"); … … 114 110 try { 115 111 try { 116 throwResume (zen){};117 throwResume (zen){};112 throwResume a_zen; 113 throwResume a_zen; 118 114 } catchResume (zen *) { 119 115 printf("inner catch\n"); 120 116 } 121 throwResume (zen){};117 throwResume a_zen; 122 118 } catchResume (zen *) { 123 119 printf("outer catch\n"); … … 130 126 // Do a throw and rethrow in a void function. 131 127 void in_void(void) { 128 zen a_zen = {&zen_vt}; 132 129 try { 133 130 try { 134 131 printf("throw\n"); 135 throwResume (zen){};132 throwResume a_zen; 136 133 } catchResume (zen *) { 137 134 printf("rethrow\n"); -
tests/exceptions/terminate.cfa
r0effb6a r47e000c 4 4 #include "except-io.hfa" 5 5 6 TRIVIAL_EXCEPTION(yin); 7 TRIVIAL_EXCEPTION(yang); 8 TRIVIAL_EXCEPTION(zen); 9 TRIVIAL_EXCEPTION(moment_of, zen); 6 EHM_EXCEPTION(yin)(); 7 EHM_EXCEPTION(yang)(); 8 EHM_EXCEPTION(zen)(); 9 10 EHM_VIRTUAL_TABLE(yin, yin_vt); 11 EHM_VIRTUAL_TABLE(yang, yang_vt); 12 EHM_VIRTUAL_TABLE(zen, zen_vt); 10 13 11 14 void in_void(void); 12 15 13 16 int main(int argc, char * argv[]) { 17 yin a_yin = {&yin_vt}; 18 yang a_yang = {&yang_vt}; 19 zen a_zen = {&zen_vt}; 20 14 21 // The simple throw catch test. 15 22 try { 16 23 loud_exit a = "simple try clause"; 17 24 printf("simple throw\n"); 18 throw (zen){};25 throw a_zen; 19 26 printf("end of try clause\n"); 20 27 } catch (zen * error) { … … 26 33 // Throw catch-all test. 27 34 try { 28 throw (zen){};35 throw a_zen; 29 36 } catch (exception_t * error) { 30 37 printf("catch-all\n"); 31 }32 printf("\n");33 34 // Catch a parent of the given exception.35 try {36 printf("throwing child exception\n");37 throw (moment_of){};38 } catch (zen *) {39 printf("inner parent match\n");40 } catch (moment_of *) {41 printf("outer exact match\n");42 38 } 43 39 printf("\n"); … … 46 42 try { 47 43 try { 48 throw (yin){};44 throw a_yin; 49 45 } catch (zen *) { 50 46 printf("caught yin as zen\n"); … … 62 58 loud_exit a = "rethrow inner try"; 63 59 printf("rethrow inner try\n"); 64 throw (zen){};60 throw a_zen; 65 61 } catch (zen *) { 66 62 loud_exit a = "rethrowing catch clause"; … … 77 73 try { 78 74 try { 79 throw (yin){};75 throw a_yin; 80 76 } catch (yin *) { 81 77 printf("caught yin, will throw yang\n"); 82 throw (yang){};78 throw a_yang; 83 79 } catch (yang *) { 84 80 printf("caught exception from same try\n"); … … 93 89 try { 94 90 printf("throwing first exception\n"); 95 throw (yin){};91 throw a_yin; 96 92 } catch (yin *) { 97 93 printf("caught first exception\n"); 98 94 try { 99 95 printf("throwing second exception\n"); 100 throw (yang){};96 throw a_yang; 101 97 } catch (yang *) { 102 98 printf("caught second exception\n"); … … 114 110 try { 115 111 try { 116 throw (zen){};117 throw (zen){};112 throw a_zen; 113 throw a_zen; 118 114 } catch (zen *) { 119 115 printf("inner catch\n"); 120 116 } 121 throw (zen){};117 throw a_zen; 122 118 } catch (zen *) { 123 119 printf("outer catch\n"); … … 130 126 // Do a throw and rethrow in a void function. 131 127 void in_void(void) { 128 zen a_zen = {&zen_vt}; 132 129 try { 133 130 try { 134 131 printf("throw\n"); 135 throw (zen){};132 throw a_zen; 136 133 } catch (zen *) { 137 134 printf("rethrow\n"); -
tests/exceptions/trash.cfa
r0effb6a r47e000c 3 3 #include <exception.hfa> 4 4 5 TRIVIAL_EXCEPTION(yin); 6 TRIVIAL_EXCEPTION(yang); 5 EHM_EXCEPTION(yin)(); 6 EHM_EXCEPTION(yang)(); 7 8 EHM_VIRTUAL_TABLE(yin, yin_vt); 9 EHM_VIRTUAL_TABLE(yang, yang_vt); 7 10 8 11 int main(int argc, char * argv[]) { 9 12 try { 10 13 try { 11 throw (yin){ };14 throw (yin){&yin_vt}; 12 15 } finally { 13 16 try { 14 throw (yang){ };17 throw (yang){&yang_vt}; 15 18 } catch (yin *) { 16 19 printf("inner yin\n"); -
tests/exceptions/type-check.cfa
r0effb6a r47e000c 3 3 #include <exception.hfa> 4 4 5 TRIVIAL_EXCEPTION(truth);5 EHM_EXCEPTION(truth)(); 6 6 7 7 int main(int argc, char * argv[]) { -
tests/exceptions/virtual-cast.cfa
r0effb6a r47e000c 12 12 #include <assert.h> 13 13 14 15 16 // Hand defined alpha virtual type: 17 struct __cfatid_struct_alpha { 18 __cfa__parent_vtable const * parent; 19 }; 20 21 __attribute__(( section(".gnu.linkonce.__cfatid_alpha") )) 22 struct __cfatid_struct_alpha __cfatid_alpha = { 23 (__cfa__parent_vtable *)0, 24 }; 25 14 26 struct alpha_vtable { 15 alpha_vtable const * const parent;27 struct __cfatid_struct_alpha const * const __cfavir_typeid; 16 28 char (*code)(void); 17 29 }; … … 27 39 28 40 41 // Hand defined beta virtual type: 42 struct __cfatid_struct_beta { 43 __cfatid_struct_alpha const * parent; 44 }; 45 46 __attribute__(( section(".gnu.linkonce.__cfatid_beta") )) 47 struct __cfatid_struct_beta __cfatid_beta = { 48 &__cfatid_alpha, 49 }; 50 29 51 struct beta_vtable { 30 alpha_vtable const * const parent;52 struct __cfatid_struct_beta const * const __cfavir_typeid; 31 53 char (*code)(void); 32 54 }; … … 42 64 43 65 66 // Hand defined gamma virtual type: 67 struct __cfatid_struct_gamma { 68 __cfatid_struct_beta const * parent; 69 }; 70 71 __attribute__(( section(".gnu.linkonce.__cfatid_gamma") )) 72 struct __cfatid_struct_gamma __cfatid_gamma = { 73 &__cfatid_beta, 74 }; 75 44 76 struct gamma_vtable { 45 beta_vtable const * const parent;77 struct __cfatid_struct_gamma const * const __cfavir_typeid; 46 78 char (*code)(void); 47 79 }; … … 57 89 58 90 extern "C" { 59 alpha_vtable _alpha_vtable_instance = { 0, ret_a };60 beta_vtable _beta_vtable_instance = { &_ alpha_vtable_instance, ret_b };61 gamma_vtable _gamma_vtable_instance = { &_ beta_vtable_instance, ret_g };91 alpha_vtable _alpha_vtable_instance = { &__cfatid_alpha, ret_a }; 92 beta_vtable _beta_vtable_instance = { &__cfatid_beta, ret_b }; 93 gamma_vtable _gamma_vtable_instance = { &__cfatid_gamma, ret_g }; 62 94 } 63 95 -
tests/exceptions/virtual-poly.cfa
r0effb6a r47e000c 8 8 #include <assert.h> 9 9 10 11 struct __cfatid_struct_mono_base { 12 __cfa__parent_vtable const * parent; 13 }; 14 15 __attribute__(( section(".gnu.linkonce.__cfatid_mono_base") )) 16 struct __cfatid_struct_mono_base __cfatid_mono_base = { 17 (__cfa__parent_vtable *)0, 18 }; 19 10 20 struct mono_base_vtable { 11 mono_base_vtable const * const parent;21 __cfatid_struct_mono_base const * const __cfavir_typeid; 12 22 }; 13 23 … … 17 27 18 28 forall(T) 29 struct __cfatid_struct_mono_child { 30 __cfatid_struct_mono_base const * parent; 31 }; 32 33 forall(T) 19 34 struct mono_child_vtable { 20 mono_base_vtable const * const parent;35 __cfatid_struct_mono_child(T) const * const __cfavir_typeid; 21 36 }; 22 37 … … 26 41 }; 27 42 28 mono_base_vtable _mono_base_vtable_instance @= { 0 }; 43 __cfatid_struct_mono_child(int) __cfatid_mono_child @= { 44 &__cfatid_mono_base, 45 }; 46 29 47 mono_child_vtable(int) _mono_child_vtable_instance @= { 30 &_ mono_base_vtable_instance48 &__cfatid_mono_child, 31 49 }; 32 50 … … 37 55 } 38 56 57 58 forall(U) 59 struct __cfatid_struct_poly_base { 60 __cfa__parent_vtable const * parent; 61 }; 62 39 63 forall(U) 40 64 struct poly_base_vtable { 41 poly_base_vtable(U) const * const parent;65 __cfatid_struct_poly_base(U) const * const __cfavir_typeid; 42 66 }; 43 67 … … 48 72 49 73 forall(V) 74 struct __cfatid_struct_poly_child { 75 __cfatid_struct_poly_base(V) const * parent; 76 }; 77 78 forall(V) 50 79 struct poly_child_vtable { 51 poly_base_vtable(V) const * const parent;80 __cfatid_struct_poly_child(V) const * const __cfavir_typeid; 52 81 }; 53 82 … … 57 86 }; 58 87 59 poly_base_vtable(int) _poly_base_vtable_instance @= { 0 }; 88 __cfatid_struct_poly_base(int) __cfatid_poly_base @= { 89 (__cfa__parent_vtable *)0, 90 }; 91 __cfatid_struct_poly_child(int) __cfatid_poly_child = { 92 &__cfatid_poly_base, 93 }; 60 94 poly_child_vtable(int) _poly_child_vtable_instance @= { 61 &_ poly_base_vtable_instance95 &__cfatid_poly_child, 62 96 }; 63 /* Resolver bug keeps me from adding these.64 poly_base_vtable(char) _poly_base_vtable_instance @= { 0 };65 poly_child_vtable(char) _poly_child_vtable_instance @= {66 &_poly_base_vtable_instance67 };68 */69 97 70 98 void poly_poly_test() { … … 77 105 mono_poly_test(); 78 106 poly_poly_test(); 79 printf( "done\n" ); // non-empty .expect file107 printf( "done\n" ); 80 108 } -
tests/linking/exception-nothreads.cfa
r0effb6a r47e000c 17 17 #include <exception.hfa> 18 18 19 TRIVIAL_EXCEPTION(ping); 19 EHM_EXCEPTION(ping)(); 20 EHM_VIRTUAL_TABLE(ping, ping_vt); 20 21 21 22 int main(void) { 22 23 try { 23 throwResume (ping){ };24 throwResume (ping){&ping_vt}; 24 25 } catchResume (ping *) { 25 26 printf("%s threads\n", threading_enabled() ? "with" : "no"); -
tests/linking/exception-withthreads.cfa
r0effb6a r47e000c 18 18 #include "../exceptions/with-threads.hfa" 19 19 20 TRIVIAL_EXCEPTION(ping); 20 EHM_EXCEPTION(ping)(); 21 EHM_VIRTUAL_TABLE(ping, ping_vt); 21 22 22 23 int main(void) { 23 24 try { 24 throwResume (ping){ };25 throwResume (ping){&ping_vt}; 25 26 } catchResume (ping *) { 26 27 printf("%s threads\n", threading_enabled() ? "with" : "no"); -
tests/quasiKeyword.cfa
r0effb6a r47e000c 14 14 #include <exception.hfa> 15 15 16 TRIVIAL_EXCEPTION( E);16 EHM_EXCEPTION( E )(); 17 17 18 18 void catch( int i ) {}
Note: See TracChangeset
for help on using the changeset viewer.