Index: benchmark/basic/ttst_lock.c
===================================================================
--- benchmark/basic/ttst_lock.c	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ benchmark/basic/ttst_lock.c	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -9,5 +9,11 @@
 #define CALIGN __attribute__(( aligned (CACHE_ALIGN) ))
 #define CACHE_ALIGN 128
-#define Pause() __asm__ __volatile__ ( "pause" : : : )
+#if defined( __i386 ) || defined( __x86_64 )
+	#define Pause() __asm__ __volatile__ ( "pause" : : : )
+#elif defined( __ARM_ARCH )
+	#define Pause() __asm__ __volatile__ ( "YIELD" : : : )
+#else
+	#error unsupported architecture
+#endif
 
 typedef uintptr_t TYPE;									// addressable word-size
Index: doc/theses/thierry_delisle_PhD/code/readyQ_proto/dynamic_entropy.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/dynamic_entropy.hpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/dynamic_entropy.hpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -0,0 +1,201 @@
+#pragma once
+
+#define LIST_VARIANT dyn_ent_list
+
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#include "assert.hpp"
+#include "utils.hpp"
+#include "links.hpp"
+
+std::mutex mtx_;
+
+template<typename node_t>
+class __attribute__((aligned(128))) dyn_ent_list {
+	const unsigned numLists;
+    	__attribute__((aligned(64))) std::unique_ptr<intrusive_queue_t<node_t> []> lists;
+
+public:
+	dyn_ent_list(unsigned numThreads, unsigned)
+		: numLists(numThreads * 4)
+		, lists(new intrusive_queue_t<node_t>[numLists])
+	{
+		std::cout << "Constructing Relaxed List with " << numLists << std::endl;
+	}
+
+	__attribute__((noinline, hot)) void push(node_t * node) {
+		node->_links.ts = rdtscl();
+
+		// Try to pick a lane and lock it
+		unsigned i;
+		do {
+			// Pick the index of a lane
+			i = idx_from_r(tls.rng1.next(), tls.my_queue).first;
+			// i = ret.first; //local = ret.second;
+			tls.stats.push.attempt++;
+		} while( !lists[i].lock.try_lock() );
+
+		lists[i].push(node);
+		lists[i].lock.unlock();
+		tls.rng2.set_raw_state( tls.rng1.get_raw_state());
+		tls.stats.push.success++;
+	}
+
+	__attribute__((noinline, hot)) node_t * pop() {
+		for(int n = 0; n < 25; n++) {
+			// Pick two lists at random
+			unsigned i, j;
+			bool locali, localj;
+			auto reti = idx_from_r(tls.rng2.prev(), tls.my_queue);
+			auto retj = idx_from_r(tls.rng2.prev(), tls.my_queue);
+
+			i = reti.first; locali = reti.second;
+			j = retj.first; localj = retj.second;
+			tls.stats.pop.attempt++;
+
+			// try popping from the 2 picked lists
+			node_t * thrd = try_pop(i, j);
+			if(thrd) {
+				tls.stats.pop.success++;
+				return thrd;
+			}
+		}
+
+		unsigned offset = tls.rng2.next();
+		for(unsigned i = 0; i < numLists; i++) {
+			unsigned idx = (offset + i) % numLists;
+			node_t * thrd = try_pop(idx);
+			if(thrd) {
+				return thrd;
+			}
+		}
+
+		// All lanes where empty return 0p
+		return nullptr;
+	}
+
+private:
+	inline node_t * try_pop(unsigned i, unsigned j) {
+		// Pick the bet list
+		int w = i;
+		if( __builtin_expect(!(lists[j].ts() > 0), true) ) {
+			w = (lists[i].ts() < lists[j].ts()) ? i : j;
+		}
+
+		return try_pop(w);
+	}
+
+	inline node_t * try_pop(unsigned w) {
+		// If list looks empty retry
+		if( lists[w].ts() == 0 ) { tls.stats.pop.empty++; return nullptr; }
+
+		// If we can't get the lock retry
+		if( !lists[w].lock.try_lock() ) { tls.stats.pop.locked++; return nullptr; }
+
+
+		// If list is empty, unlock and retry
+		if( lists[w].ts() == 0 ) {
+			tls.stats.pop.both++;
+			lists[w].lock.unlock();
+			return nullptr;
+		}
+
+		auto node = lists[w].pop();
+		lists[w].lock.unlock();
+		return node.first;
+	}
+
+	inline std::pair<unsigned, bool> idx_from_r(unsigned r, unsigned preferred) {
+		unsigned i;
+		bool local;
+		unsigned rlow  = r % 4;
+		unsigned rhigh = r / 4;
+		if((0 != rlow) && preferred != outside) {
+			// (BIAS - 1) out of BIAS chances
+			// Use perferred queues
+			i = preferred + (rhigh % 4);
+			local = true;
+		}
+		else {
+			// 1 out of BIAS chances
+			// Use all queues
+			i = rhigh;
+			local = false;
+		}
+		return {i % numLists, local};
+	}
+private:
+	static std::atomic_uint32_t ticket;
+	static const unsigned outside = 0xFFFFFFFF;
+
+	static inline unsigned calc_preferred() {
+		unsigned t = ticket++;
+		if(t == 0) return outside;
+		unsigned i = 4 * (t - 1);
+		return i;
+	}
+
+	static __attribute__((aligned(128))) thread_local struct TLS {
+		Random     rng1 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
+		Random     rng2 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
+		Random     rng3 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
+		unsigned   my_queue = calc_preferred();
+		struct {
+			struct {
+				size_t attempt = 0;
+				size_t success = 0;
+			} push;
+			struct {
+				size_t attempt = 0;
+				size_t success = 0;
+				size_t empty   = 0;
+				size_t locked  = 0;
+				size_t both    = 0;
+			} pop;
+		} stats;
+	} tls;
+public:
+	static const char * name() {
+		return "Dynamic Entropy List";
+	}
+
+public:
+	static struct GlobalStats {
+		struct {
+			std::atomic_size_t attempt = 0;
+			std::atomic_size_t success = 0;
+		} push;
+		struct {
+			std::atomic_size_t attempt = 0;
+			std::atomic_size_t success = 0;
+			std::atomic_size_t empty   = 0;
+			std::atomic_size_t locked  = 0;
+			std::atomic_size_t both    = 0;
+		} pop;
+	} global_stats;
+	static void stats_tls_tally() {
+		global_stats.push.attempt += tls.stats.push.attempt;
+		global_stats.push.success += tls.stats.push.success;
+		global_stats.pop .attempt += tls.stats.pop.attempt;
+		global_stats.pop .success += tls.stats.pop.success;
+		global_stats.pop .empty   += tls.stats.pop.empty;
+		global_stats.pop .locked  += tls.stats.pop.locked;
+		global_stats.pop .both    += tls.stats.pop.both;
+	}
+
+	static void stats_print(std::ostream & os, double) {
+			const auto & global = global_stats;
+
+		double push_sur = (100.0 * double(global.push.success) / global.push.attempt);
+		double pop_sur  = (100.0 * double(global.pop .success) / global.pop .attempt);
+
+		double push_len = double(global.push.attempt     ) / global.push.success;
+		double pop_len  = double(global.pop .attempt     ) / global.pop .success;
+
+		os << "Push   Pick   : " << push_sur << " %, len " << push_len << " (" << global.push.attempt      << " / " << global.push.success << ")\n";
+		os << "Pop    Pick   : " << pop_sur  << " %, len " << pop_len  << " (" << global.pop .attempt      << " / " << global.pop .success << ")\n";
+		os << "Pop    Fails  : " << global_stats.pop .empty << "e, " << global_stats.pop .locked << "l, " << global_stats.pop .both << "\n";
+	}
+};
Index: doc/theses/thierry_delisle_PhD/code/readyQ_proto/links2.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/links2.hpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/links2.hpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -0,0 +1,113 @@
+#pragma once
+
+#include <assert.h>
+
+#include "utils.hpp"
+
+//------------------------------------------------------------
+// Queue based on the MCS lock
+// It is a Multi-Producer/Single-Consumer queue threads pushing
+// elements must hold on to the elements they push
+// Not appropriate for an async message queue for example,
+template<typename node_t>
+class mcs_queue {
+	node_t * volatile tail;
+
+public:
+	mcs_queue(): tail(nullptr) {}
+
+	inline bool empty() const { return !tail; }
+
+	node_t * push( node_t * elem ) {
+		/* paranoid */ assert(!elem->_links.next);
+		// Race to add to the tail
+		node_t * prev = __atomic_exchange_n(&tail, elem, __ATOMIC_SEQ_CST);
+		// If we aren't the first, we need to tell the person before us
+		// No need to
+		if (prev) prev->_links.next = elem;
+		return prev;
+	}
+
+	// Advances the head of the list, dropping the element given.
+	// Passing an element that is not the head is undefined behavior
+	// NOT Multi-Thread Safe, concurrent pushes are safe
+	node_t * advance(node_t * elem) {
+		node_t * expected = elem;
+		// Check if this is already the last item
+		if (__atomic_compare_exchange_n(&tail, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) return nullptr;
+
+		// If not wait for next item to show-up, filled by push
+		while (!elem->_links.next) Pause();
+
+		// we need to return if the next link was empty
+		node_t * ret = elem->_links.next;
+
+		// invalidate link to reset to initial state
+		elem->_links.next = nullptr;
+		return ret;
+	}
+};
+
+//------------------------------------------------------------
+// Queue based on the MCS lock
+// Extension of the above lock which supports 'blind' pops.
+// i.e., popping a value from the head without knowing what the head is
+// has no extra guarantees beyond the mcs_queue
+template<typename node_t>
+class mpsc_queue : private mcs_queue<node_t> {
+	node_t * volatile head;
+public:
+	mpsc_queue(): mcs_queue<node_t>(), head(nullptr) {}
+
+	inline bool empty() const { return mcs_queue<node_t>::empty(); }
+
+	// Added a new element to the queue
+	// Multi-Thread Safe, Lock-Free
+	inline node_t * push(node_t * elem) {
+		node_t * prev = mcs_queue<node_t>::push(elem);
+		if (!prev) head = elem;
+		return prev;
+	}
+
+	// Pop an element from the queue
+	// return the element that was removed
+	// next is set to the new head of the queue
+	// NOT Multi-Thread Safe
+	inline node_t * pop(node_t *& next) {
+		node_t * elem = head;
+		// If head is empty just return
+		if (!elem) return nullptr;
+
+		// If there is already someone in the list, then it's easy
+		if (elem->_links.next) {
+			head = next = elem->_links.next;
+			// force memory sync
+			__atomic_thread_fence(__ATOMIC_SEQ_CST);
+
+			// invalidate link to reset to initial state
+			elem->_links.next = nullptr;
+		}
+		// Otherwise, there might be a race where it only looks but someone is enqueuing
+		else {
+			// null out head here, because we linearize with push
+			// at the CAS in advance and therefore can write to head
+			// after that point, it could overwrite the write in push
+			head = nullptr;
+			next = mcs_queue<node_t>::advance(elem);
+
+			// Only write to the head if there is a next element
+			// it is the only way we can guarantee we are not overwriting
+			// a write made in push
+			if (next) head = next;
+		}
+
+		// return removed element
+		return elem;
+	}
+
+	// Same as previous function
+	inline node_t * pop() {
+		node_t * _ = nullptr;
+		return pop(_);
+	}
+};
Index: doc/theses/thierry_delisle_PhD/code/readyQ_proto/ntmove.cpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/ntmove.cpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/ntmove.cpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -0,0 +1,87 @@
+#include <atomic>
+#include <iostream>
+#include <locale>
+#include <thread>
+
+#include <x86intrin.h>
+
+struct __attribute__((aligned(128))) Global_t {
+	volatile size_t value;
+} global;
+
+static const size_t iterations = 1'000'000'000;
+
+size_t read() {
+	// size_t r = __atomic_load_n(&global.value, __ATOMIC_RELAXED);
+	// _mm_stream_si64((long long int*)&global.value, r);
+	// // _mm_clflush( (void*)&global.value );
+	// // __builtin_prefetch((void*)&global.value);
+	// asm volatile(
+	// 	"PREFETCHNTA %[target]"
+	// 	:
+	// 	: [target] "m" (global.value)
+	// );
+	// return r;
+	return __atomic_load_n(&global.value, __ATOMIC_SEQ_CST);
+
+	// __m128i r = _mm_stream_load_si128((__m128i*)&global.value);
+	// asm volatile(
+	// 	"PREFETCHNTA %[target]"
+	// 	:
+	// 	: [target] "m" (global.value)
+	// );
+	// return ((Global_t*)&r)->value;
+	// size_t r;
+	// asm volatile(
+	// 	"MOVNTI %[target], %[r]\n\t"
+	// 	: [r] "=r" (r)
+	// 	: [target] "m" (global.value)
+	// );
+	// return r;
+}
+
+void write(size_t v) {
+	// __atomic_store_n(&global.value, v, __ATOMIC_SEQ_CST);
+	// __atomic_store_n(&global.value, v, __ATOMIC_RELAXED);
+	// asm volatile(
+	// 	"MOVNTI %[v], %[target]\n\t"
+	// 	:
+	// 	: [target] "m" (global.value), [v] "r" (v)
+	// );
+	_mm_stream_si64((long long int*)&global.value, v);
+}
+
+void reader(size_t * reads, size_t * diffs, size_t * m) {
+	size_t last = read();
+	for(size_t i = 0; i < iterations; i++) {
+		size_t val = read();
+		if(last != val) (*diffs)++;
+		last = val;
+		if(last > *m) *m = last;
+		(*reads)++;
+	}
+}
+
+std::atomic<bool> done = { false };
+
+void writer() {
+	size_t v = 0;
+	while(!done) {
+		v++;
+		write(v);
+		__atomic_thread_fence(__ATOMIC_SEQ_CST);
+	}
+}
+
+int main() {
+	std::cout.imbue(std::locale(""));
+	size_t reads = 0;
+	size_t diffs = 0;
+	size_t max   = 0;
+	auto w = std::thread(writer);
+	auto r = std::thread(reader, &reads, &diffs, &max);
+	r.join();
+	done = true;
+	w.join();
+	std::cout << reads << " " << diffs << " " << max << std::endl;
+}
Index: doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list.hpp	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list.hpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -39,5 +39,5 @@
 		while( __builtin_expect(ll.exchange(true),false) ) {
 			while(ll.load(std::memory_order_relaxed))
-				asm volatile("pause");
+				Pause();
 		}
 		/* paranoid */ assert(ll);
@@ -93,5 +93,5 @@
 			 && ready.compare_exchange_weak(copy, n + 1) )
 			 	break;
-			asm volatile("pause");
+			Pause();
 		}
 
@@ -133,5 +133,5 @@
 		// Step 1 : make sure no writer are in the middle of the critical section
 		while(lock.load(std::memory_order_relaxed))
-			asm volatile("pause");
+			Pause();
 
 		// Fence needed because we don't want to start trying to acquire the lock
@@ -195,5 +195,5 @@
 		//   to simply lock their own lock and enter.
 		while(lock.load(std::memory_order_relaxed))
-			asm volatile("pause");
+			Pause();
 
 		// Step 2 : lock per-proc lock
@@ -204,5 +204,5 @@
 		for(uint_fast32_t i = 0; i < s; i++) {
 			while(data[i].lock.load(std::memory_order_relaxed))
-				asm volatile("pause");
+				Pause();
 		}
 
Index: doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list_good.cpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list_good.cpp	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list_good.cpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -21,5 +21,5 @@
 		target = (target - (target % total)) + total;
 		while(waiting < target)
-			asm volatile("pause");
+			Pause();
 
 		assert(waiting < (1ul << 60));
Index: doc/theses/thierry_delisle_PhD/code/readyQ_proto/randbit.cpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/randbit.cpp	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/randbit.cpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -123,5 +123,5 @@
 		target = (target - (target % total)) + total;
 		while(waiting < target)
-			asm volatile("pause");
+			Pause();
 
 		assert(waiting < (1ul << 60));
Index: doc/theses/thierry_delisle_PhD/code/readyQ_proto/relaxed_list.cpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/relaxed_list.cpp	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/relaxed_list.cpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -206,5 +206,5 @@
 	std::cout << "Total ops     : " << ops << "(" << global.in << "i, " << global.out << "o, " << global.empty << "e)\n";
 	#ifndef NO_STATS
-		LIST_VARIANT<Node>::stats_print(std::cout);
+		LIST_VARIANT<Node>::stats_print(std::cout, duration);
 	#endif
 }
@@ -368,6 +368,8 @@
 
 		for(Node * & node : nodes) {
-			node = list.pop();
-			assert(node);
+			node = nullptr;
+			while(!node) {
+				node = list.pop();
+			}
 			local.crc_out += node->value;
 			local.out++;
@@ -691,6 +693,6 @@
 
 				for(const auto & n : nodes) {
-					local.valmax = max(local.valmax, size_t(n.value));
-					local.valmin = min(local.valmin, size_t(n.value));
+					local.valmax = std::max(local.valmax, size_t(n.value));
+					local.valmin = std::min(local.valmin, size_t(n.value));
 				}
 
@@ -773,5 +775,5 @@
 						try {
 							arg = optarg = argv[optind];
-							nnodes = stoul(optarg, &len);
+							nnodes = std::stoul(optarg, &len);
 							if(len != arg.size()) { throw std::invalid_argument(""); }
 						} catch(std::invalid_argument &) {
@@ -792,5 +794,5 @@
 						try {
 							arg = optarg = argv[optind];
-							nnodes = stoul(optarg, &len);
+							nnodes = std::stoul(optarg, &len);
 							if(len != arg.size()) { throw std::invalid_argument(""); }
 						} catch(std::invalid_argument &) {
@@ -812,5 +814,5 @@
 						try {
 							arg = optarg = argv[optind];
-							nnodes = stoul(optarg, &len);
+							nnodes = std::stoul(optarg, &len);
 							if(len != arg.size()) { throw std::invalid_argument(""); }
 							nslots = nnodes;
@@ -823,5 +825,5 @@
 						try {
 							arg = optarg = argv[optind];
-							nnodes = stoul(optarg, &len);
+							nnodes = std::stoul(optarg, &len);
 							if(len != arg.size()) { throw std::invalid_argument(""); }
 						} catch(std::invalid_argument &) {
@@ -831,5 +833,5 @@
 						try {
 							arg = optarg = argv[optind + 1];
-							nslots = stoul(optarg, &len);
+							nslots = std::stoul(optarg, &len);
 							if(len != arg.size()) { throw std::invalid_argument(""); }
 						} catch(std::invalid_argument &) {
@@ -884,5 +886,5 @@
 			case 'd':
 				try {
-					duration = stod(optarg, &len);
+					duration = std::stod(optarg, &len);
 					if(len != arg.size()) { throw std::invalid_argument(""); }
 				} catch(std::invalid_argument &) {
@@ -893,5 +895,5 @@
 			case 't':
 				try {
-					nthreads = stoul(optarg, &len);
+					nthreads = std::stoul(optarg, &len);
 					if(len != arg.size()) { throw std::invalid_argument(""); }
 				} catch(std::invalid_argument &) {
@@ -902,5 +904,5 @@
 			case 'q':
 				try {
-					nqueues = stoul(optarg, &len);
+					nqueues = std::stoul(optarg, &len);
 					if(len != arg.size()) { throw std::invalid_argument(""); }
 				} catch(std::invalid_argument &) {
Index: doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi-packed.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi-packed.hpp	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi-packed.hpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -168,5 +168,4 @@
 	for(int i = 0; i < width; i++) {
 		int idx = i % hwdith;
-		std::cout << i << " -> " << idx + width << std::endl;
 		leafs[i].parent = &nodes[ idx ];
 	}
@@ -174,5 +173,4 @@
 	for(int i = 0; i < root; i++) {
 		int idx = (i / 2) + hwdith;
-		std::cout << i + width << " -> " << idx + width << std::endl;
 		nodes[i].parent = &nodes[ idx ];
 	}
Index: doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi.hpp	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi.hpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -159,5 +159,4 @@
 	std::cout << "SNZI: " << depth << "x" << width << "(" << mask - 1 << ") " << (sizeof(snzi_t::node) * (root + 1)) << " bytes" << std::endl;
 	for(int i = 0; i < root; i++) {
-		std::cout << i << " -> " << (i / base) + width << std::endl;
 		nodes[i].parent = &nodes[(i / base) + width];
 	}
Index: doc/theses/thierry_delisle_PhD/code/readyQ_proto/utils.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/utils.hpp	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/utils.hpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -12,26 +12,4 @@
 
 #include <x86intrin.h>
-
-// Barrier from
-class barrier_t {
-public:
-	barrier_t(size_t total)
-		: waiting(0)
-		, total(total)
-	{}
-
-	void wait(unsigned) {
-		size_t target = waiting++;
-		target = (target - (target % total)) + total;
-		while(waiting < target)
-			asm volatile("pause");
-
-		assert(waiting < (1ul << 60));
-    	}
-
-private:
-	std::atomic<size_t> waiting;
-	size_t total;
-};
 
 // class Random {
@@ -102,9 +80,26 @@
 };
 
-static inline long long rdtscl(void) {
-    unsigned int lo, hi;
-    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
-    return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
-}
+static inline long long int rdtscl(void) {
+	#if defined( __i386 ) || defined( __x86_64 )
+		unsigned int lo, hi;
+		__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+		return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
+	#elif defined( __aarch64__ ) || defined( __arm__ )
+		// https://github.com/google/benchmark/blob/v1.1.0/src/cycleclock.h#L116
+		long long int virtual_timer_value;
+		asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
+		return virtual_timer_value;
+	#else
+		#error unsupported hardware architecture
+	#endif
+}
+
+#if defined( __i386 ) || defined( __x86_64 )
+	#define Pause() __asm__ __volatile__ ( "pause" : : : )
+#elif defined( __ARM_ARCH )
+	#define Pause() __asm__ __volatile__ ( "YIELD" : : : )
+#else
+	#error unsupported architecture
+#endif
 
 static inline void affinity(int tid) {
@@ -195,4 +190,26 @@
 }
 
+// Barrier from
+class barrier_t {
+public:
+	barrier_t(size_t total)
+		: waiting(0)
+		, total(total)
+	{}
+
+	void wait(unsigned) {
+		size_t target = waiting++;
+		target = (target - (target % total)) + total;
+		while(waiting < target)
+			Pause();
+
+		assert(waiting < (1ul << 60));
+    	}
+
+private:
+	std::atomic<size_t> waiting;
+	size_t total;
+};
+
 struct spinlock_t {
 	std::atomic_bool ll = { false };
@@ -201,5 +218,5 @@
 		while( __builtin_expect(ll.exchange(true),false) ) {
 			while(ll.load(std::memory_order_relaxed))
-				asm volatile("pause");
+				Pause();
 		}
 	}
Index: doc/theses/thierry_delisle_PhD/code/readyQ_proto/work_stealing.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/work_stealing.hpp	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/work_stealing.hpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -6,4 +6,5 @@
 #include <memory>
 #include <mutex>
+#include <thread>
 #include <type_traits>
 
@@ -11,7 +12,24 @@
 #include "utils.hpp"
 #include "links.hpp"
+#include "links2.hpp"
 #include "snzi.hpp"
 
+#include <x86intrin.h>
+
 using namespace std;
+
+static const long long lim = 2000;
+static const unsigned nqueues = 2;
+
+struct __attribute__((aligned(128))) timestamp_t {
+	volatile unsigned long long val = 0;
+};
+
+template<typename node_t>
+struct __attribute__((aligned(128))) localQ_t {
+	mpsc_queue<node_t> queue = {};
+	spinlock_t lock = {};
+	bool needs_help = true;
+};
 
 template<typename node_t>
@@ -25,7 +43,8 @@
 
 	work_stealing(unsigned _numThreads, unsigned)
-		: numThreads(_numThreads)
+		: numThreads(_numThreads * nqueues)
 		, lists(new intrusive_queue_t<node_t>[numThreads])
-		, snzi( std::log2( numThreads / 2 ), 2 )
+		, times(new timestamp_t[numThreads])
+		// , snzi( std::log2( numThreads / 2 ), 2 )
 
 	{
@@ -39,103 +58,116 @@
 
 	__attribute__((noinline, hot)) void push(node_t * node) {
-		node->_links.ts = rdtscl();
-		if( node->_links.hint > numThreads ) {
-			node->_links.hint = tls.rng.next() % numThreads;
-			tls.stat.push.nhint++;
-		}
-
-		unsigned i = node->_links.hint;
+		// node->_links.ts = rdtscl();
+		node->_links.ts = 1;
+
+		auto & list = *({
+			unsigned i;
+			do {
+				tls.stats.push.attempt++;
+				// unsigned r = tls.rng1.next();
+				unsigned r = tls.it++;
+				if(tls.my_queue == outside) {
+					i = r % numThreads;
+				} else {
+					i = tls.my_queue + (r % nqueues);
+				}
+			} while(!lists[i].lock.try_lock());
+		 	&lists[i];
+		});
+
+		list.push( node );
+		list.lock.unlock();
+		// tls.rng2.set_raw_state( tls.rng1.get_raw_state());
+		// count++;
+		tls.stats.push.success++;
+	}
+
+	__attribute__((noinline, hot)) node_t * pop() {
+		if( tls.myfriend == outside ) {
+			auto r  = tls.rng1.next();
+			tls.myfriend = r % numThreads;
+			times[tls.myfriend].val = 0;
+		}
+		else if(times[tls.myfriend].val == 0) {
+			node_t * n = try_pop(tls.myfriend, tls.stats.pop.help);
+			tls.stats.help++;
+			tls.myfriend = outside;
+			if(n) return n;
+		}
+
+		if(tls.my_queue != outside) {
+			node_t * n = local();
+			if(n) return n;
+		}
+
+		// try steal
+		for(int i = 0; i < 25; i++) {
+			node_t * n = steal();
+			if(n) return n;
+		}
+
+		return search();
+	}
+
+private:
+	inline node_t * local() {
+		// unsigned i = (tls.rng2.prev() % 4) + tls.my_queue;
+		unsigned i = (--tls.it % nqueues) + tls.my_queue;
+		return try_pop(i, tls.stats.pop.local);
+	}
+
+	inline node_t * steal() {
+		unsigned i = tls.rng2.prev() % numThreads;
+		return try_pop(i, tls.stats.pop.steal);
+	}
+
+	inline node_t * search() {
+		unsigned offset = tls.rng2.prev();
+		for(unsigned i = 0; i < numThreads; i++) {
+			unsigned idx = (offset + i) % numThreads;
+			node_t * thrd = try_pop(idx, tls.stats.pop.search);
+			if(thrd) {
+				return thrd;
+			}
+		}
+
+		return nullptr;
+	}
+
+private:
+	struct attempt_stat_t {
+		std::size_t attempt = { 0 };
+		std::size_t elock   = { 0 };
+		std::size_t eempty  = { 0 };
+		std::size_t espec   = { 0 };
+		std::size_t success = { 0 };
+	};
+
+	node_t * try_pop(unsigned i, attempt_stat_t & stat) {
+		assert(i < numThreads);
 		auto & list = lists[i];
-		list.lock.lock();
-
-		if(list.push( node )) {
-			snzi.arrive(i);
-		}
-
-		list.lock.unlock();
-	}
-
-	__attribute__((noinline, hot)) node_t * pop() {
-		node_t * node;
-		while(true) {
-			if(!snzi.query()) {
-				return nullptr;
-			}
-
-			{
-				unsigned i = tls.my_queue;
-				auto & list = lists[i];
-				if( list.ts() != 0 ) {
-					list.lock.lock();
-					if((node = try_pop(i))) {
-						tls.stat.pop.local.success++;
-						break;
-					}
-					else {
-						tls.stat.pop.local.elock++;
-					}
-				}
-				else {
-					tls.stat.pop.local.espec++;
-				}
-			}
-
-			tls.stat.pop.steal.tried++;
-
-			int i = tls.rng.next() % numThreads;
-			auto & list = lists[i];
-			if( list.ts() == 0 ) {
-				tls.stat.pop.steal.empty++;
-				continue;
-			}
-
-			if( !list.lock.try_lock() ) {
-				tls.stat.pop.steal.locked++;
-				continue;
-			}
-
-			if((node = try_pop(i))) {
-				tls.stat.pop.steal.success++;
-				break;
-			}
-		}
-
-		#if defined(READ)
-			const unsigned f = READ;
-			if(0 == (tls.it % f)) {
-				unsigned i = tls.it / f;
-				lists[i % numThreads].ts();
-			}
-			// lists[tls.it].ts();
-			tls.it++;
-		#endif
-
-
-		return node;
-	}
-
-private:
-	node_t * try_pop(unsigned i) {
-		auto & list = lists[i];
+		stat.attempt++;
+
+		// If the list is empty, don't try
+		if(list.ts() == 0) { stat.espec++; return nullptr; }
+
+		// If we can't get the lock, move on
+		if( !list.lock.try_lock() ) { stat.elock++; return nullptr; }
+
 
 		// If list is empty, unlock and retry
 		if( list.ts() == 0 ) {
 			list.lock.unlock();
+			stat.eempty++;
 			return nullptr;
 		}
 
-			// Actually pop the list
-		node_t * node;
-		bool emptied;
-		std::tie(node, emptied) = list.pop();
-		assert(node);
-
-		if(emptied) {
-			snzi.depart(i);
-		}
-
-		// Unlock and return
+		auto node = list.pop();
 		list.lock.unlock();
-		return node;
+		stat.success++;
+		times[i].val = 1; //node.first->_links.ts;
+		// count--;
+		// _mm_stream_si64((long long int*)&times[i].val, node.first->_links.ts);
+		return node.first;
 	}
 
@@ -144,7 +176,19 @@
 
 	static std::atomic_uint32_t ticket;
+	static const unsigned outside = 0xFFFFFFFF;
+
+	static inline unsigned calc_preferred() {
+		unsigned t = ticket++;
+		if(t == 0) return outside;
+		unsigned i = (t - 1) * nqueues;
+		return i;
+	}
+
 	static __attribute__((aligned(128))) thread_local struct TLS {
-		Random     rng = { int(rdtscl()) };
-		unsigned   my_queue = ticket++;
+		Random     rng1 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
+		Random     rng2 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
+		unsigned   it   = 0;
+		unsigned   my_queue = calc_preferred();
+		unsigned   myfriend = outside;
 		#if defined(READ)
 			unsigned it = 0;
@@ -152,20 +196,15 @@
 		struct {
 			struct {
-				std::size_t nhint = { 0 };
+				std::size_t attempt = { 0 };
+				std::size_t success = { 0 };
 			} push;
 			struct {
-				struct {
-					std::size_t success = { 0 };
-					std::size_t espec = { 0 };
-					std::size_t elock = { 0 };
-				} local;
-				struct {
-					std::size_t tried   = { 0 };
-					std::size_t locked  = { 0 };
-					std::size_t empty   = { 0 };
-					std::size_t success = { 0 };
-				} steal;
+				attempt_stat_t help;
+				attempt_stat_t local;
+				attempt_stat_t steal;
+				attempt_stat_t search;
 			} pop;
-		} stat;
+			std::size_t help = { 0 };
+		} stats;
 	} tls;
 
@@ -173,5 +212,6 @@
 	const unsigned numThreads;
     	std::unique_ptr<intrusive_queue_t<node_t> []> lists;
-	__attribute__((aligned(64))) snzi_t snzi;
+    	std::unique_ptr<timestamp_t []> times;
+	__attribute__((aligned(128))) std::atomic_size_t count;
 
 #ifndef NO_STATS
@@ -179,42 +219,94 @@
 	static struct GlobalStats {
 		struct {
-			std::atomic_size_t nhint = { 0 };
+			std::atomic_size_t attempt = { 0 };
+			std::atomic_size_t success = { 0 };
 		} push;
 		struct {
 			struct {
+				std::atomic_size_t attempt = { 0 };
+				std::atomic_size_t elock   = { 0 };
+				std::atomic_size_t eempty  = { 0 };
+				std::atomic_size_t espec   = { 0 };
 				std::atomic_size_t success = { 0 };
-				std::atomic_size_t espec = { 0 };
-				std::atomic_size_t elock = { 0 };
+			} help;
+			struct {
+				std::atomic_size_t attempt = { 0 };
+				std::atomic_size_t elock   = { 0 };
+				std::atomic_size_t eempty  = { 0 };
+				std::atomic_size_t espec   = { 0 };
+				std::atomic_size_t success = { 0 };
 			} local;
 			struct {
-				std::atomic_size_t tried   = { 0 };
-				std::atomic_size_t locked  = { 0 };
-				std::atomic_size_t empty   = { 0 };
+				std::atomic_size_t attempt = { 0 };
+				std::atomic_size_t elock   = { 0 };
+				std::atomic_size_t eempty  = { 0 };
+				std::atomic_size_t espec   = { 0 };
 				std::atomic_size_t success = { 0 };
 			} steal;
+			struct {
+				std::atomic_size_t attempt = { 0 };
+				std::atomic_size_t elock   = { 0 };
+				std::atomic_size_t eempty  = { 0 };
+				std::atomic_size_t espec   = { 0 };
+				std::atomic_size_t success = { 0 };
+			} search;
 		} pop;
+		std::atomic_size_t help = { 0 };
 	} global_stats;
 
 public:
 	static void stats_tls_tally() {
-		global_stats.push.nhint += tls.stat.push.nhint;
-		global_stats.pop.local.success += tls.stat.pop.local.success;
-		global_stats.pop.local.espec   += tls.stat.pop.local.espec  ;
-		global_stats.pop.local.elock   += tls.stat.pop.local.elock  ;
-		global_stats.pop.steal.tried   += tls.stat.pop.steal.tried  ;
-		global_stats.pop.steal.locked  += tls.stat.pop.steal.locked ;
-		global_stats.pop.steal.empty   += tls.stat.pop.steal.empty  ;
-		global_stats.pop.steal.success += tls.stat.pop.steal.success;
-	}
-
-	static void stats_print(std::ostream & os ) {
+		global_stats.push.attempt += tls.stats.push.attempt;
+		global_stats.push.success += tls.stats.push.success;
+		global_stats.pop.help  .attempt += tls.stats.pop.help  .attempt;
+		global_stats.pop.help  .elock   += tls.stats.pop.help  .elock  ;
+		global_stats.pop.help  .eempty  += tls.stats.pop.help  .eempty ;
+		global_stats.pop.help  .espec   += tls.stats.pop.help  .espec  ;
+		global_stats.pop.help  .success += tls.stats.pop.help  .success;
+		global_stats.pop.local .attempt += tls.stats.pop.local .attempt;
+		global_stats.pop.local .elock   += tls.stats.pop.local .elock  ;
+		global_stats.pop.local .eempty  += tls.stats.pop.local .eempty ;
+		global_stats.pop.local .espec   += tls.stats.pop.local .espec  ;
+		global_stats.pop.local .success += tls.stats.pop.local .success;
+		global_stats.pop.steal .attempt += tls.stats.pop.steal .attempt;
+		global_stats.pop.steal .elock   += tls.stats.pop.steal .elock  ;
+		global_stats.pop.steal .eempty  += tls.stats.pop.steal .eempty ;
+		global_stats.pop.steal .espec   += tls.stats.pop.steal .espec  ;
+		global_stats.pop.steal .success += tls.stats.pop.steal .success;
+		global_stats.pop.search.attempt += tls.stats.pop.search.attempt;
+		global_stats.pop.search.elock   += tls.stats.pop.search.elock  ;
+		global_stats.pop.search.eempty  += tls.stats.pop.search.eempty ;
+		global_stats.pop.search.espec   += tls.stats.pop.search.espec  ;
+		global_stats.pop.search.success += tls.stats.pop.search.success;
+		global_stats.help += tls.stats.help;
+	}
+
+	static void stats_print(std::ostream & os, double duration ) {
 		std::cout << "----- Work Stealing Stats -----" << std::endl;
 
-		double stealSucc = double(global_stats.pop.steal.success) / global_stats.pop.steal.tried;
-		os << "Push to new Q : " << std::setw(15) << global_stats.push.nhint << "\n";
-		os << "Local Pop     : " << std::setw(15) << global_stats.pop.local.success << "\n";
-		os << "Steal Pop     : " << std::setw(15) << global_stats.pop.steal.success << "(" << global_stats.pop.local.espec << "s, " << global_stats.pop.local.elock << "l)\n";
-		os << "Steal Success : " << std::setw(15) << stealSucc << "(" << global_stats.pop.steal.tried << " tries)\n";
-		os << "Steal Fails   : " << std::setw(15) << global_stats.pop.steal.empty << "e, " << global_stats.pop.steal.locked << "l\n";
+		double push_suc = (100.0 * double(global_stats.push.success) / global_stats.push.attempt);
+		double push_len = double(global_stats.push.attempt     ) / global_stats.push.success;
+		os << "Push   Pick : " << push_suc << " %, len " << push_len << " (" << global_stats.push.attempt      << " / " << global_stats.push.success << ")\n";
+
+		double hlp_suc = (100.0 * double(global_stats.pop.help.success) / global_stats.pop.help.attempt);
+		double hlp_len = double(global_stats.pop.help.attempt     ) / global_stats.pop.help.success;
+		os << "Help        : " << hlp_suc << " %, len " << hlp_len << " (" << global_stats.pop.help.attempt      << " / " << global_stats.pop.help.success << ")\n";
+		os << "Help Fail   : " << global_stats.pop.help.espec << "s, " << global_stats.pop.help.eempty << "e, " << global_stats.pop.help.elock << "l\n";
+
+		double pop_suc = (100.0 * double(global_stats.pop.local.success) / global_stats.pop.local.attempt);
+		double pop_len = double(global_stats.pop.local.attempt     ) / global_stats.pop.local.success;
+		os << "Local       : " << pop_suc << " %, len " << pop_len << " (" << global_stats.pop.local.attempt      << " / " << global_stats.pop.local.success << ")\n";
+		os << "Local Fail  : " << global_stats.pop.local.espec << "s, " << global_stats.pop.local.eempty << "e, " << global_stats.pop.local.elock << "l\n";
+
+		double stl_suc = (100.0 * double(global_stats.pop.steal.success) / global_stats.pop.steal.attempt);
+		double stl_len = double(global_stats.pop.steal.attempt     ) / global_stats.pop.steal.success;
+		os << "Steal       : " << stl_suc << " %, len " << stl_len << " (" << global_stats.pop.steal.attempt      << " / " << global_stats.pop.steal.success << ")\n";
+		os << "Steal Fail  : " << global_stats.pop.steal.espec << "s, " << global_stats.pop.steal.eempty << "e, " << global_stats.pop.steal.elock << "l\n";
+
+		double srh_suc = (100.0 * double(global_stats.pop.search.success) / global_stats.pop.search.attempt);
+		double srh_len = double(global_stats.pop.search.attempt     ) / global_stats.pop.search.success;
+		os << "Search      : " << srh_suc << " %, len " << srh_len << " (" << global_stats.pop.search.attempt      << " / " << global_stats.pop.search.success << ")\n";
+		os << "Search Fail : " << global_stats.pop.search.espec << "s, " << global_stats.pop.search.eempty << "e, " << global_stats.pop.search.elock << "l\n";
+		os << "Helps       : " << std::setw(15) << std::scientific << global_stats.help / duration << "/sec (" << global_stats.help  << ")\n";
 	}
 private:
Index: libcfa/src/concurrency/coroutine.cfa
===================================================================
--- libcfa/src/concurrency/coroutine.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/concurrency/coroutine.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -46,8 +46,5 @@
 
 //-----------------------------------------------------------------------------
-FORALL_DATA_INSTANCE(CoroutineCancelled, (coroutine_t &), (coroutine_t))
-
-forall(T &)
-void mark_exception(CoroutineCancelled(T) *) {}
+EHM_VIRTUAL_TABLE(SomeCoroutineCancelled, std_coroutine_cancelled);
 
 forall(T &)
@@ -71,9 +68,10 @@
 
 	// TODO: Remove explitate vtable set once trac#186 is fixed.
-	CoroutineCancelled(T) except;
-	except.virtual_table = &get_exception_vtable(&except);
+	SomeCoroutineCancelled except;
+	except.virtual_table = &std_coroutine_cancelled;
 	except.the_coroutine = &cor;
 	except.the_exception = except;
-	throwResume except;
+	// Why does this need a cast?
+	throwResume (SomeCoroutineCancelled &)except;
 
 	except->virtual_table->free( except );
Index: libcfa/src/concurrency/coroutine.hfa
===================================================================
--- libcfa/src/concurrency/coroutine.hfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/concurrency/coroutine.hfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -22,5 +22,12 @@
 //-----------------------------------------------------------------------------
 // Exception thrown from resume when a coroutine stack is cancelled.
-FORALL_DATA_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) (
+EHM_EXCEPTION(SomeCoroutineCancelled)(
+	void * the_coroutine;
+	exception_t * the_exception;
+);
+
+EHM_EXTERN_VTABLE(SomeCoroutineCancelled, std_coroutine_cancelled);
+
+EHM_FORALL_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) (
 	coroutine_t * the_coroutine;
 	exception_t * the_exception;
@@ -37,5 +44,5 @@
 // Anything that implements this trait can be resumed.
 // Anything that is resumed is a coroutine.
-trait is_coroutine(T & | IS_RESUMPTION_EXCEPTION(CoroutineCancelled, (T))) {
+trait is_coroutine(T & | IS_RESUMPTION_EXCEPTION(SomeCoroutineCancelled)) {
 	void main(T & this);
 	$coroutine * get_coroutine(T & this);
Index: libcfa/src/concurrency/kernel.cfa
===================================================================
--- libcfa/src/concurrency/kernel.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/concurrency/kernel.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -359,4 +359,5 @@
 				#if !defined(__CFA_NO_STATISTICS__)
 					__tls_stats()->ready.threads.threads++;
+					__push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this );
 				#endif
 				// This is case 2, the racy case, someone tried to run this thread before it finished blocking
@@ -376,4 +377,5 @@
 	#if !defined(__CFA_NO_STATISTICS__)
 		__tls_stats()->ready.threads.threads--;
+		__push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this );
 	#endif
 
@@ -455,7 +457,9 @@
 		if( kernelTLS().this_stats ) {
 			__tls_stats()->ready.threads.threads++;
+			__push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", kernelTLS().this_processor );
 		}
 		else {
 			__atomic_fetch_add(&cl->stats->ready.threads.threads, 1, __ATOMIC_RELAXED);
+			__push_stat( cl->stats, cl->stats->ready.threads.threads, true, "Cluster", cl );
 		}
 	#endif
Index: libcfa/src/concurrency/kernel/startup.cfa
===================================================================
--- libcfa/src/concurrency/kernel/startup.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/concurrency/kernel/startup.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -268,4 +268,7 @@
 			__print_stats( st, mainProcessor->print_stats, "Processor ", mainProcessor->name, (void*)mainProcessor );
 		}
+		#if defined(CFA_STATS_ARRAY)
+			__flush_stat( st, "Processor", mainProcessor );
+		#endif
 	#endif
 
@@ -348,4 +351,7 @@
 			__print_stats( &local_stats, proc->print_stats, "Processor ", proc->name, (void*)proc );
 		}
+		#if defined(CFA_STATS_ARRAY)
+			__flush_stat( &local_stats, "Processor", proc );
+		#endif
 	#endif
 
@@ -615,4 +621,7 @@
 			__print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this );
 		}
+		#if defined(CFA_STATS_ARRAY)
+			__flush_stat( this.stats, "Cluster", &this );
+		#endif
 		free( this.stats );
 	#endif
Index: libcfa/src/concurrency/stats.cfa
===================================================================
--- libcfa/src/concurrency/stats.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/concurrency/stats.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -5,4 +5,5 @@
 #include <inttypes.h>
 #include "bits/debug.hfa"
+#include "bits/locks.hfa"
 #include "stats.hfa"
 
@@ -44,4 +45,9 @@
 			stats->io.calls.errors.busy = 0;
 			stats->io.poller.sleeps     = 0;
+		#endif
+
+		#if defined(CFA_STATS_ARRAY)
+			stats->array.values = alloc(CFA_STATS_ARRAY);
+			stats->array.cnt = 0;
 		#endif
 	}
@@ -151,3 +157,48 @@
 		#endif
 	}
+
+	#if defined(CFA_STATS_ARRAY)
+		extern "C" {
+			#include <stdio.h>
+			#include <errno.h>
+			#include <sys/stat.h>
+			#include <fcntl.h>
+		}
+
+		void __flush_stat( struct __stats_t * this, const char * name, void * handle) {
+			int ret = mkdir(".cfadata", 0755);
+			if(ret < 0 && errno != EEXIST) abort("Failed to create directory .cfadata: %d\n", errno);
+
+			char filename[100];
+			snprintf(filename, 100, ".cfadata/%s%p.data", name, handle);
+
+			int fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0644);
+			if(fd < 0) abort("Failed to create file %s: %d\n", filename, errno);
+
+			for(i; this->array.cnt) {
+				char line[100];
+				size_t n = snprintf(line, 100, "%llu, %lld\n", this->array.values[i].ts, this->array.values[i].value);
+				write(fd, line, n);
+			}
+
+			this->array.cnt = 0;
+			close(fd);
+		}
+
+		static __spinlock_t stats_lock;
+
+		void __push_stat( struct __stats_t * this, int64_t value, bool external, const char * name, void * handle ) {
+			if(external) lock(stats_lock __cfaabi_dbg_ctx2);
+
+			if( this->array.cnt >= CFA_STATS_ARRAY ) __flush_stat( this, name, handle );
+
+			size_t idx = this->array.cnt;
+			this->array.cnt++;
+
+			if(external) unlock(stats_lock);
+
+			this->array.values[idx].ts = rdtscl();
+			this->array.values[idx].value = value;
+		}
+	#endif
 #endif
Index: libcfa/src/concurrency/stats.hfa
===================================================================
--- libcfa/src/concurrency/stats.hfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/concurrency/stats.hfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -1,3 +1,5 @@
 #pragma once
+
+// #define CFA_STATS_ARRAY 10000
 
 #include <stdint.h>
@@ -109,4 +111,11 @@
 	#endif
 
+	#if defined(CFA_STATS_ARRAY)
+		struct __stats_elem_t {
+			long long int ts;
+			int64_t value;
+		};
+	#endif
+
 	struct __attribute__((aligned(128))) __stats_t {
 		__stats_readQ_t ready;
@@ -114,4 +123,12 @@
 			__stats_io_t    io;
 		#endif
+
+		#if defined(CFA_STATS_ARRAY)
+			struct {
+				__stats_elem_t * values;
+				volatile size_t cnt;
+			} array;
+		#endif
+
 	};
 
@@ -119,4 +136,11 @@
 	void __tally_stats( struct __stats_t *, struct __stats_t * );
 	void __print_stats( struct __stats_t *, int, const char *, const char *, void * );
+	#if defined(CFA_STATS_ARRAY)
+		void __push_stat ( struct __stats_t *, int64_t value, bool external, const char * name, void * handle);
+		void __flush_stat( struct __stats_t *, const char *, void * );
+	#else
+		static inline void __push_stat ( struct __stats_t *, int64_t, bool, const char *, void * ) {}
+		static inline void __flush_stat( struct __stats_t *, const char *, void * ) {}
+	#endif
 #endif
 
Index: libcfa/src/concurrency/thread.cfa
===================================================================
--- libcfa/src/concurrency/thread.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/concurrency/thread.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -62,5 +62,5 @@
 }
 
-FORALL_DATA_INSTANCE(ThreadCancelled, (thread_t &), (thread_t))
+EHM_VIRTUAL_TABLE(SomeThreadCancelled, std_thread_cancelled);
 
 forall(T &)
@@ -73,21 +73,27 @@
 forall(T &)
 const char * msg(ThreadCancelled(T) *) {
-	return "ThreadCancelled";
+	return "ThreadCancelled(...)";
 }
 
 forall(T &)
 static void default_thread_cancel_handler(ThreadCancelled(T) & ) {
+	// Improve this error message, can I do formatting?
 	abort( "Unhandled thread cancellation.\n" );
 }
 
-forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)))
+static void default_thread_cancel_handler(SomeThreadCancelled & ) {
+	// Improve this error message, can I do formatting?
+	abort( "Unhandled thread cancellation.\n" );
+}
+
+forall(T & | is_thread(T) | IS_EXCEPTION(SomeThreadCancelled))
 void ?{}( thread_dtor_guard_t & this,
-		T & thrd, void(*cancelHandler)(ThreadCancelled(T) &)) {
- 	$monitor * m = get_monitor(thrd);
+		T & thrd, void(*cancelHandler)(SomeThreadCancelled &)) {
+	$monitor * m = get_monitor(thrd);
 	$thread * desc = get_thread(thrd);
 
 	// Setup the monitor guard
 	void (*dtor)(T& mutex this) = ^?{};
-	bool join = cancelHandler != (void(*)(ThreadCancelled(T)&))0;
+	bool join = cancelHandler != (void(*)(SomeThreadCancelled&))0;
 	(this.mg){&m, (void(*)())dtor, join};
 
@@ -103,13 +109,14 @@
 	}
 	desc->state = Cancelled;
-	void(*defaultResumptionHandler)(ThreadCancelled(T) &) = 
+	void(*defaultResumptionHandler)(SomeThreadCancelled &) =
 		join ? cancelHandler : default_thread_cancel_handler;
 
-	ThreadCancelled(T) except;
 	// TODO: Remove explitate vtable set once trac#186 is fixed.
-	except.virtual_table = &get_exception_vtable(&except);
+	SomeThreadCancelled except;
+	except.virtual_table = &std_thread_cancelled;
 	except.the_thread = &thrd;
 	except.the_exception = __cfaehm_cancellation_exception( cancellation );
-	throwResume except;
+	// Why is this cast required?
+	throwResume (SomeThreadCancelled &)except;
 
 	except.the_exception->virtual_table->free( except.the_exception );
@@ -158,5 +165,5 @@
 
 //-----------------------------------------------------------------------------
-forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)))
+forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(SomeThreadCancelled))
 T & join( T & this ) {
 	thread_dtor_guard_t guard = { this, defaultResumptionHandler };
Index: libcfa/src/concurrency/thread.hfa
===================================================================
--- libcfa/src/concurrency/thread.hfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/concurrency/thread.hfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -32,5 +32,12 @@
 };
 
-FORALL_DATA_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (
+EHM_EXCEPTION(SomeThreadCancelled) (
+	void * the_thread;
+	exception_t * the_exception;
+);
+
+EHM_EXTERN_VTABLE(SomeThreadCancelled, std_thread_cancelled);
+
+EHM_FORALL_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (
 	thread_t * the_thread;
 	exception_t * the_exception;
@@ -79,6 +86,6 @@
 };
 
-forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) )
-void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) );
+forall( T & | is_thread(T) | IS_EXCEPTION(SomeThreadCancelled) )
+void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(SomeThreadCancelled &) );
 void ^?{}( thread_dtor_guard_t & this );
 
@@ -125,5 +132,5 @@
 //----------
 // join
-forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) )
+forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(SomeThreadCancelled) )
 T & join( T & this );
 
Index: libcfa/src/exception.c
===================================================================
--- libcfa/src/exception.c	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/exception.c	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -10,6 +10,6 @@
 // Created On       : Mon Jun 26 15:13:00 2017
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Oct 27 16:27:00 2020
-// Update Count     : 35
+// Last Modified On : Wed Feb 24 13:40:00 2021
+// Update Count     : 36
 //
 
@@ -26,4 +26,5 @@
 #include "concurrency/invoke.h"
 #include "stdhdr/assert.h"
+#include "virtual.h"
 
 #if defined( __ARM_ARCH )
@@ -46,12 +47,7 @@
 const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643;
 
-// Base exception vtable is abstract, you should not have base exceptions.
-struct __cfaehm_base_exception_t_vtable
-		___cfaehm_base_exception_t_vtable_instance = {
-	.parent = NULL,
-	.size = 0,
-	.copy = NULL,
-	.free = NULL,
-	.msg = NULL
+// Base Exception type id:
+struct __cfa__parent_vtable __cfatid_exception_t = {
+	NULL,
 };
 
Index: libcfa/src/exception.h
===================================================================
--- libcfa/src/exception.h	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/exception.h	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -10,6 +10,6 @@
 // Created On       : Mon Jun 26 15:11:00 2017
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Oct 27 14:45:00 2020
-// Update Count     : 11
+// Last Modified On : Thr Apr  8 15:20:00 2021
+// Update Count     : 12
 //
 
@@ -29,6 +29,7 @@
 struct __cfaehm_base_exception_t;
 typedef struct __cfaehm_base_exception_t exception_t;
+struct __cfa__parent_vtable;
 struct __cfaehm_base_exception_t_vtable {
-	const struct __cfaehm_base_exception_t_vtable * parent;
+	const struct __cfa__parent_vtable * __cfavir_typeid;
 	size_t size;
 	void (*copy)(struct __cfaehm_base_exception_t *this,
@@ -40,6 +41,5 @@
 	struct __cfaehm_base_exception_t_vtable const * virtual_table;
 };
-extern struct __cfaehm_base_exception_t_vtable
-	___cfaehm_base_exception_t_vtable_instance;
+extern struct __cfa__parent_vtable __cfatid_exception_t;
 
 
@@ -104,7 +104,7 @@
 	/* The first field must be a pointer to a virtual table.
 	 * That virtual table must be a decendent of the base exception virtual table.
+	 * The virtual table must point at the prober type-id.
+	 * None of these can be enforced in an assertion.
 	 */
-	virtualT const & get_exception_vtable(exceptT *);
-	// Always returns the virtual table for this type (associated types hack).
 };
 
Index: libcfa/src/exception.hfa
===================================================================
--- libcfa/src/exception.hfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/exception.hfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -10,6 +10,6 @@
 // Created On       : Thu Apr  7 10:25:00 2020
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Aug  4 16:22:00 2020
-// Update Count     : 3
+// Last Modified On : Thr Apr  8 15:16:00 2021
+// Update Count     : 4
 //
 
@@ -18,111 +18,53 @@
 // -----------------------------------------------------------------------------------------------
 
-// TRIVIAL_EXCEPTION_DECLARATION(exception_name);
-// Declare a trivial exception, one that adds no fields or features.
-// This will make the exception visible and may go in a .hfa or .cfa file.
-#define TRIVIAL_EXCEPTION_DECLARATION(...) \
-	_EXC_DISPATCH(_TRIVIAL_EXCEPTION_DECLARATION, __VA_ARGS__)
+// EHM_EXCEPTION(exception_name)(fields...);
+// Create an exception (a virtual structure that inherits from exception_t)
+// with the given name and fields.
+#define EHM_EXCEPTION(exception_name) \
+	_EHM_TYPE_ID_STRUCT(exception_name, ); \
+	_EHM_TYPE_ID_VALUE(exception_name, ); \
+	_EHM_VIRTUAL_TABLE_STRUCT(exception_name, , ); \
+	_EHM_EXCEPTION_STRUCT(exception_name, , )
 
-// TRIVIAL_EXCEPTION_INSTANCE(exception_name);
-// Create the trival exception. This must be used exactly once and should be used in a .cfa file,
-// as it creates the unique instance of the virtual table.
-#define TRIVIAL_EXCEPTION_INSTANCE(...) _EXC_DISPATCH(_TRIVIAL_EXCEPTION_INSTANCE, __VA_ARGS__)
+// EHM_EXTERN_VTABLE(exception_name, table_name);
+// Forward declare a virtual table called table_name for exception_name type.
+#define EHM_EXTERN_VTABLE(exception_name, table_name) \
+	_EHM_EXTERN_VTABLE(exception_name, , table_name)
 
-// TRIVIAL_EXCEPTION(exception_name[, parent_name]);
-// Does both of the above, a short hand if the exception is only used in one .cfa file.
-// For legacy reasons this is the only one that official supports having a parent other than the
-// base exception. This feature may be removed or changed.
-#define TRIVIAL_EXCEPTION(...) \
-	_EXC_DISPATCH(_TRIVIAL_EXCEPTION_DECLARATION, __VA_ARGS__); \
-	_EXC_DISPATCH(_TRIVIAL_EXCEPTION_INSTANCE, __VA_ARGS__)
+// EHM_VIRTUAL_TABLE(exception_name, table_name);
+// Define a virtual table called table_name for exception_name type.
+#define EHM_VIRTUAL_TABLE(exception_name, table_name) \
+	_EHM_DEFINE_COPY(exception_name, ) \
+	_EHM_DEFINE_MSG(exception_name, ) \
+	_EHM_VIRTUAL_TABLE(exception_name, , table_name)
 
-// FORALL_TRIVIAL_EXCEPTION(exception_name, (assertions...), (parameters...));
-// Forward declare a polymorphic but otherwise trivial exception type. You must provide the entire
-// assertion list (exactly what would go in the forall clause) and parameters list (only the
-// parameter names from the assertion list, same order and comma seperated). This should be
-// visible where ever use the exception. This just generates the polymorphic framework, see
-// POLY_VTABLE_DECLARATION to allow instantiations.
-#define FORALL_TRIVIAL_EXCEPTION(exception_name, assertions, parameters) \
-	_FORALL_TRIVIAL_EXCEPTION(exception_name, __cfaehm_base_exception_t, assertions, parameters, )
+// EHM_FORALL_EXCEPTION(exception_name, (assertions), (parameters))(fields...);
+// As EHM_EXCEPTION but for polymorphic types instead of monomorphic ones.
+// The assertions list should include all polymorphic parameters and
+// assertions inside a parentisized list. Parameters should include all the
+// polymorphic parameter names inside a parentisized list (same order).
+#define EHM_FORALL_EXCEPTION(exception_name, assertions, parameters) \
+	_EHM_TYPE_ID_STRUCT(exception_name, forall assertions); \
+	_EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall assertions, parameters); \
+	_EHM_EXCEPTION_STRUCT(exception_name, forall assertions, parameters)
 
-// FORALL_TRIVIAL_INSTANCE(exception_name, (assertions...), (parameters...))
-// Create the forall trivial exception. The assertion list and parameters must match.
-// There must be exactly one use of this in a program for each exception type. This just
-// generates the polymorphic framework, see POLY_VTABLE_INSTANCE to allow instantiations.
-#define FORALL_TRIVIAL_INSTANCE(exception_name, assertions, parameters) \
-	_FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters)
+// EHM_FORALL_EXTERN_VTABLE(exception_name, (arguments), table_name);
+// As EHM_EXTERN_VTABLE but for polymorphic types instead of monomorphic ones.
+// Arguments should be the parentisized list of polymorphic arguments.
+#define EHM_FORALL_EXTERN_VTABLE(exception_name, arguments, table_name) \
+	_EHM_EXTERN_VTABLE(exception_name, arguments, table_name)
 
-// DATA_EXCEPTION(exception_name)(fields...);
-// Forward declare an exception that adds fields but no features. The added fields go in the
-// second argument list. The virtual table instance must be provided later (see VTABLE_INSTANCE).
-#define DATA_EXCEPTION(...) _EXC_DISPATCH(_DATA_EXCEPTION, __VA_ARGS__)
+// EHM_FORALL_VIRTUAL_TABLE(exception_name, (arguments), table_name);
+// As EHM_VIRTUAL_TABLE but for polymorphic types instead of monomorphic ones.
+// Arguments should be the parentisized list of polymorphic arguments.
+#define EHM_FORALL_VIRTUAL_TABLE(exception_name, arguments, table_name) \
+	_EHM_TYPE_ID_VALUE(exception_name, arguments); \
+	_EHM_DEFINE_COPY(exception_name, arguments) \
+	_EHM_DEFINE_MSG(exception_name, arguments) \
+	_EHM_VIRTUAL_TABLE(exception_name, arguments, table_name)
 
-// FORALL_DATA_EXCEPTION(exception_name, (assertions...), (parameters...))(fields...);
-// Define a polymorphic exception that adds fields but no additional features. The assertion list
-// and matching parameters must match. Then you can give the list of fields. This should be
-// visible where ever you use the exception. This just generates the polymorphic framework, see
-// POLY_VTABLE_DECLARATION to allow instantiations.
-#define FORALL_DATA_EXCEPTION(exception_name, assertions, parameters) \
-	_FORALL_DATA_EXCEPTION(exception_name, __cfaehm_base_exception_t, assertions, parameters, )
+#define EHM_TYPE_ID(exception_name) _EHM_TYPE_ID_TYPE(exception_name)
 
-// FORALL_DATA_INSTANCE(exception_name, (assertions...), (parameters...))
-// Create a polymorphic data exception. The assertion list and parameters must match. This should
-// appear once in each program. This just generates the polymorphic framework, see
-// POLY_VTABLE_INSTANCE to allow instantiations.
-#define FORALL_DATA_INSTANCE(exception_name, assertions, parameters) \
-	_FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters)
-
-// VTABLE_DECLARATION(exception_name)([new_features...]);
-// Declare a virtual table type for an exception with exception_name. You may also add features
-// (fields on the virtual table) by including them in the second list.
-#define VTABLE_DECLARATION(...) _EXC_DISPATCH(_VTABLE_DECLARATION, __VA_ARGS__)
-
-// VTABLE_INSTANCE(exception_name)(msg [, others...]);
-// Create the instance of the virtual table. There must be exactly one instance of a virtual table
-// for each exception type. This fills in most of the fields of the virtual table (uses ?=? and
-// ^?{}) but you must provide the message function and any other fields added in the declaration.
-#define VTABLE_INSTANCE(...) _EXC_DISPATCH(_VTABLE_INSTANCE, __VA_ARGS__)
-
-// FORALL_VTABLE_DECLARATION(exception_name, (assertions...), (parameters...))([new_features...]);
-// Declare a polymorphic virtual table type for an exception with exception_name, the given
-// assertions and parameters. You may also add features (fields on the virtual table). This just
-// generates the polymorphic framework, see POLY_VTABLE_DECLARATION to allow instantiations.
-#define FORALL_VTABLE_DECLARATION(exception_name, assertions, parameters) \
-	_FORALL_VTABLE_DECLARATION(exception_name, __cfaehm_base_exception_t, assertions, parameters, )
-
-// POLY_VTABLE_DECLARATION(exception_name, types...);
-// Declares that an instantiation for this exception exists for the given types. This should be
-// visible anywhere you use the instantiation of the exception is used.
-#define POLY_VTABLE_DECLARATION(exception_name, ...) \
-	VTABLE_TYPE(exception_name)(__VA_ARGS__) const & get_exception_vtable(exception_name(__VA_ARGS__) *); \
-	extern VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name)
-
-// POLY_VTABLE_INSTANCE(exception_name, types...)(msg [, others...]);
-// Creates an instantiation for the given exception for the given types. This should occur only
-// once in the entire program. You must fill in all features, message and any others given in the
-// initial declaration.
-#define POLY_VTABLE_INSTANCE(exception_name, ...) \
-	_POLY_VTABLE_INSTANCE(exception_name, __cfaehm_base_exception_t, __VA_ARGS__)
-
-// VTABLE_TYPE(exception_name) | VTABLE_NAME(exception_name)
-// Get the name of the vtable type or the name of the vtable instance for an exception type.
-#define VTABLE_TYPE(exception_name) struct _GLUE2(exception_name,_vtable)
-#define VTABLE_NAME(exception_name) _GLUE3(_,exception_name,_vtable_instance)
-
-// VTABLE_FIELD(exception_name);
-// FORALL_VTABLE_FIELD(exception_name, (parameters-or-types));
-// The declaration of the virtual table field. Should be the first declaration in a virtual type.
-#define VTABLE_FIELD(exception_name) VTABLE_TYPE(exception_name) const * virtual_table
-#define FORALL_VTABLE_FIELD(exception_name, parameters) \
-	VTABLE_TYPE(exception_name) parameters const * virtual_table
-
-// VTABLE_INIT(object_reference, exception_name);
-// Sets a virtual table field on an object to the virtual table instance for the type.
-#define VTABLE_INIT(this, exception_name) (this).virtual_table = &VTABLE_NAME(exception_name)
-
-// VTABLE_ASSERTION(exception_name, (parameters...))
-// The assertion that there is an instantiation of the vtable for the exception and types.
-#define VTABLE_ASSERTION(exception_name, parameters) \
-	{ VTABLE_TYPE(exception_name) parameters VTABLE_NAME(exception_name); }
+#define EHM_MATCH_ALL __cfa__parent_vtable
 
 // IS_EXCEPTION(exception_name [, (...parameters)])
@@ -135,113 +77,113 @@
 #define IS_TERMINATION_EXCEPTION(...) _IS_EXCEPTION(is_termination_exception, __VA_ARGS__, , ~)
 
-// All internal helper macros begin with an underscore.
-#define _CLOSE(...) __VA_ARGS__ }
-#define _GLUE2(left, right) left##right
-#define _GLUE3(left, middle, right) left##middle##right
-#define _EXC_DISPATCH(to, ...) to(__VA_ARGS__,__cfaehm_base_exception_t,)
-#define _UNPACK(...) __VA_ARGS__
+// Macros starting with a leading underscore are internal.
 
-#define _TRIVIAL_EXCEPTION_DECLARATION(exception_name, parent_name, ...) \
-	_VTABLE_DECLARATION(exception_name, parent_name)(); \
-	struct exception_name { \
-		VTABLE_FIELD(exception_name); \
-	}; \
-	void ?{}(exception_name & this); \
-	const char * _GLUE2(exception_name,_msg)(exception_name * this)
+// Create an exception type definition. must be tailing, can be polymorphic.
+#define _EHM_EXCEPTION_STRUCT(exception_name, forall_clause, parameters) \
+	forall_clause struct exception_name { \
+		_EHM_VTABLE_TYPE(exception_name) parameters const * virtual_table; \
+		_CLOSE
 
-#define _TRIVIAL_EXCEPTION_INSTANCE(exception_name, parent_name, ...) \
-	void ?{}(exception_name & this) { \
-		VTABLE_INIT(this, exception_name); \
-	} \
-	const char * _GLUE2(exception_name,_msg)(exception_name * this) { \
-		return #exception_name; \
-	} \
-	_VTABLE_INSTANCE(exception_name, parent_name,)(_GLUE2(exception_name,_msg))
+// Create a (possibly polymorphic) virtual table forward declaration.
+#define _EHM_EXTERN_VTABLE(exception_name, arguments, table_name) \
+	extern const _EHM_VTABLE_TYPE(exception_name) arguments table_name
 
-#define _FORALL_TRIVIAL_EXCEPTION(exception_name, parent_name, assertions, \
-		parameters, parent_parameters) \
-	_FORALL_VTABLE_DECLARATION(exception_name, parent_name, assertions, \
-		parameters, parent_parameters)(); \
-	forall assertions struct exception_name { \
-		FORALL_VTABLE_FIELD(exception_name, parameters); \
-	}; \
-	_FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters)
-
-#define _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) \
-	forall(_UNPACK assertions | \
-		is_exception(exception_name parameters, VTABLE_TYPE(exception_name) parameters)) \
-	void ?{}(exception_name parameters & this)
-
-#define _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters) \
-	_FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) { \
-		(this).virtual_table = &get_exception_vtable(&this); \
+// Create a (possibly polymorphic) virtual table definition.
+#define _EHM_VIRTUAL_TABLE(exception_type, arguments, table_name) \
+	const _EHM_VTABLE_TYPE(exception_type) arguments table_name @= { \
+		.__cfavir_typeid : &_EHM_TYPE_ID_NAME(exception_type), \
+		.size : sizeof(struct exception_type arguments), \
+		.copy : copy, \
+		.^?{} : ^?{}, \
+		.msg : msg, \
 	}
 
-#define _DATA_EXCEPTION(exception_name, parent_name, ...) \
-	_VTABLE_DECLARATION(exception_name, parent_name)(); \
-	struct exception_name { \
-		VTABLE_FIELD(exception_name); \
-		_CLOSE
+// Create a (possibly polymorphic) copy function from an assignment operator.
+#define _EHM_DEFINE_FORALL_COPY(exception_name, forall_clause, parameters) \
+	forall_clause void copy(exception_name parameters * this, \
+			exception_name parameters * that) { \
+		*this = *that; \
+	}
 
-#define _FORALL_DATA_EXCEPTION(exception_name, parent_name, \
-		assertions, parameters, parent_parameters) \
-	_FORALL_VTABLE_DECLARATION(exception_name, parent_name, \
-		assertions, parameters, parent_parameters)(); \
-	_FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters); \
-	forall assertions struct exception_name { \
-		FORALL_VTABLE_FIELD(exception_name, parameters); \
-		_CLOSE
+#define _EHM_DEFINE_COPY(exception_name, arguments) \
+	void copy(exception_name arguments * this, exception_name arguments * that) { \
+		*this = *that; \
+	}
 
-#define _VTABLE_DECLARATION(exception_name, parent_name, ...) \
-	struct exception_name; \
-	VTABLE_TYPE(exception_name); \
-	VTABLE_TYPE(exception_name) const & get_exception_vtable(exception_name *); \
-	extern VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name); \
-	VTABLE_TYPE(exception_name) { \
-		VTABLE_TYPE(parent_name) const * parent; \
-		size_t size; \
-		void (*copy)(exception_name * this, exception_name * other); \
-		void (*^?{})(exception_name & this); \
-		const char * (*msg)(exception_name * this); \
-		_CLOSE
+// Create a (possibly polymorphic) msg function
+#define _EHM_DEFINE_FORALL_MSG(exception_name, forall_clause, parameters) \
+	forall_clause const char * msg(exception_name parameters * this) { \
+		return #exception_name #parameters; \
+	}
 
-#define _VTABLE_INSTANCE(exception_name, parent_name, ...) \
-	VTABLE_TYPE(exception_name) const & get_exception_vtable(exception_name *) { \
-		return VTABLE_NAME(exception_name); \
-	} \
-	void _GLUE2(exception_name,_copy)(exception_name * this, exception_name * other) { \
-		*this = *other; \
-	} \
-	VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name) @= { \
-		&VTABLE_NAME(parent_name), sizeof(exception_name), \
-		_GLUE2(exception_name,_copy), ^?{}, \
-		_CLOSE
+#define _EHM_DEFINE_MSG(exception_name, arguments) \
+	const char * msg(exception_name arguments * this) { \
+		return #exception_name #arguments; \
+	}
 
-#define _FORALL_VTABLE_DECLARATION(exception_name, parent_name, assertions, \
-		parameters, parent_parameters) \
-	forall assertions struct exception_name; \
-	forall assertions VTABLE_TYPE(exception_name) { \
-		VTABLE_TYPE(parent_name) parent_parameters const * parent; \
+// Produces the C compatable name of the virtual table type for a virtual type.
+#define _EHM_VTABLE_TYPE(type_name) struct _GLUE2(type_name,_vtable)
+
+// Create the vtable type for exception name.
+#define _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall_clause, parameters) \
+	forall_clause struct exception_name; \
+	forall_clause _EHM_VTABLE_TYPE(exception_name) { \
+		_EHM_TYPE_ID_TYPE(exception_name) parameters const * __cfavir_typeid; \
 		size_t size; \
 		void (*copy)(exception_name parameters * this, exception_name parameters * other); \
 		void (*^?{})(exception_name parameters & this); \
 		const char * (*msg)(exception_name parameters * this); \
-		_CLOSE
+	}
 
-#define _POLY_VTABLE_INSTANCE(exception_name, parent_name, ...) \
-	extern VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name); \
-	VTABLE_TYPE(exception_name)(__VA_ARGS__) const & get_exception_vtable( \
-			exception_name(__VA_ARGS__) *) { \
-		return VTABLE_NAME(exception_name); \
-	} \
-	void _GLUE2(exception_name,_copy)( \
-			exception_name(__VA_ARGS__) * this, exception_name(__VA_ARGS__) * other) { \
-		*this = *other; \
-	} \
-	VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name) @= { \
-		&VTABLE_NAME(parent_name), sizeof(exception_name(__VA_ARGS__)), \
-		_GLUE2(exception_name,_copy), ^?{}, \
-		_CLOSE
+// Define the function required to satify the trait for exceptions.
+#define _EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \
+	forall_clause inline void mark_exception( \
+		exception_name parameters const &, \
+		_EHM_VTABLE_TYPE(exception_name) parameters const &) {} \
+
+#define _EHM_TRAIT_FUNCTION2(exception_name, forall_clause, parameters) \
+	forall_clause _EHM_VTABLE_TYPE(exception_name) parameters const & \
+			get_exception_vtable(exception_name parameters const & this)
+
+#define __EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \
+	forall_clause inline _EHM_VTABLE_TYPE(exception_name) parameters const & \
+			get_exception_vtable(exception_name parameters const & this) { \
+		/* This comes before the structure definition, but we know the offset. */ \
+		/* return (_EHM_VTABLE_TYPE(exception_name) parameters const &)this; */ \
+		assert(false); \
+	}
+
+// Generates a new type-id structure. This is used to mangle the name of the
+// type-id instance so it also includes polymorphic information. Must be the
+// direct decendent of exception_t.
+// The second field is used to recover type information about the exception.
+#define _EHM_TYPE_ID_STRUCT(exception_name, forall_clause) \
+	forall_clause _EHM_TYPE_ID_TYPE(exception_name) { \
+		__cfa__parent_vtable const * parent; \
+	}
+
+// Generate a new type-id value.
+#define _EHM_TYPE_ID_VALUE(exception_name, arguments) \
+	__attribute__(( section(".gnu.linkonce." "__cfatid_" #exception_name) )) \
+	_EHM_TYPE_ID_TYPE(exception_name) arguments const \
+			_EHM_TYPE_ID_NAME(exception_name) = { \
+		&__cfatid_exception_t, \
+	}
+
+// _EHM_TYPE_ID_STRUCT and _EHM_TYPE_ID_VALUE are the two that would need to
+// be updated to extend the hierarchy if we are still using macros when that
+// is added.
+
+// Produce the C compatable name of the type-id type for an exception type.
+#define _EHM_TYPE_ID_TYPE(exception_name) \
+	struct _GLUE2(__cfatid_struct_, exception_name)
+
+// Produce the name of the instance of the type-id for an exception type.
+#define _EHM_TYPE_ID_NAME(exception_name) _GLUE2(__cfatid_,exception_name)
 
 #define _IS_EXCEPTION(kind, exception_name, parameters, ...) \
-	kind(exception_name parameters, VTABLE_TYPE(exception_name) parameters)
+	kind(exception_name parameters, _EHM_VTABLE_TYPE(exception_name) parameters)
+
+// Internal helper macros:
+#define _CLOSE(...) __VA_ARGS__ }
+#define _GLUE2(left, right) left##right
Index: libcfa/src/fstream.cfa
===================================================================
--- libcfa/src/fstream.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/fstream.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -321,18 +321,15 @@
 
 
+EHM_VIRTUAL_TABLE(Open_Failure, Open_Failure_main_table);
 void ?{}( Open_Failure & this, ofstream & ostream ) {
-	VTABLE_INIT(this, Open_Failure);
+	this.virtual_table = &Open_Failure_main_table;
 	this.ostream = &ostream;
 	this.tag = 1;
 }
 void ?{}( Open_Failure & this, ifstream & istream ) {
-	VTABLE_INIT(this, Open_Failure);
+	this.virtual_table = &Open_Failure_main_table;
 	this.istream = &istream;
 	this.tag = 0;
 }
-const char * Open_Failure_msg(Open_Failure * this) {
-	return "Open_Failure";
-}
-VTABLE_INSTANCE(Open_Failure)(Open_Failure_msg);
 void throwOpen_Failure( ofstream & ostream ) {
 	Open_Failure exc = { ostream };
Index: libcfa/src/fstream.hfa
===================================================================
--- libcfa/src/fstream.hfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/fstream.hfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -133,5 +133,5 @@
 
 
-DATA_EXCEPTION(Open_Failure)(
+EHM_EXCEPTION(Open_Failure)(
 	union {
 		ofstream * ostream;
Index: libcfa/src/virtual.c
===================================================================
--- libcfa/src/virtual.c	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ libcfa/src/virtual.c	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -15,7 +15,9 @@
 
 #include "virtual.h"
+#include "assert.h"
 
 int __cfa__is_parent( struct __cfa__parent_vtable const * parent,
     	struct __cfa__parent_vtable const * child ) {
+	assert( child );
 	do {
 		if ( parent == child )
@@ -28,4 +30,5 @@
 void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent,
     	struct __cfa__parent_vtable const * const * child ) {
+	assert( child );
 	return (__cfa__is_parent(parent, *child)) ? (void *)child : (void *)0;
 }
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ src/AST/Expr.cpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -260,4 +260,13 @@
 }
 
+ConstantExpr * ConstantExpr::from_string( const CodeLocation & loc, const std::string & str ) {
+	const Type * charType = new BasicType( BasicType::Char );
+	// Adjust the length of the string for the terminator.
+	const Expr * strSize = from_ulong( loc, str.size() + 1 );
+	const Type * strType = new ArrayType( charType, strSize, FixedLen, StaticDim );
+	const std::string strValue = "\"" + str + "\"";
+	return new ConstantExpr( loc, strType, strValue, std::nullopt );
+}
+
 ConstantExpr * ConstantExpr::null( const CodeLocation & loc, const Type * ptrType ) {
 	return new ConstantExpr{
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ src/AST/Expr.hpp	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -438,11 +438,13 @@
 	long long int intValue() const;
 
-	/// generates a boolean constant of the given bool
+	/// Generates a boolean constant of the given bool.
 	static ConstantExpr * from_bool( const CodeLocation & loc, bool b );
-	/// generates an integer constant of the given int
+	/// Generates an integer constant of the given int.
 	static ConstantExpr * from_int( const CodeLocation & loc, int i );
-	/// generates an integer constant of the given unsigned long int
+	/// Generates an integer constant of the given unsigned long int.
 	static ConstantExpr * from_ulong( const CodeLocation & loc, unsigned long i );
-	/// generates a null pointer value for the given type. void * if omitted.
+	/// Generates a string constant from the given string (char type, unquoted string).
+	static ConstantExpr * from_string( const CodeLocation & loc, const std::string & string );
+	/// Generates a null pointer value for the given type. void * if omitted.
 	static ConstantExpr * null( const CodeLocation & loc, const Type * ptrType = nullptr );
 
Index: src/Concurrency/Keywords.cc
===================================================================
--- src/Concurrency/Keywords.cc	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ src/Concurrency/Keywords.cc	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -42,6 +42,9 @@
 
 namespace Concurrency {
+	inline static std::string getTypeIdName( std::string const & exception_name ) {
+		return exception_name.empty() ? std::string() : Virtual::typeIdType( exception_name );
+	}
 	inline static std::string getVTableName( std::string const & exception_name ) {
-		return exception_name.empty() ? std::string() : Virtual::vtableTypeName(exception_name);
+		return exception_name.empty() ? std::string() : Virtual::vtableTypeName( exception_name );
 	}
 
@@ -75,4 +78,5 @@
 		  type_name( type_name ), field_name( field_name ), getter_name( getter_name ),
 		  context_error( context_error ), exception_name( exception_name ),
+		  typeid_name( getTypeIdName( exception_name ) ),
 		  vtable_name( getVTableName( exception_name ) ),
 		  needs_main( needs_main ), cast_target( cast_target ) {}
@@ -84,4 +88,5 @@
 
 		void handle( StructDecl * );
+		void addTypeId( StructDecl * );
 		void addVtableForward( StructDecl * );
 		FunctionDecl * forwardDeclare( StructDecl * );
@@ -99,4 +104,5 @@
 		const std::string context_error;
 		const std::string exception_name;
+		const std::string typeid_name;
 		const std::string vtable_name;
 		bool needs_main;
@@ -106,4 +112,5 @@
 		FunctionDecl * dtor_decl = nullptr;
 		StructDecl * except_decl = nullptr;
+		StructDecl * typeid_decl = nullptr;
 		StructDecl * vtable_decl = nullptr;
 	};
@@ -392,4 +399,7 @@
 		else if ( !except_decl && exception_name == decl->name && decl->body ) {
 			except_decl = decl;
+		}
+		else if ( !typeid_decl && typeid_name == decl->name && decl->body ) {
+			typeid_decl = decl;
 		}
 		else if ( !vtable_decl && vtable_name == decl->name && decl->body ) {
@@ -448,5 +458,11 @@
 		if( !dtor_decl ) SemanticError( decl, context_error );
 
-		addVtableForward( decl );
+		if ( !exception_name.empty() ) {
+			if( !typeid_decl ) SemanticError( decl, context_error );
+			if( !vtable_decl ) SemanticError( decl, context_error );
+
+			addTypeId( decl );
+			addVtableForward( decl );
+		}
 		FunctionDecl * func = forwardDeclare( decl );
 		ObjectDecl * field = addField( decl );
@@ -454,19 +470,24 @@
 	}
 
+	void ConcurrentSueKeyword::addTypeId( StructDecl * decl ) {
+		assert( typeid_decl );
+		StructInstType typeid_type( Type::Const, typeid_decl );
+		typeid_type.parameters.push_back( new TypeExpr(
+			new StructInstType( noQualifiers, decl )
+			) );
+		declsToAddBefore.push_back( Virtual::makeTypeIdInstance( &typeid_type ) );
+	}
+
 	void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) {
-		if ( vtable_decl ) {
-			std::list< Expression * > poly_args = {
-				new TypeExpr( new StructInstType( noQualifiers, decl ) ),
-			};
-			declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
-				vtable_decl->makeInst( poly_args ),
-				except_decl->makeInst( poly_args )
-			) );
-			declsToAddBefore.push_back( Virtual::makeVtableForward(
-				vtable_decl->makeInst( move( poly_args ) ) ) );
-		// Its only an error if we want a vtable and don't have one.
-		} else if ( ! vtable_name.empty() ) {
-			SemanticError( decl, context_error );
-		}
+		assert( vtable_decl );
+		std::list< Expression * > poly_args = {
+			new TypeExpr( new StructInstType( noQualifiers, decl ) ),
+		};
+		declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
+			vtable_decl->makeInst( poly_args ),
+			except_decl->makeInst( poly_args )
+		) );
+		declsToAddBefore.push_back( Virtual::makeVtableForward(
+			vtable_decl->makeInst( move( poly_args ) ) ) );
 	}
 
Index: src/SynTree/Constant.cc
===================================================================
--- src/SynTree/Constant.cc	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ src/SynTree/Constant.cc	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -42,4 +42,13 @@
 }
 
+Constant Constant::from_string( const std::string & str ) {
+	Type * charType = new BasicType( noQualifiers, BasicType::Char );
+	// Adjust the length of the string for the terminator.
+	Expression * strSize = new ConstantExpr( Constant::from_ulong( str.size() + 1 ) );
+	Type * strType = new ArrayType( noQualifiers, charType, strSize, false, false );
+	const std::string strValue = "\"" + str + "\"";
+	return Constant( strType, strValue, std::nullopt );
+}
+
 Constant Constant::null( Type * ptrtype ) {
 	if ( nullptr == ptrtype ) {
Index: src/SynTree/Constant.h
===================================================================
--- src/SynTree/Constant.h	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ src/SynTree/Constant.h	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -47,4 +47,6 @@
 	/// generates an integer constant of the given unsigned long int
 	static Constant from_ulong( unsigned long i );
+	/// generates a string constant from the given string (char type, unquoted string)
+	static Constant from_string( const std::string & string );
 
 	/// generates a null pointer value for the given type. void * if omitted.
Index: src/Virtual/ExpandCasts.cc
===================================================================
--- src/Virtual/ExpandCasts.cc	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ src/Virtual/ExpandCasts.cc	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -32,4 +32,14 @@
 namespace Virtual {
 
+static bool is_prefix( const std::string & prefix, const std::string& entire ) {
+	size_t const p_size = prefix.size();
+	return (p_size < entire.size() && prefix == entire.substr(0, p_size));
+}
+
+static bool is_type_id_object( const ObjectDecl * objectDecl ) {
+	const std::string & objectName = objectDecl->name;
+	return is_prefix( "__cfatid_", objectName );
+}
+
 	// Indented until the new ast code gets added.
 
@@ -66,38 +76,6 @@
 	};
 
-	/* Currently virtual depends on the rather brittle name matching between
-	 * a (strict/explicate) virtual type, its vtable type and the vtable
-	 * instance.
-	 * A stronger implementation, would probably keep track of those triads
-	 * and use that information to create better error messages.
-	 */
-
-	namespace {
-
-	std::string get_vtable_name( std::string const & name ) {
-		return name + "_vtable";
-	}
-
-	std::string get_vtable_inst_name( std::string const & name ) {
-		return std::string("_") + get_vtable_name( name ) + "_instance";
-	}
-
-	std::string get_vtable_name_root( std::string const & name ) {
-		return name.substr(0, name.size() - 7 );
-	}
-
-	std::string get_vtable_inst_name_root( std::string const & name ) {
-		return get_vtable_name_root( name.substr(1, name.size() - 10 ) );
-	}
-
-	bool is_vtable_inst_name( std::string const & name ) {
-		return 17 < name.size() &&
-			name == get_vtable_inst_name( get_vtable_inst_name_root( name ) );
-	}
-
-	} // namespace
-
 	class VirtualCastCore {
-		Type * pointer_to_pvt(int level_of_indirection) {
+		CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) {
 			Type * type = new StructInstType(
 				Type::Qualifiers( Type::Const ), pvt_decl );
@@ -105,5 +83,5 @@
 				type = new PointerType( noQualifiers, type );
 			}
-			return type;
+			return new CastExpr( expr, type );
 		}
 
@@ -141,11 +119,7 @@
 
 	void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
-		if ( is_vtable_inst_name( objectDecl->get_name() ) ) {
-			if ( ObjectDecl * existing = indexer.insert( objectDecl ) ) {
-				std::string msg = "Repeated instance of virtual table, original found at: ";
-				msg += existing->location.filename;
-				msg += ":" + toString( existing->location.first_line );
-				SemanticError( objectDecl->location, msg );
-			}
+		if ( is_type_id_object( objectDecl ) ) {
+			// Multiple definitions should be fine because of linkonce.
+			indexer.insert( objectDecl );
 		}
 	}
@@ -170,52 +144,87 @@
 	}
 
-	/// Get the virtual table type used in a virtual cast.
-	Type * getVirtualTableType( const VirtualCastExpr * castExpr ) {
-		const Type * objectType;
-		if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) {
-			objectType = target->base;
-		} else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) {
-			objectType = target->base;
+	/// Get the base type from a pointer or reference.
+	const Type * getBaseType( const Type * type ) {
+		if ( auto target = dynamic_cast<const PointerType *>( type ) ) {
+			return target->base;
+		} else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) {
+			return target->base;
 		} else {
-			castError( castExpr, "Virtual cast type must be a pointer or reference type." );
-		}
-		assert( objectType );
-
-		const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType );
-		if ( nullptr == structType ) {
-			castError( castExpr, "Virtual cast type must refer to a structure type." );
-		}
-		const StructDecl * structDecl = structType->baseStruct;
-		assert( structDecl );
-
-		const ObjectDecl * fieldDecl = nullptr;
-		if ( 0 < structDecl->members.size() ) {
-			const Declaration * memberDecl = structDecl->members.front();
+			return nullptr;
+		}
+	}
+
+	/* Attempt to follow the "head" field of the structure to get the...
+	 * Returns nullptr on error, otherwise owner must free returned node.
+	 */
+	StructInstType * followHeadPointerType(
+			const StructInstType * oldType,
+			const std::string& fieldName,
+			const CodeLocation& errorLocation ) {
+
+		// First section of the function is all about trying to fill this variable in.
+		StructInstType * newType = nullptr;
+		{
+			const StructDecl * oldDecl = oldType->baseStruct;
+			assert( oldDecl );
+
+			// Helper function for throwing semantic errors.
+			auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) {
+				const std::string& context = "While following head pointer of " +
+					oldDecl->name + " named '" + fieldName + "': ";
+				SemanticError( errorLocation, context + message );
+			};
+
+			if ( oldDecl->members.empty() ) {
+				throwError( "Type has no fields." );
+			}
+			const Declaration * memberDecl = oldDecl->members.front();
 			assert( memberDecl );
-			fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
-			if ( fieldDecl && fieldDecl->name != "virtual_table" ) {
-				fieldDecl = nullptr;
-			}
-		}
-		if ( nullptr == fieldDecl ) {
-			castError( castExpr, "Virtual cast type must have a leading virtual_table field." );
-		}
-		const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type );
-		if ( nullptr == fieldType ) {
-			castError( castExpr, "Virtual cast type virtual_table field is not a pointer." );
-		}
-		assert( fieldType->base );
-		auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base );
-		assert( virtualStructType );
-
-		// Here is the type, but if it is polymorphic it will have lost information.
-		// (Always a clone so that it may always be deleted.)
-		StructInstType * virtualType = virtualStructType->clone();
-		if ( ! structType->parameters.empty() ) {
-			deleteAll( virtualType->parameters );
-			virtualType->parameters.clear();
-			cloneAll( structType->parameters, virtualType->parameters );
-		}
-		return virtualType;
+			const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
+			assert( fieldDecl );
+			if ( fieldName != fieldDecl->name ) {
+				throwError( "Head field did not have expected name." );
+			}
+
+			const Type * fieldType = fieldDecl->type;
+			if ( nullptr == fieldType ) {
+				throwError( "Could not get head field." );
+			}
+			const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType );
+			if ( nullptr == ptrType ) {
+				throwError( "First field is not a pointer type." );
+			}
+			assert( ptrType->base );
+			newType = dynamic_cast<StructInstType *>( ptrType->base );
+			if ( nullptr == newType ) {
+				throwError( "First field does not point to a structure type." );
+			}
+		}
+
+		// Now we can look into copying it.
+		newType = newType->clone();
+		if ( ! oldType->parameters.empty() ) {
+			deleteAll( newType->parameters );
+			newType->parameters.clear();
+			cloneAll( oldType->parameters, newType->parameters );
+		}
+		return newType;
+	}
+
+	/// Get the type-id type from a virtual type.
+	StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) {
+		const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type );
+		if ( nullptr == typeInst ) {
+			return nullptr;
+		}
+		StructInstType * tableInst =
+			followHeadPointerType( typeInst, "virtual_table", errorLocation );
+		if ( nullptr == tableInst ) {
+			return nullptr;
+		}
+		StructInstType * typeIdInst =
+			followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation );
+		delete tableInst;
+		return typeIdInst;
 	}
 
@@ -228,21 +237,22 @@
 		assert( pvt_decl );
 
-		const Type * vtable_type = getVirtualTableType( castExpr );
-		ObjectDecl * table = indexer.lookup( vtable_type );
-		if ( nullptr == table ) {
-			SemanticError( castLocation( castExpr ),
-				"Could not find virtual table instance." );
+		const Type * base_type = getBaseType( castExpr->result );
+		if ( nullptr == base_type ) {
+			castError( castExpr, "Virtual cast target must be a pointer or reference type." );
+		}
+		const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) );
+		if ( nullptr == type_id_type ) {
+			castError( castExpr, "Ill formed virtual cast target type." );
+		}
+		ObjectDecl * type_id = indexer.lookup( type_id_type );
+		delete type_id_type;
+		if ( nullptr == type_id ) {
+			castError( castExpr, "Virtual cast does not target a virtual type." );
 		}
 
 		Expression * result = new CastExpr(
 			new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
-					new CastExpr(
-						new AddressExpr( new VariableExpr( table ) ),
-						pointer_to_pvt(1)
-					),
-					new CastExpr(
-						castExpr->get_arg(),
-						pointer_to_pvt(2)
-					)
+				cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ),
+				cast_to_type_id( castExpr->get_arg(), 2 ),
 			} ),
 			castExpr->get_result()->clone()
@@ -252,5 +262,4 @@
 		castExpr->set_result( nullptr );
 		delete castExpr;
-		delete vtable_type;
 		return result;
 	}
Index: src/Virtual/Tables.cc
===================================================================
--- src/Virtual/Tables.cc	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ src/Virtual/Tables.cc	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -10,6 +10,6 @@
 // Created On       : Mon Aug 31 11:11:00 2020
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Sep  3 14:56:00 2020
-// Update Count     : 0
+// Last Modified On : Thr Apr  8 15:51:00 2021
+// Update Count     : 1
 //
 
@@ -22,6 +22,22 @@
 namespace Virtual {
 
+std::string typeIdType( std::string const & type_name ) {
+	return "__cfatid_struct_" + type_name;
+}
+
+std::string typeIdName( std::string const & type_name ) {
+	return "__cfatid_" + type_name;
+}
+
+static std::string typeIdTypeToInstance( std::string const & type_name ) {
+	return typeIdName(type_name.substr(16));
+}
+
 std::string vtableTypeName( std::string const & name ) {
 	return name + "_vtable";
+}
+
+std::string baseTypeName( std::string const & vtable_type_name ) {
+	return vtable_type_name.substr(0, vtable_type_name.size() - 7);
 }
 
@@ -81,4 +97,8 @@
 				inits.push_back(
 						new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) );
+			} else if ( std::string( "__cfavir_typeid" ) == field->name ) {
+				std::string const & baseType = baseTypeName( vtableType->name );
+				std::string const & typeId = typeIdName( baseType );
+				inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) );
 			} else if ( std::string( "size" ) == field->name ) {
 				inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) );
@@ -147,3 +167,33 @@
 }
 
+ObjectDecl * makeTypeIdForward() {
+	return nullptr;
 }
+
+Attribute * linkonce( const std::string & subsection ) {
+	const std::string section = ".gnu.linkonce." + subsection;
+	return new Attribute( "section", {
+		new ConstantExpr( Constant::from_string( section ) ),
+	} );
+}
+
+ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {
+	assert( typeIdType );
+	StructInstType * type = typeIdType->clone();
+	type->tq.is_const = true;
+	std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );
+	return new ObjectDecl(
+		typeid_name,
+		noStorageClasses,
+		LinkageSpec::Cforall,
+		/* bitfieldWidth */ nullptr,
+		type,
+		new ListInit( { new SingleInit(
+			new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )
+			) } ),
+		{ linkonce( typeid_name ) },
+		noFuncSpecifiers
+	);
+}
+
+}
Index: src/Virtual/Tables.h
===================================================================
--- src/Virtual/Tables.h	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ src/Virtual/Tables.h	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -10,6 +10,6 @@
 // Created On       : Mon Aug 31 11:07:00 2020
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Sep  1 14:29:00 2020
-// Update Count     : 0
+// Last Modified On : Thr Apr  8 15:55:00 2021
+// Update Count     : 1
 //
 
@@ -22,4 +22,6 @@
 namespace Virtual {
 
+std::string typeIdType( std::string const & type_name );
+std::string typeIdName( std::string const & type_name );
 std::string vtableTypeName( std::string const & type_name );
 std::string instanceName( std::string const & vtable_name );
@@ -50,3 +52,8 @@
  */
 
+ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );
+/* Build an instance of the type-id from the type of the type-id.
+ * TODO: Should take the parent type. Currently locked to the exception_t.
+ */
+
 }
Index: tests/exceptions/.expect/resume-threads.txt
===================================================================
--- tests/exceptions/.expect/resume-threads.txt	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/.expect/resume-threads.txt	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -6,7 +6,4 @@
 
 catch-all
-
-throwing child exception
-inner parent match
 
 caught yin as yin
Index: tests/exceptions/.expect/resume.txt
===================================================================
--- tests/exceptions/.expect/resume.txt	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/.expect/resume.txt	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -6,7 +6,4 @@
 
 catch-all
-
-throwing child exception
-inner parent match
 
 caught yin as yin
Index: tests/exceptions/.expect/terminate-threads.txt
===================================================================
--- tests/exceptions/.expect/terminate-threads.txt	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/.expect/terminate-threads.txt	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -5,7 +5,4 @@
 
 catch-all
-
-throwing child exception
-inner parent match
 
 caught yin as yin
Index: tests/exceptions/.expect/terminate.txt
===================================================================
--- tests/exceptions/.expect/terminate.txt	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/.expect/terminate.txt	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -5,7 +5,4 @@
 
 catch-all
-
-throwing child exception
-inner parent match
 
 caught yin as yin
Index: tests/exceptions/cancel/coroutine.cfa
===================================================================
--- tests/exceptions/cancel/coroutine.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/cancel/coroutine.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -4,5 +4,6 @@
 #include <exception.hfa>
 
-TRIVIAL_EXCEPTION(internal_error);
+EHM_EXCEPTION(internal_error)();
+EHM_VIRTUAL_TABLE(internal_error, internal_vt);
 
 coroutine WillCancel {};
@@ -14,5 +15,5 @@
 void main(WillCancel & wc) {
 	printf("1");
-	cancel_stack((internal_error){});
+	cancel_stack((internal_error){&internal_vt});
 	printf("!");
 }
@@ -24,5 +25,5 @@
 		resume(cancel);
 		printf("4");
-	} catchResume (CoroutineCancelled(WillCancel) * error) {
+	} catchResume (SomeCoroutineCancelled * error) {
 		printf("2");
 		if ((virtual internal_error *)error->the_exception) {
Index: tests/exceptions/cancel/thread.cfa
===================================================================
--- tests/exceptions/cancel/thread.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/cancel/thread.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -4,5 +4,6 @@
 #include <exception.hfa>
 
-TRIVIAL_EXCEPTION(internal_error);
+EHM_EXCEPTION(internal_error)();
+EHM_VIRTUAL_TABLE(internal_error, internal_vt);
 
 thread WillCancel {};
@@ -14,5 +15,5 @@
 void main(WillCancel &) {
 	printf("1");
-	cancel_stack((internal_error){});
+	cancel_stack((internal_error){&internal_vt});
 	printf("!");
 }
@@ -25,5 +26,5 @@
 		join(cancel);
 		printf("4");
-	} catchResume (ThreadCancelled(WillCancel) * error) {
+	} catchResume (SomeThreadCancelled * error) {
 		printf("2");
 		if ((virtual internal_error *)error->the_exception) {
@@ -42,5 +43,5 @@
 		}
 		printf("4");
-	} catchResume (ThreadCancelled(WillCancel) * error) {
+	} catchResume (SomeThreadCancelled * error) {
 		printf("2");
 		if ((virtual internal_error *)error->the_exception) {
Index: tests/exceptions/conditional.cfa
===================================================================
--- tests/exceptions/conditional.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/conditional.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -6,44 +6,9 @@
 #include <exception.hfa>
 
-VTABLE_DECLARATION(num_error)(
-	int (*code)(num_error *this);
+EHM_EXCEPTION(num_error)(
+	int num;
 );
 
-struct num_error {
-	VTABLE_FIELD(num_error);
-    char * msg;
-    int num;
-};
-
-const char * num_error_msg(num_error * this) {
-    if ( ! this->msg ) {
-        static const char * base = "Num Error with code: X";
-        this->msg = (char *)malloc(22);
-        for (int i = 0 ; (this->msg[i] = base[i]) ; ++i);
-    }
-    this->msg[21] = '0' + this->num;
-    return this->msg;
-}
-void ?{}(num_error & this, int num) {
-	VTABLE_INIT(this, num_error);
-    this.msg = 0;
-    this.num = num;
-}
-void ?{}(num_error & this, num_error & other) {
-    this.virtual_table = other.virtual_table;
-    this.msg = 0;
-    this.num = other.num;
-}
-void ^?{}(num_error & this) {
-    if( this.msg ) free( this.msg );
-}
-int num_error_code( num_error * this ) {
-    return this->num;
-}
-
-VTABLE_INSTANCE(num_error)(
-	num_error_msg,
-	num_error_code,
-);
+EHM_VIRTUAL_TABLE(num_error, num_error_vt);
 
 void caught_num_error(int expect, num_error * actual) {
@@ -52,11 +17,11 @@
 
 int main(int argc, char * argv[]) {
-	num_error exc = 2;
+	num_error exc = {&num_error_vt, 2};
 
 	try {
 		throw exc;
-	} catch (num_error * error ; 3 == error->virtual_table->code( error )) {
+	} catch (num_error * error ; 3 == error->num ) {
 		caught_num_error(3, error);
-	} catch (num_error * error ; 2 == error->virtual_table->code( error )) {
+	} catch (num_error * error ; 2 == error->num ) {
 		caught_num_error(2, error);
 	}
@@ -64,7 +29,7 @@
 	try {
 		throwResume exc;
-	} catchResume (num_error * error ; 3 == error->virtual_table->code( error )) {
+	} catchResume (num_error * error ; 3 == error->num ) {
 		caught_num_error(3, error);
-	} catchResume (num_error * error ; 2 == error->virtual_table->code( error )) {
+	} catchResume (num_error * error ; 2 == error->num ) {
 		caught_num_error(2, error);
 	}
Index: tests/exceptions/data-except.cfa
===================================================================
--- tests/exceptions/data-except.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/data-except.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -3,44 +3,34 @@
 #include <exception.hfa>
 
-DATA_EXCEPTION(paired)(
+EHM_EXCEPTION(paired)(
 	int first;
 	int second;
 );
 
-void ?{}(paired & this, int first, int second) {
-	VTABLE_INIT(this, paired);
-	this.first = first;
-	this.second = second;
-}
+EHM_VIRTUAL_TABLE(paired, paired_vt);
 
-const char * paired_msg(paired * this) {
-	return "paired";
-}
-
-VTABLE_INSTANCE(paired)(paired_msg);
-
-void throwPaired(int first, int second) {
-	paired exc = {first, second};
+const char * virtual_msg(paired * this) {
+	return this->virtual_table->msg(this);
 }
 
 int main(int argc, char * argv[]) {
-	paired except = {3, 13};
+	paired except = {&paired_vt, 3, 13};
 
 	try {
 		throw except;
 	} catch (paired * exc) {
-		printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second);
+		printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second);
 		++exc->first;
 	}
 
-	printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second);
+	printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second);
 
 	try {
 		throwResume except;
 	} catchResume (paired * exc) {
-		printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second);
+		printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second);
 		++exc->first;
 	}
 
-	printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second);
+	printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second);
 }
Index: tests/exceptions/defaults.cfa
===================================================================
--- tests/exceptions/defaults.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/defaults.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -4,18 +4,13 @@
 #include <exception.hfa>
 
-DATA_EXCEPTION(log_message)(
+EHM_EXCEPTION(log_message)(
 	char * msg;
 );
 
-void ?{}(log_message & this, char * msg) {
-	VTABLE_INIT(this, log_message);
-	this.msg = msg;
-}
-
-const char * get_log_message(log_message * this) {
+_EHM_DEFINE_COPY(log_message, )
+const char * msg(log_message * this) {
 	return this->msg;
 }
-
-VTABLE_INSTANCE(log_message)(get_log_message);
+_EHM_VIRTUAL_TABLE(log_message, , log_vt);
 
 // Logging messages don't have to be handled.
@@ -28,34 +23,39 @@
 	// We can catch log:
 	try {
-		throwResume (log_message){"Should be printed.\n"};
+		throwResume (log_message){&log_vt, "Should be printed.\n"};
 	} catchResume (log_message * this) {
 		printf("%s", this->virtual_table->msg(this));
 	}
 	// But we don't have to:
-	throwResume (log_message){"Should not be printed.\n"};
+	throwResume (log_message){&log_vt, "Should not be printed.\n"};
 }
 
 // I don't have a good use case for doing the same with termination.
-TRIVIAL_EXCEPTION(jump);
+EHM_EXCEPTION(jump)();
 void defaultTerminationHandler(jump &) {
 	printf("jump default handler.\n");
 }
 
+EHM_VIRTUAL_TABLE(jump, jump_vt);
+
 void jump_test(void) {
 	try {
-		throw (jump){};
+		throw (jump){&jump_vt};
 	} catch (jump * this) {
 		printf("jump catch handler.\n");
 	}
-	throw (jump){};
+	throw (jump){&jump_vt};
 }
 
-TRIVIAL_EXCEPTION(first);
-TRIVIAL_EXCEPTION(unhandled_exception);
+EHM_EXCEPTION(first)();
+EHM_VIRTUAL_TABLE(first, first_vt);
+
+EHM_EXCEPTION(unhandled_exception)();
+EHM_VIRTUAL_TABLE(unhandled_exception, unhandled_vt);
 
 void unhandled_test(void) {
 	forall(T &, V & | is_exception(T, V))
 	void defaultTerminationHandler(T &) {
-		throw (unhandled_exception){};
+		throw (unhandled_exception){&unhandled_vt};
 	}
 	void defaultTerminationHandler(unhandled_exception &) {
@@ -63,5 +63,5 @@
 	}
 	try {
-		throw (first){};
+		throw (first){&first_vt};
 	} catch (unhandled_exception * t) {
 		printf("Catch unhandled_exception.\n");
@@ -69,18 +69,19 @@
 }
 
-TRIVIAL_EXCEPTION(second);
+EHM_EXCEPTION(second)();
+EHM_VIRTUAL_TABLE(second, second_vt);
 
 void cross_test(void) {
 	void defaultTerminationHandler(first &) {
 		printf("cross terminate default\n");
-		throw (second){};
+		throw (second){&second_vt};
 	}
 	void defaultResumptionHandler(first &) {
 		printf("cross resume default\n");
-		throwResume (second){};
+		throwResume (second){&second_vt};
 	}
 	try {
 		printf("cross terminate throw\n");
-		throw (first){};
+		throw (first){&first_vt};
 	} catch (second *) {
 		printf("cross terminate catch\n");
@@ -88,5 +89,5 @@
 	try {
 		printf("cross resume throw\n");
-		throwResume (first){};
+		throwResume (first){&first_vt};
 	} catchResume (second *) {
 		printf("cross resume catch\n");
Index: tests/exceptions/finally.cfa
===================================================================
--- tests/exceptions/finally.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/finally.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -4,8 +4,10 @@
 #include "except-io.hfa"
 
-TRIVIAL_EXCEPTION(myth);
+EHM_EXCEPTION(myth)();
+
+EHM_VIRTUAL_TABLE(myth, myth_vt);
 
 int main(int argc, char * argv[]) {
-	myth exc;
+	myth exc = {&myth_vt};
 
 	try {
Index: tests/exceptions/interact.cfa
===================================================================
--- tests/exceptions/interact.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/interact.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -4,11 +4,14 @@
 #include "except-io.hfa"
 
-TRIVIAL_EXCEPTION(star);
-TRIVIAL_EXCEPTION(moon);
+EHM_EXCEPTION(star)();
+EHM_EXCEPTION(moon)();
+
+EHM_VIRTUAL_TABLE(star, star_vt);
+EHM_VIRTUAL_TABLE(moon, moon_vt);
 
 int main(int argc, char * argv[]) {
 	// Resume falls back to terminate.
 	try {
-		throwResume (star){};
+		throwResume (star){&star_vt};
 	} catch (star *) {
 		printf("caught as termination\n");
@@ -17,5 +20,5 @@
 	try {
 		loud_region a = "try block with resume throw";
-		throwResume (star){};
+		throwResume (star){&star_vt};
 	} catch (star *) {
 		printf("caught as termination\n");
@@ -29,5 +32,5 @@
 	try {
 		try {
-			throw (star){};
+			throw (star){&star_vt};
 		} catchResume (star *) {
 			printf("resume catch on terminate\n");
@@ -43,5 +46,5 @@
 	try {
 		try {
-			throwResume (star){};
+			throwResume (star){&star_vt};
 		} catch (star *) {
 			printf("terminate catch on resume\n");
@@ -58,5 +61,5 @@
 		try {
 			try {
-				throw (star){};
+				throw (star){&star_vt};
 			} catchResume (star *) {
 				printf("inner resume catch (error)\n");
@@ -75,5 +78,5 @@
 		try {
 			try {
-				throwResume (star){};
+				throwResume (star){&star_vt};
 			} catch (star *) {
 				printf("inner termination catch\n");
@@ -94,10 +97,10 @@
 				try {
 					printf("throwing resume moon\n");
-					throwResume (moon){};
+					throwResume (moon){&moon_vt};
 				} catch (star *) {
 					printf("termination catch\n");
 				}
 				printf("throwing resume star\n");
-				throwResume (star){};
+				throwResume (star){&star_vt};
 			} catchResume (star *) {
 				printf("resumption star catch\n");
@@ -105,5 +108,5 @@
 		} catchResume (moon *) {
 			printf("resumption moon catch, will terminate\n");
-			throw (star){};
+			throw (star){&star_vt};
 		}
 	} catchResume (star *) {
Index: tests/exceptions/polymorphic.cfa
===================================================================
--- tests/exceptions/polymorphic.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/polymorphic.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -3,15 +3,15 @@
 #include <exception.hfa>
 
-FORALL_TRIVIAL_EXCEPTION(proxy, (T), (T));
-FORALL_TRIVIAL_INSTANCE(proxy, (U), (U))
+EHM_FORALL_EXCEPTION(proxy, (T&), (T))();
 
-const char * msg(proxy(int) * this) { return "proxy(int)"; }
-const char * msg(proxy(char) * this) { return "proxy(char)"; }
-POLY_VTABLE_INSTANCE(proxy, int)(msg);
-POLY_VTABLE_INSTANCE(proxy, char)(msg);
+EHM_FORALL_VIRTUAL_TABLE(proxy, (int), proxy_int);
+EHM_FORALL_VIRTUAL_TABLE(proxy, (char), proxy_char);
 
 void proxy_test(void) {
+	proxy(int) an_int = {&proxy_int};
+	proxy(char) a_char = {&proxy_char};
+
     try {
-		throw (proxy(int)){};
+		throw an_int;
 	} catch (proxy(int) *) {
 		printf("terminate catch\n");
@@ -19,5 +19,5 @@
 
 	try {
-		throwResume (proxy(char)){};
+		throwResume a_char;
 	} catchResume (proxy(char) *) {
 		printf("resume catch\n");
@@ -25,5 +25,5 @@
 
 	try {
-		throw (proxy(char)){};
+		throw a_char;
 	} catch (proxy(int) *) {
 		printf("caught proxy(int)\n");
@@ -33,21 +33,15 @@
 }
 
-FORALL_DATA_EXCEPTION(cell, (T), (T))(
+EHM_FORALL_EXCEPTION(cell, (T), (T))(
 	T data;
 );
 
-FORALL_DATA_INSTANCE(cell, (T), (T))
-
-const char * msg(cell(int) * this) { return "cell(int)"; }
-const char * msg(cell(char) * this) { return "cell(char)"; }
-const char * msg(cell(bool) * this) { return "cell(bool)"; }
-POLY_VTABLE_INSTANCE(cell, int)(msg);
-POLY_VTABLE_INSTANCE(cell, char)(msg);
-POLY_VTABLE_INSTANCE(cell, bool)(msg);
+EHM_FORALL_VIRTUAL_TABLE(cell, (int), int_cell);
+EHM_FORALL_VIRTUAL_TABLE(cell, (char), char_cell);
+EHM_FORALL_VIRTUAL_TABLE(cell, (bool), bool_cell);
 
 void cell_test(void) {
 	try {
-		cell(int) except;
-		except.data = -7;
+		cell(int) except = {&int_cell, -7};
 		throw except;
 	} catch (cell(int) * error) {
@@ -56,6 +50,5 @@
 
 	try {
-		cell(bool) ball;
-		ball.data = false;
+		cell(bool) ball = {&bool_cell, false};
 		throwResume ball;
 		printf("%i\n", ball.data);
Index: tests/exceptions/resume.cfa
===================================================================
--- tests/exceptions/resume.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/resume.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -4,17 +4,24 @@
 #include "except-io.hfa"
 
-TRIVIAL_EXCEPTION(yin);
-TRIVIAL_EXCEPTION(yang);
-TRIVIAL_EXCEPTION(zen);
-TRIVIAL_EXCEPTION(moment_of, zen);
+EHM_EXCEPTION(yin)();
+EHM_EXCEPTION(yang)();
+EHM_EXCEPTION(zen)();
+
+EHM_VIRTUAL_TABLE(yin, yin_vt);
+EHM_VIRTUAL_TABLE(yang, yang_vt);
+EHM_VIRTUAL_TABLE(zen, zen_vt);
 
 void in_void(void);
 
 int main(int argc, char * argv[]) {
+	yin a_yin = {&yin_vt};
+	yang a_yang = {&yang_vt};
+	zen a_zen = {&zen_vt};
+
 	// The simple throw catchResume test.
 	try {
 		loud_exit a = "simple try clause";
 		printf("simple throw\n");
-		throwResume (zen){};
+		throwResume a_zen;
 		printf("end of try clause\n");
 	} catchResume (zen * error) {
@@ -26,18 +33,7 @@
 	// Throw catch-all test.
 	try {
-		throwResume (zen){};
+		throwResume a_zen;
 	} catchResume (exception_t * error) {
 		printf("catch-all\n");
-	}
-	printf("\n");
-
-	// Catch a parent of the given exception.
-	try {
-		printf("throwing child exception\n");
-		throwResume (moment_of){};
-	} catchResume (zen *) {
-		printf("inner parent match\n");
-	} catchResume (moment_of *) {
-		printf("outer exact match\n");
 	}
 	printf("\n");
@@ -46,5 +42,5 @@
 	try {
 		try {
-			throwResume (yin){};
+			throwResume a_yin;
 		} catchResume (zen *) {
 			printf("caught yin as zen\n");
@@ -62,5 +58,5 @@
 			loud_exit a = "rethrow inner try";
 			printf("rethrow inner try\n");
-			throwResume (zen){};
+			throwResume a_zen;
 		} catchResume (zen *) {
 			loud_exit a = "rethrowing catch clause";
@@ -77,8 +73,8 @@
 	try {
 		try {
-			throwResume (yin){};
+			throwResume a_yin;
 		} catchResume (yin *) {
 			printf("caught yin, will throw yang\n");
-			throwResume (yang){};
+			throwResume a_yang;
 		} catchResume (yang *) {
 			printf("caught exception from same try\n");
@@ -93,10 +89,10 @@
 		try {
 			printf("throwing first exception\n");
-			throwResume (yin){};
+			throwResume a_yin;
 		} catchResume (yin *) {
 			printf("caught first exception\n");
 			try {
 				printf("throwing second exception\n");
-				throwResume (yang){};
+				throwResume a_yang;
 			} catchResume (yang *) {
 				printf("caught second exception\n");
@@ -114,10 +110,10 @@
 	try {
 		try {
-			throwResume (zen){};
-			throwResume (zen){};
+			throwResume a_zen;
+			throwResume a_zen;
 		} catchResume (zen *) {
 			printf("inner catch\n");
 		}
-		throwResume (zen){};
+		throwResume a_zen;
 	} catchResume (zen *) {
 		printf("outer catch\n");
@@ -130,8 +126,9 @@
 // Do a throw and rethrow in a void function.
 void in_void(void) {
+    zen a_zen = {&zen_vt};
 	try {
 		try {
 			printf("throw\n");
-			throwResume (zen){};
+			throwResume a_zen;
 		} catchResume (zen *) {
 			printf("rethrow\n");
Index: tests/exceptions/terminate.cfa
===================================================================
--- tests/exceptions/terminate.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/terminate.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -4,17 +4,24 @@
 #include "except-io.hfa"
 
-TRIVIAL_EXCEPTION(yin);
-TRIVIAL_EXCEPTION(yang);
-TRIVIAL_EXCEPTION(zen);
-TRIVIAL_EXCEPTION(moment_of, zen);
+EHM_EXCEPTION(yin)();
+EHM_EXCEPTION(yang)();
+EHM_EXCEPTION(zen)();
+
+EHM_VIRTUAL_TABLE(yin, yin_vt);
+EHM_VIRTUAL_TABLE(yang, yang_vt);
+EHM_VIRTUAL_TABLE(zen, zen_vt);
 
 void in_void(void);
 
 int main(int argc, char * argv[]) {
+	yin a_yin = {&yin_vt};
+	yang a_yang = {&yang_vt};
+	zen a_zen = {&zen_vt};
+
 	// The simple throw catch test.
 	try {
 		loud_exit a = "simple try clause";
 		printf("simple throw\n");
-		throw (zen){};
+		throw a_zen;
 		printf("end of try clause\n");
 	} catch (zen * error) {
@@ -26,18 +33,7 @@
 	// Throw catch-all test.
 	try {
-		throw (zen){};
+		throw a_zen;
 	} catch (exception_t * error) {
 		printf("catch-all\n");
-	}
-	printf("\n");
-
-	// Catch a parent of the given exception.
-	try {
-		printf("throwing child exception\n");
-		throw (moment_of){};
-	} catch (zen *) {
-		printf("inner parent match\n");
-	} catch (moment_of *) {
-		printf("outer exact match\n");
 	}
 	printf("\n");
@@ -46,5 +42,5 @@
 	try {
 		try {
-			throw (yin){};
+			throw a_yin;
 		} catch (zen *) {
 			printf("caught yin as zen\n");
@@ -62,5 +58,5 @@
 			loud_exit a = "rethrow inner try";
 			printf("rethrow inner try\n");
-			throw (zen){};
+			throw a_zen;
 		} catch (zen *) {
 			loud_exit a = "rethrowing catch clause";
@@ -77,8 +73,8 @@
 	try {
 		try {
-			throw (yin){};
+			throw a_yin;
 		} catch (yin *) {
 			printf("caught yin, will throw yang\n");
-			throw (yang){};
+			throw a_yang;
 		} catch (yang *) {
 			printf("caught exception from same try\n");
@@ -93,10 +89,10 @@
 		try {
 			printf("throwing first exception\n");
-			throw (yin){};
+			throw a_yin;
 		} catch (yin *) {
 			printf("caught first exception\n");
 			try {
 				printf("throwing second exception\n");
-				throw (yang){};
+				throw a_yang;
 			} catch (yang *) {
 				printf("caught second exception\n");
@@ -114,10 +110,10 @@
 	try {
 		try {
-			throw (zen){};
-			throw (zen){};
+			throw a_zen;
+			throw a_zen;
 		} catch (zen *) {
 			printf("inner catch\n");
 		}
-		throw (zen){};
+		throw a_zen;
 	} catch (zen *) {
 		printf("outer catch\n");
@@ -130,8 +126,9 @@
 // Do a throw and rethrow in a void function.
 void in_void(void) {
+	zen a_zen = {&zen_vt};
 	try {
 		try {
 			printf("throw\n");
-			throw (zen){};
+			throw a_zen;
 		} catch (zen *) {
 			printf("rethrow\n");
Index: tests/exceptions/trash.cfa
===================================================================
--- tests/exceptions/trash.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/trash.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -3,14 +3,17 @@
 #include <exception.hfa>
 
-TRIVIAL_EXCEPTION(yin);
-TRIVIAL_EXCEPTION(yang);
+EHM_EXCEPTION(yin)();
+EHM_EXCEPTION(yang)();
+
+EHM_VIRTUAL_TABLE(yin, yin_vt);
+EHM_VIRTUAL_TABLE(yang, yang_vt);
 
 int main(int argc, char * argv[]) {
 	try {
 		try {
-			throw (yin){};
+			throw (yin){&yin_vt};
 		} finally {
 			try {
-				throw (yang){};
+				throw (yang){&yang_vt};
 			} catch (yin *) {
 				printf("inner yin\n");
Index: tests/exceptions/type-check.cfa
===================================================================
--- tests/exceptions/type-check.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/type-check.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -3,5 +3,5 @@
 #include <exception.hfa>
 
-TRIVIAL_EXCEPTION(truth);
+EHM_EXCEPTION(truth)();
 
 int main(int argc, char * argv[]) {
Index: tests/exceptions/virtual-cast.cfa
===================================================================
--- tests/exceptions/virtual-cast.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/virtual-cast.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -12,6 +12,18 @@
 #include <assert.h>
 
+
+
+// Hand defined alpha virtual type:
+struct __cfatid_struct_alpha {
+	__cfa__parent_vtable const * parent;
+};
+
+__attribute__(( section(".gnu.linkonce.__cfatid_alpha") ))
+struct __cfatid_struct_alpha __cfatid_alpha = {
+	(__cfa__parent_vtable *)0,
+};
+
 struct alpha_vtable {
-	alpha_vtable const * const parent;
+	struct __cfatid_struct_alpha const * const __cfavir_typeid;
 	char (*code)(void);
 };
@@ -27,6 +39,16 @@
 
 
+// Hand defined beta virtual type:
+struct __cfatid_struct_beta {
+	__cfatid_struct_alpha const * parent;
+};
+
+__attribute__(( section(".gnu.linkonce.__cfatid_beta") ))
+struct __cfatid_struct_beta __cfatid_beta = {
+	&__cfatid_alpha,
+};
+
 struct beta_vtable {
-	alpha_vtable const * const parent;
+	struct __cfatid_struct_beta const * const __cfavir_typeid;
 	char (*code)(void);
 };
@@ -42,6 +64,16 @@
 
 
+// Hand defined gamma virtual type:
+struct __cfatid_struct_gamma {
+	__cfatid_struct_beta const * parent;
+};
+
+__attribute__(( section(".gnu.linkonce.__cfatid_gamma") ))
+struct __cfatid_struct_gamma __cfatid_gamma = {
+	&__cfatid_beta,
+};
+
 struct gamma_vtable {
-	beta_vtable const * const parent;
+	struct __cfatid_struct_gamma const * const __cfavir_typeid;
 	char (*code)(void);
 };
@@ -57,7 +89,7 @@
 
 extern "C" {
-	alpha_vtable _alpha_vtable_instance = { 0, ret_a };
-	beta_vtable _beta_vtable_instance = { &_alpha_vtable_instance, ret_b };
-	gamma_vtable _gamma_vtable_instance = { &_beta_vtable_instance, ret_g };
+	alpha_vtable _alpha_vtable_instance = { &__cfatid_alpha, ret_a };
+	beta_vtable _beta_vtable_instance = { &__cfatid_beta, ret_b };
+	gamma_vtable _gamma_vtable_instance = { &__cfatid_gamma, ret_g };
 }
 
Index: tests/exceptions/virtual-poly.cfa
===================================================================
--- tests/exceptions/virtual-poly.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/exceptions/virtual-poly.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -8,6 +8,16 @@
 #include <assert.h>
 
+
+struct __cfatid_struct_mono_base {
+    __cfa__parent_vtable const * parent;
+};
+
+__attribute__(( section(".gnu.linkonce.__cfatid_mono_base") ))
+struct __cfatid_struct_mono_base __cfatid_mono_base = {
+    (__cfa__parent_vtable *)0,
+};
+
 struct mono_base_vtable {
-	mono_base_vtable const * const parent;
+	__cfatid_struct_mono_base const * const __cfavir_typeid;
 };
 
@@ -17,6 +27,11 @@
 
 forall(T)
+struct __cfatid_struct_mono_child {
+    __cfatid_struct_mono_base const * parent;
+};
+
+forall(T)
 struct mono_child_vtable {
-	mono_base_vtable const * const parent;
+	__cfatid_struct_mono_child(T) const * const __cfavir_typeid;
 };
 
@@ -26,7 +41,10 @@
 };
 
-mono_base_vtable _mono_base_vtable_instance @= { 0 };
+__cfatid_struct_mono_child(int) __cfatid_mono_child @= {
+	&__cfatid_mono_base,
+};
+
 mono_child_vtable(int) _mono_child_vtable_instance @= {
-	&_mono_base_vtable_instance
+	&__cfatid_mono_child,
 };
 
@@ -37,7 +55,13 @@
 }
 
+
+forall(U)
+struct __cfatid_struct_poly_base {
+    __cfa__parent_vtable const * parent;
+};
+
 forall(U)
 struct poly_base_vtable {
-	poly_base_vtable(U) const * const parent;
+	__cfatid_struct_poly_base(U) const * const __cfavir_typeid;
 };
 
@@ -48,6 +72,11 @@
 
 forall(V)
+struct __cfatid_struct_poly_child {
+    __cfatid_struct_poly_base(V) const * parent;
+};
+
+forall(V)
 struct poly_child_vtable {
-	poly_base_vtable(V) const * const parent;
+	__cfatid_struct_poly_child(V) const * const __cfavir_typeid;
 };
 
@@ -57,14 +86,13 @@
 };
 
-poly_base_vtable(int) _poly_base_vtable_instance @= { 0 };
+__cfatid_struct_poly_base(int) __cfatid_poly_base @= {
+	(__cfa__parent_vtable *)0,
+};
+__cfatid_struct_poly_child(int) __cfatid_poly_child = {
+    &__cfatid_poly_base,
+};
 poly_child_vtable(int) _poly_child_vtable_instance @= {
-	&_poly_base_vtable_instance
+	&__cfatid_poly_child,
 };
-/* Resolver bug keeps me from adding these.
-poly_base_vtable(char) _poly_base_vtable_instance @= { 0 };
-poly_child_vtable(char) _poly_child_vtable_instance @= {
-	&_poly_base_vtable_instance
-};
-*/
 
 void poly_poly_test() {
@@ -77,4 +105,4 @@
 	mono_poly_test();
 	poly_poly_test();
-	printf( "done\n" );				// non-empty .expect file
+	printf( "done\n" );
 }
Index: tests/linking/exception-nothreads.cfa
===================================================================
--- tests/linking/exception-nothreads.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/linking/exception-nothreads.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -17,9 +17,10 @@
 #include <exception.hfa>
 
-TRIVIAL_EXCEPTION(ping);
+EHM_EXCEPTION(ping)();
+EHM_VIRTUAL_TABLE(ping, ping_vt);
 
 int main(void) {
 	try {
-		throwResume (ping){};
+		throwResume (ping){&ping_vt};
 	} catchResume (ping *) {
 		printf("%s threads\n", threading_enabled() ? "with" : "no");
Index: tests/linking/exception-withthreads.cfa
===================================================================
--- tests/linking/exception-withthreads.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/linking/exception-withthreads.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -18,9 +18,10 @@
 #include "../exceptions/with-threads.hfa"
 
-TRIVIAL_EXCEPTION(ping);
+EHM_EXCEPTION(ping)();
+EHM_VIRTUAL_TABLE(ping, ping_vt);
 
 int main(void) {
 	try {
-		throwResume (ping){};
+		throwResume (ping){&ping_vt};
 	} catchResume (ping *) {
 		printf("%s threads\n", threading_enabled() ? "with" : "no");
Index: tests/quasiKeyword.cfa
===================================================================
--- tests/quasiKeyword.cfa	(revision 0effb6a0cb50458d87e129f0bb8c9608ba98fe44)
+++ tests/quasiKeyword.cfa	(revision 47e000c054a8dc58293a93fbc643e10735fd30f9)
@@ -14,5 +14,5 @@
 #include <exception.hfa>
 
-TRIVIAL_EXCEPTION( E );
+EHM_EXCEPTION( E )();
 
 void catch( int i ) {}
