Index: benchmark/basic/ttst_lock.c
===================================================================
--- benchmark/basic/ttst_lock.c	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/basic/ttst_lock.c	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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: benchmark/benchcltr.hfa
===================================================================
--- benchmark/benchcltr.hfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/benchcltr.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -114,5 +114,5 @@
 	for() {
 		sleep(100`ms);
-		end = getTimeNsec();
+		end = timeNsec();
 		Duration delta = end - start;
 		/*if(is_tty)*/ {
@@ -126,5 +126,5 @@
 }
 #else
-uint64_t getTimeNsec() {
+uint64_t timeNsec() {
 	timespec curr;
 	clock_gettime( CLOCK_REALTIME, &curr );
@@ -140,5 +140,5 @@
 	for(;;) {
 		usleep(100000);
-		end = getTimeNsec();
+		end = timeNsec();
 		uint64_t delta = end - start;
 		/*if(is_tty)*/ {
Index: benchmark/io/http/protocol.cfa
===================================================================
--- benchmark/io/http/protocol.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/io/http/protocol.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -249,5 +249,5 @@
 
 		char buff[100];
-		Time now = getTimeNsec();
+		Time now = timeNsec();
 		strftime( buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now );
 		sout | "Updated date to '" | buff | "'";
Index: benchmark/io/readv-posix.c
===================================================================
--- benchmark/io/readv-posix.c	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/io/readv-posix.c	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -111,5 +111,5 @@
 				printf("Starting\n");
 				bool is_tty = isatty(STDOUT_FILENO);
-				start = getTimeNsec();
+				start = timeNsec();
 				run = true;
 
@@ -118,5 +118,5 @@
 
 				run = false;
-				end = getTimeNsec();
+				end = timeNsec();
 				printf("\nDone\n");
 
Index: benchmark/io/readv.cfa
===================================================================
--- benchmark/io/readv.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/io/readv.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -147,5 +147,5 @@
 				printf("Starting\n");
 				bool is_tty = isatty(STDOUT_FILENO);
-				start = getTimeNsec();
+				start = timeNsec();
 				run = true;
 
@@ -156,5 +156,5 @@
 
 				run = false;
-				end = getTimeNsec();
+				end = timeNsec();
 				printf("\nDone\n");
 			}
Index: benchmark/readyQ/cycle.cc
===================================================================
--- benchmark/readyQ/cycle.cc	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/readyQ/cycle.cc	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -89,5 +89,5 @@
 
 			bool is_tty = isatty(STDOUT_FILENO);
-			start = getTimeNsec();
+			start = timeNsec();
 
 			for(int i = 0; i < nthreads; i++) {
@@ -97,5 +97,5 @@
 
 			stop = true;
-			end = getTimeNsec();
+			end = timeNsec();
 			printf("\nDone\n");
 
Index: benchmark/readyQ/cycle.cfa
===================================================================
--- benchmark/readyQ/cycle.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/readyQ/cycle.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -65,5 +65,5 @@
 
 			bool is_tty = isatty(STDOUT_FILENO);
-			start = getTimeNsec();
+			start = timeNsec();
 
 			for(i; nthreads) {
@@ -73,5 +73,5 @@
 
 			stop = true;
-			end = getTimeNsec();
+			end = timeNsec();
 			printf("\nDone\n");
 
Index: benchmark/readyQ/cycle.cpp
===================================================================
--- benchmark/readyQ/cycle.cpp	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/readyQ/cycle.cpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -93,5 +93,5 @@
 
 			bool is_tty = isatty(STDOUT_FILENO);
-			start = getTimeNsec();
+			start = timeNsec();
 
 			for(int i = 0; i < nthreads; i++) {
@@ -101,5 +101,5 @@
 
 			stop = true;
-			end = getTimeNsec();
+			end = timeNsec();
 			printf("\nDone\n");
 
Index: benchmark/readyQ/locality.cc
===================================================================
--- benchmark/readyQ/locality.cc	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/readyQ/locality.cc	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -281,5 +281,5 @@
 
 			bool is_tty = isatty(STDOUT_FILENO);
-			start = getTimeNsec();
+			start = timeNsec();
 
 			for(size_t i = 0; i < nthreads; i++) {
@@ -289,5 +289,5 @@
 
 			stop = true;
-			end = getTimeNsec();
+			end = timeNsec();
 			printf("\nDone\n");
 
Index: benchmark/readyQ/locality.cfa
===================================================================
--- benchmark/readyQ/locality.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/readyQ/locality.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -232,5 +232,5 @@
 
 			bool is_tty = isatty(STDOUT_FILENO);
-			start = getTimeNsec();
+			start = timeNsec();
 
 			for(i; nthreads) {
@@ -240,5 +240,5 @@
 
 			stop = true;
-			end = getTimeNsec();
+			end = timeNsec();
 			printf("\nDone\n");
 
Index: benchmark/readyQ/locality.cpp
===================================================================
--- benchmark/readyQ/locality.cpp	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/readyQ/locality.cpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -287,5 +287,5 @@
 
 			bool is_tty = isatty(STDOUT_FILENO);
-			start = getTimeNsec();
+			start = timeNsec();
 
 			for(size_t i = 0; i < nthreads; i++) {
@@ -295,5 +295,5 @@
 
 			stop = true;
-			end = getTimeNsec();
+			end = timeNsec();
 			printf("\nDone\n");
 
Index: benchmark/readyQ/rq_bench.hfa
===================================================================
--- benchmark/readyQ/rq_bench.hfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/readyQ/rq_bench.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -73,5 +73,5 @@
 	for() {
 		sleep(100`ms);
-		Time end = getTimeNsec();
+		Time end = timeNsec();
 		Duration delta = end - start;
 		if(is_tty) {
Index: benchmark/readyQ/rq_bench.hpp
===================================================================
--- benchmark/readyQ/rq_bench.hpp	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/readyQ/rq_bench.hpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -46,5 +46,5 @@
 	}
 
-uint64_t getTimeNsec() {
+uint64_t timeNsec() {
 	timespec curr;
 	clock_gettime( CLOCK_REALTIME, &curr );
@@ -60,5 +60,5 @@
 	for(;;) {
 		Sleeper::usleep(100000);
-		uint64_t end = getTimeNsec();
+		uint64_t end = timeNsec();
 		uint64_t delta = end - start;
 		if(is_tty) {
Index: benchmark/readyQ/yield.cfa
===================================================================
--- benchmark/readyQ/yield.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ benchmark/readyQ/yield.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -66,5 +66,5 @@
 
 				bool is_tty = isatty(STDOUT_FILENO);
-				start = getTimeNsec();
+				start = timeNsec();
 				run = true;
 
@@ -75,5 +75,5 @@
 
 				run = false;
-				end = getTimeNsec();
+				end = timeNsec();
 				printf("\nDone\n");
 			}
Index: doc/bibliography/pl.bib
===================================================================
--- doc/bibliography/pl.bib	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ doc/bibliography/pl.bib	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -1797,14 +1797,16 @@
 }
 
-@article{Delisle20,
+@article{Delisle21,
     keywords	= {concurrency, Cforall},
     contributer	= {pabuhr@plg},
     author	= {Thierry Delisle and Peter A. Buhr},
     title	= {Advanced Control-flow and Concurrency in \textsf{C}$\mathbf{\forall}$},
-    year	= 2020,
     journal	= spe,
-    pages	= {1-38},
-    note	= {\href{https://doi-org.proxy.lib.uwaterloo.ca/10.1002/spe.2925}{https://\-doi-org.proxy.lib.uwaterloo.ca/\-10.1002/\-spe.2925}},
-    note	= {},
+    month	= may,
+    year	= 2021,
+    volume	= 51,
+    number	= 5,
+    pages	= {1005-1042},
+    note	= {\href{https://onlinelibrary.wiley.com/doi/10.1002/spe.2925}{https://\-onlinelibrary.wiley.com/\-doi/\-10.1002/\-spe.2925}},
 }
 
Index: doc/theses/thierry_delisle_PhD/code/readyQ_proto/dynamic_entropy.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/dynamic_entropy.hpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/dynamic_entropy.hpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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/links.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/links.hpp	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/links.hpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -117,5 +117,5 @@
 	}
 
-	long long ts() const {
+	unsigned long long ts() const {
 		return before._links.ts;
 	}
Index: doc/theses/thierry_delisle_PhD/code/readyQ_proto/links2.hpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readyQ_proto/links2.hpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/links2.hpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -0,0 +1,115 @@
+#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(); }
+
+	node_t * head() const { return _head; }
+
+	// 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 c8a02103529bbac3a87ecc27896ddaea00e4e292)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/ntmove.cpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list.hpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list_good.cpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/randbit.cpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/relaxed_list.cpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi-packed.hpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi.hpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/utils.hpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -11,27 +11,5 @@
 #include <sys/sysinfo.h>
 
-#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;
-};
+// #include <x86intrin.h>
 
 // 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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ doc/theses/thierry_delisle_PhD/code/readyQ_proto/work_stealing.hpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -6,4 +6,5 @@
 #include <memory>
 #include <mutex>
+#include <thread>
 #include <type_traits>
 
@@ -11,7 +12,45 @@
 #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 {
+	#ifdef NO_MPSC
+		intrusive_queue_t<node_t> list;
+
+		inline auto ts() { return list.ts(); }
+		inline auto lock() { return list.lock.lock(); }
+		inline auto try_lock() { return list.lock.try_lock(); }
+		inline auto unlock() { return list.lock.unlock(); }
+
+		inline auto push( node_t * node ) { return list.push( node ); }
+		inline auto pop() { return list.pop(); }
+	#else
+		mpsc_queue<node_t> queue = {};
+		spinlock_t _lock = {};
+
+		inline auto ts() { auto h = queue.head(); return h ? h->_links.ts : 0ull; }
+		inline auto lock() { return _lock.lock(); }
+		inline auto try_lock() { return _lock.try_lock(); }
+		inline auto unlock() { return _lock.unlock(); }
+
+		inline auto push( node_t * node ) { return queue.push( node ); }
+		inline auto pop() { return queue.pop(); }
+	#endif
+
+
+};
 
 template<typename node_t>
@@ -25,7 +64,9 @@
 
 	work_stealing(unsigned _numThreads, unsigned)
-		: numThreads(_numThreads)
-		, lists(new intrusive_queue_t<node_t>[numThreads])
-		, snzi( std::log2( numThreads / 2 ), 2 )
+		: numThreads(_numThreads * nqueues)
+		, lists(new localQ_t<node_t>[numThreads])
+		// , lists(new intrusive_queue_t<node_t>[numThreads])
+		, times(new timestamp_t[numThreads])
+		// , snzi( std::log2( numThreads / 2 ), 2 )
 
 	{
@@ -40,102 +81,146 @@
 	__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++;
+		// node->_links.ts = 1;
+
+		auto & list = *({
+			unsigned i;
+			#ifdef NO_MPSC
+				do {
+			#endif
+				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);
+				}
+			#ifdef NO_MPSC
+				} while(!lists[i].try_lock());
+			#endif
+		 	&lists[i];
+		});
+
+		list.push( node );
+		#ifdef NO_MPSC
+			list.unlock();
+		#endif
+		// tls.rng2.set_raw_state( tls.rng1.get_raw_state());
+		// count++;
+		tls.stats.push.success++;
+	}
+
+	__attribute__((noinline, hot)) node_t * pop() {
+		if(tls.my_queue != outside) {
+			// if( tls.myfriend == outside ) {
+			// 	auto r  = tls.rng1.next();
+			// 	tls.myfriend = r % numThreads;
+			// 	// assert(lists[(tls.it % nqueues) + tls.my_queue].ts() >= lists[((tls.it + 1) % nqueues) + tls.my_queue].ts());
+			// 	tls.mytime = std::min(lists[(tls.it % nqueues) + tls.my_queue].ts(), lists[((tls.it + 1) % nqueues) + tls.my_queue].ts());
+			// 	// times[tls.myfriend].val = 0;
+			// 	// lists[tls.myfriend].val = 0;
+			// }
+			// // else if(times[tls.myfriend].val == 0) {
+			// // else if(lists[tls.myfriend].val == 0) {
+			// else if(times[tls.myfriend].val < tls.mytime) {
+			// // else if(times[tls.myfriend].val < lists[(tls.it % nqueues) + tls.my_queue].ts()) {
+			// 	node_t * n = try_pop(tls.myfriend, tls.stats.pop.help);
+			// 	tls.stats.help++;
+			// 	tls.myfriend = outside;
+			// 	if(n) return n;
+			// }
+			// if( tls.myfriend == outside ) {
+			// 	auto r  = tls.rng1.next();
+			// 	tls.myfriend = r % numThreads;
+			// 	tls.mytime = lists[((tls.it + 1) % nqueues) + tls.my_queue].ts();
+			// }
+			// else {
+			// 	if(times[tls.myfriend].val + 1000 < tls.mytime) {
+			// 		node_t * n = try_pop(tls.myfriend, tls.stats.pop.help);
+			// 		tls.stats.help++;
+			// 		if(n) return n;
+			// 	}
+			// 	tls.myfriend = outside;
+			// }
+
+			node_t * n = local();
+			if(n) return n;
 		}
 
-		unsigned i = node->_links.hint;
-		auto & list = lists[i];
-		list.lock.lock();
-
-		if(list.push( node )) {
-			snzi.arrive(i);
+		// try steal
+		for(int i = 0; i < 25; i++) {
+			node_t * n = steal();
+			if(n) return n;
 		}
 
-		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;
+		return search();
+	}
+
+private:
+	inline node_t * local() {
+		unsigned i = (--tls.it % nqueues) + tls.my_queue;
+		node_t * n = try_pop(i, tls.stats.pop.local);
+		if(n) return n;
+		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;
 			}
 		}
 
-		#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) {
+		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];
+		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.try_lock() ) { stat.elock++; return nullptr; }
 
 		// If list is empty, unlock and retry
 		if( list.ts() == 0 ) {
-			list.lock.unlock();
+			list.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
-		list.lock.unlock();
-		return node;
+		auto node = list.pop();
+		list.unlock();
+		stat.success++;
+		#ifdef NO_MPSC
+			// times[i].val = 1;
+			times[i].val = node.first->_links.ts;
+			// lists[i].val = node.first->_links.ts;
+			return node.first;
+		#else
+			times[i].val = node->_links.ts;
+			return node;
+		#endif
 	}
 
@@ -144,7 +229,20 @@
 
 	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;
+		unsigned long long int mytime = 0;
 		#if defined(READ)
 			unsigned it = 0;
@@ -152,26 +250,23 @@
 		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;
 
 private:
 	const unsigned numThreads;
-    	std::unique_ptr<intrusive_queue_t<node_t> []> lists;
-	__attribute__((aligned(64))) snzi_t snzi;
+    	std::unique_ptr<localQ_t<node_t> []> lists;
+    	// std::unique_ptr<intrusive_queue_t<node_t> []> lists;
+    	std::unique_ptr<timestamp_t []> times;
+	__attribute__((aligned(128))) std::atomic_size_t count;
 
 #ifndef NO_STATS
@@ -179,42 +274,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/prelude/builtins.c
===================================================================
--- libcfa/prelude/builtins.c	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/prelude/builtins.c	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -9,7 +9,7 @@
 // Author           : Peter A. Buhr
 // Created On       : Fri Jul 21 16:21:03 2017
-// Last Modified By : Andrew Beach
-// Last Modified On : Tue Oct 27 14:42:00 2020
-// Update Count     : 111
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Tue Apr 13 17:26:32 2021
+// Update Count     : 117
 //
 
@@ -125,6 +125,6 @@
 } // distribution
 
-#define __CFA_BASE_COMP_1__() if ( ep == 1 ) return 1
-#define __CFA_BASE_COMP_2__() if ( ep == 2 ) return ep << (y - 1)
+#define __CFA_BASE_COMP_1__() if ( x == 1 ) return 1
+#define __CFA_BASE_COMP_2__() if ( x == 2 ) return x << (y - 1)
 #define __CFA_EXP_OVERFLOW__() if ( y >= sizeof(y) * CHAR_BIT ) return 0
 
@@ -134,17 +134,19 @@
 	__CFA_BASE_COMP_2__();								/* special case, positive shifting for integral types */ \
 	__CFA_EXP_OVERFLOW__();								/* immediate overflow, negative exponent > 2^size-1 */ \
-	typeof(ep) op = 1;									/* accumulate odd product */ \
+	typeof(x) op = 1;									/* accumulate odd product */ \
 	for ( ; y > 1; y >>= 1 ) {							/* squaring exponentiation, O(log2 y) */ \
-		if ( (y & 1) == 1 ) op = op * ep;				/* odd ? */ \
-		ep = ep * ep; \
+		if ( (y & 1) == 1 ) op = op * x;				/* odd ? */ \
+		x = x * x; \
 	} \
-	return ep * op
+	return x * op
 
 static inline {
-	long int ?\?( int ep, unsigned int y ) { __CFA_EXP__(); }
-	long int ?\?( long int ep, unsigned long int y ) { __CFA_EXP__(); }
+	long int ?\?( int x, unsigned int y ) { __CFA_EXP__(); }
+	long int ?\?( long int x, unsigned long int y ) { __CFA_EXP__(); }
+	long long int ?\?( long long int x, unsigned long long int y ) { __CFA_EXP__(); }
 	// unsigned computation may be faster and larger
-	unsigned long int ?\?( unsigned int ep, unsigned int y ) { __CFA_EXP__(); }
-	unsigned long int ?\?( unsigned long int ep, unsigned long int y ) { __CFA_EXP__(); }
+	unsigned long int ?\?( unsigned int x, unsigned int y ) { __CFA_EXP__(); }
+	unsigned long int ?\?( unsigned long int x, unsigned long int y ) { __CFA_EXP__(); }
+	unsigned long long int ?\?( unsigned long long int x, unsigned long long int y ) { __CFA_EXP__(); }
 } // distribution
 
@@ -157,6 +159,7 @@
 
 static inline forall( OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) {
-	OT ?\?( OT ep, unsigned int y ) { __CFA_EXP__(); }
-	OT ?\?( OT ep, unsigned long int y ) { __CFA_EXP__(); }
+	OT ?\?( OT x, unsigned int y ) { __CFA_EXP__(); }
+	OT ?\?( OT x, unsigned long int y ) { __CFA_EXP__(); }
+	OT ?\?( OT x, unsigned long long int y ) { __CFA_EXP__(); }
 } // distribution
 
@@ -166,8 +169,10 @@
 
 static inline {
+	long int ?\=?( int & x, unsigned int y ) { x = x \ y; return x; }
 	long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; }
+	long long int ?\=?( long long int & x, unsigned long long int y ) { x = x \ y; return x; }
+	unsigned long int ?\=?( unsigned int & x, unsigned int y ) { x = x \ y; return x; }
 	unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; }
-	int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; }
-	unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; }
+	unsigned long long int ?\=?( unsigned long long int & x, unsigned long long int y ) { x = x \ y; return x; }
 } // distribution
 
Index: libcfa/src/bits/weakso_locks.cfa
===================================================================
--- libcfa/src/bits/weakso_locks.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/bits/weakso_locks.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -25,5 +25,5 @@
 void unlock( blocking_lock & ) {}
 void on_notify( blocking_lock &, struct $thread * ) {}
-size_t on_wait( blocking_lock & ) {}
+size_t on_wait( blocking_lock & ) { return 0; }
 void on_wakeup( blocking_lock &, size_t ) {}
 size_t wait_count( blocking_lock & ) { return 0; }
Index: libcfa/src/clock.hfa
===================================================================
--- libcfa/src/clock.hfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/clock.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -10,6 +10,6 @@
 // Created On       : Thu Apr 12 14:36:06 2018
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Jan  6 12:49:58 2020
-// Update Count     : 9
+// Last Modified On : Wed Apr 14 17:48:25 2021
+// Update Count     : 20
 //
 
@@ -32,58 +32,84 @@
 
 static inline {
-	void resetClock( Clock & clk, Duration adj ) with( clk ) {
+	void reset( Clock & clk, Duration adj ) with( clk ) {
 		offset = adj + __timezone`s;					// timezone (global) is (UTC - local time) in seconds
-	} // resetClock
+	} // reset
 
-	void ?{}( Clock & clk, Duration adj ) { resetClock( clk, adj ); }
+	void ?{}( Clock & clk ) { reset( clk, (Duration){ 0 } ); }
+	void ?{}( Clock & clk, Duration adj ) { reset( clk, adj ); }
 
-	Duration getResNsec() {
+	// System-wide clock that measures real, i.e., wall-clock) time. This clock is affected by discontinuous jumps in
+	// the system time. For example, manual changes of the clock, and incremental adjustments performed by adjtime(3)
+	// and NTP (daylight saving (Fall back).
+	Duration resolutionNsec() {
 		struct timespec res;
 		clock_getres( CLOCK_REALTIME, &res );
 		return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns;
-	} // getRes
+	} // resolutionNsec
 
-	Duration getRes() {
+	Duration resolution() {
 		struct timespec res;
 		clock_getres( CLOCK_REALTIME_COARSE, &res );
 		return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns;
-	} // getRes
+	} // resolution
 
-	Time getTimeNsec() {								// with nanoseconds
+	Time timeNsec() {									// with nanoseconds
 		timespec curr;
 		clock_gettime( CLOCK_REALTIME, &curr );
 		return (Time){ curr };
-	} // getTimeNsec
+	} // timeNsec
 
-	Time getTime() {									// without nanoseconds
+	Time time() {										// without nanoseconds
 		timespec curr;
 		clock_gettime( CLOCK_REALTIME_COARSE, &curr );
 		curr.tv_nsec = 0;
 		return (Time){ curr };
-	} // getTime
+	} // time
 
-	Time getTime( Clock & clk ) with( clk ) {
-		return getTime() + offset;
-	} // getTime
+	Time time( Clock & clk ) with( clk ) {
+		return time() + offset;
+	} // time
 
 	Time ?()( Clock & clk ) with( clk ) {				// alternative syntax
-		return getTime() + offset;
-	} // getTime
+		return time() + offset;
+	} // ?()
 
-	timeval getTime( Clock & clk ) {
+	timeval time( Clock & clk ) {
 		return (timeval){ clk() };
-	} // getTime
+	} // time
 
-	tm getTime( Clock & clk ) with( clk ) {
+	tm time( Clock & clk ) with( clk ) {
 		tm ret;
-		localtime_r( getTime( clk ).tv_sec, &ret );
+		localtime_r( time( clk ).tv_sec, &ret );
 		return ret;
-	} // getTime
+	} // time
 
-	Time getCPUTime() {
+	// CFA processor CPU-time watch that ticks when the processor (kernel thread) is running. This watch is affected by
+	// discontinuous jumps when the OS is not running the kernal thread. A duration is returned because the value is
+	// relative and cannot be converted to real-time (wall-clock) time.
+	Duration processor() {
 		timespec ts;
 		clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts );
-		return (Time){ ts };
-    } // getCPUTime
+		return (Duration){ ts };
+	} // processor
+
+	// Program CPU-time watch measures CPU time consumed by all processors (kernel threads) in the UNIX process.  This
+	// watch is affected by discontinuous jumps when the OS is not running the kernel threads. A duration is returned
+	// because the value is relative and cannot be converted to real-time (wall-clock) time.
+	Duration program() {
+		timespec ts;
+		clock_gettime( CLOCK_PROCESS_CPUTIME_ID, &ts );
+		return (Duration){ ts };
+	} // program
+
+	// Monotonic stopwatch starting at machine boot and includes system suspension. This watch is unaffected by
+	// discontinuous jumps resulting from manual changes of the clock, and incremental adjustments performed by
+	// adjtime(3) and NTP (Fall back). A duration is returned because the value is relative and cannot be converted to
+	// real-time (wall-clock) time.
+	Duration boot() {
+		timespec ts;
+		clock_gettime( CLOCK_BOOTTIME, &ts );
+		return (Duration){ ts };
+	} // boot
 } // distribution
 
Index: libcfa/src/concurrency/coroutine.cfa
===================================================================
--- libcfa/src/concurrency/coroutine.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/coroutine.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/coroutine.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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/invoke.h
===================================================================
--- libcfa/src/concurrency/invoke.h	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/invoke.h	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -148,5 +148,4 @@
 		struct $thread * prev;
 		volatile unsigned long long ts;
-		int preferred;
 	};
 
Index: libcfa/src/concurrency/io/call.cfa.in
===================================================================
--- libcfa/src/concurrency/io/call.cfa.in	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/io/call.cfa.in	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -201,5 +201,5 @@
 
 		sqe->opcode = IORING_OP_{op};
-		sqe->user_data = (__u64)(uintptr_t)&future;
+		sqe->user_data = (uintptr_t)&future;
 		sqe->flags = sflags;
 		sqe->ioprio = 0;
@@ -215,5 +215,5 @@
 		asm volatile("": : :"memory");
 
-		verify( sqe->user_data == (__u64)(uintptr_t)&future );
+		verify( sqe->user_data == (uintptr_t)&future );
 		cfa_io_submit( ctx, &idx, 1, 0 != (submit_flags & CFA_IO_LAZY) );
 	#endif
@@ -238,5 +238,5 @@
 		'fd'  : 'fd',
 		'off' : 'offset',
-		'addr': '(__u64)iov',
+		'addr': '(uintptr_t)iov',
 		'len' : 'iovcnt',
 	}, define = 'CFA_HAVE_PREADV2'),
@@ -245,5 +245,5 @@
 		'fd'  : 'fd',
 		'off' : 'offset',
-		'addr': '(__u64)iov',
+		'addr': '(uintptr_t)iov',
 		'len' : 'iovcnt'
 	}, define = 'CFA_HAVE_PWRITEV2'),
@@ -257,5 +257,5 @@
 		'addr': 'fd',
 		'len': 'op',
-		'off': '(__u64)event'
+		'off': '(uintptr_t)event'
 	}),
 	# CFA_HAVE_IORING_OP_SYNC_FILE_RANGE
@@ -269,5 +269,5 @@
 	Call('SENDMSG', 'ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)', {
 		'fd': 'sockfd',
-		'addr': '(__u64)(struct msghdr *)msg',
+		'addr': '(uintptr_t)(struct msghdr *)msg',
 		'len': '1',
 		'msg_flags': 'flags'
@@ -276,5 +276,5 @@
 	Call('RECVMSG', 'ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)', {
 		'fd': 'sockfd',
-		'addr': '(__u64)(struct msghdr *)msg',
+		'addr': '(uintptr_t)(struct msghdr *)msg',
 		'len': '1',
 		'msg_flags': 'flags'
@@ -283,5 +283,5 @@
 	Call('SEND', 'ssize_t send(int sockfd, const void *buf, size_t len, int flags)', {
 		'fd': 'sockfd',
-		'addr': '(__u64)buf',
+		'addr': '(uintptr_t)buf',
 		'len': 'len',
 		'msg_flags': 'flags'
@@ -290,5 +290,5 @@
 	Call('RECV', 'ssize_t recv(int sockfd, void *buf, size_t len, int flags)', {
 		'fd': 'sockfd',
-		'addr': '(__u64)buf',
+		'addr': '(uintptr_t)buf',
 		'len': 'len',
 		'msg_flags': 'flags'
@@ -297,6 +297,6 @@
 	Call('ACCEPT', 'int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)', {
 		'fd': 'sockfd',
-		'addr': '(__u64)addr',
-		'addr2': '(__u64)addrlen',
+		'addr': '(uintptr_t)addr',
+		'addr2': '(uintptr_t)addrlen',
 		'accept_flags': 'flags'
 	}),
@@ -304,5 +304,5 @@
 	Call('CONNECT', 'int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)', {
 		'fd': 'sockfd',
-		'addr': '(__u64)addr',
+		'addr': '(uintptr_t)addr',
 		'off': 'addrlen'
 	}),
@@ -310,5 +310,5 @@
 	Call('FALLOCATE', 'int fallocate(int fd, int mode, off_t offset, off_t len)', {
 		'fd': 'fd',
-		'addr': '(__u64)len',
+		'addr': '(uintptr_t)len',
 		'len': 'mode',
 		'off': 'offset'
@@ -323,5 +323,5 @@
 	# CFA_HAVE_IORING_OP_MADVISE
 	Call('MADVISE', 'int madvise(void *addr, size_t length, int advice)', {
-		'addr': '(__u64)addr',
+		'addr': '(uintptr_t)addr',
 		'len': 'length',
 		'fadvise_advice': 'advice'
@@ -330,5 +330,5 @@
 	Call('OPENAT', 'int openat(int dirfd, const char *pathname, int flags, mode_t mode)', {
 		'fd': 'dirfd',
-		'addr': '(__u64)pathname',
+		'addr': '(uintptr_t)pathname',
 		'len': 'mode',
 		'open_flags': 'flags;'
@@ -339,5 +339,5 @@
 		'addr': 'pathname',
 		'len': 'sizeof(*how)',
-		'off': '(__u64)how',
+		'off': '(uintptr_t)how',
 	}, define = 'CFA_HAVE_OPENAT2'),
 	# CFA_HAVE_IORING_OP_CLOSE
@@ -348,5 +348,5 @@
 	Call('STATX', 'int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf)', {
 		'fd': 'dirfd',
-		'off': '(__u64)statxbuf',
+		'off': '(uintptr_t)statxbuf',
 		'addr': 'pathname',
 		'len': 'mask',
@@ -356,5 +356,5 @@
 	Call('READ', 'ssize_t read(int fd, void * buf, size_t count)', {
 		'fd': 'fd',
-		'addr': '(__u64)buf',
+		'addr': '(uintptr_t)buf',
 		'len': 'count'
 	}),
@@ -362,5 +362,5 @@
 	Call('WRITE', 'ssize_t write(int fd, void * buf, size_t count)', {
 		'fd': 'fd',
-		'addr': '(__u64)buf',
+		'addr': '(uintptr_t)buf',
 		'len': 'count'
 	}),
Index: libcfa/src/concurrency/kernel.cfa
===================================================================
--- libcfa/src/concurrency/kernel.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/kernel.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -113,7 +113,7 @@
 static void __wake_one(cluster * cltr);
 
-static void push  (__cluster_idles & idles, processor & proc);
-static void remove(__cluster_idles & idles, processor & proc);
-static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles );
+static void mark_idle (__cluster_proc_list & idles, processor & proc);
+static void mark_awake(__cluster_proc_list & idles, processor & proc);
+static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list idles );
 
 extern void __cfa_io_start( processor * );
@@ -189,5 +189,5 @@
 
 				// Push self to idle stack
-				push(this->cltr->idles, * this);
+				mark_idle(this->cltr->procs, * this);
 
 				// Confirm the ready-queue is empty
@@ -195,5 +195,5 @@
 				if( readyThread ) {
 					// A thread was found, cancel the halt
-					remove(this->cltr->idles, * this);
+					mark_awake(this->cltr->procs, * this);
 
 					#if !defined(__CFA_NO_STATISTICS__)
@@ -225,5 +225,5 @@
 
 				// We were woken up, remove self from idle
-				remove(this->cltr->idles, * this);
+				mark_awake(this->cltr->procs, * this);
 
 				// DON'T just proceed, start looking again
@@ -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
@@ -470,5 +474,5 @@
 
 	ready_schedule_lock();
-		$thread * thrd = pop( this );
+		$thread * thrd = pop_fast( this );
 	ready_schedule_unlock();
 
@@ -613,5 +617,5 @@
 	unsigned idle;
 	unsigned total;
-	[idle, total, p] = query(this->idles);
+	[idle, total, p] = query_idles(this->procs);
 
 	// If no one is sleeping, we are done
@@ -650,27 +654,30 @@
 }
 
-static void push  (__cluster_idles & this, processor & proc) {
+static void mark_idle(__cluster_proc_list & this, processor & proc) {
 	/* paranoid */ verify( ! __preemption_enabled() );
 	lock( this );
 		this.idle++;
 		/* paranoid */ verify( this.idle <= this.total );
-
-		insert_first(this.list, proc);
+		remove(proc);
+		insert_first(this.idles, proc);
 	unlock( this );
 	/* paranoid */ verify( ! __preemption_enabled() );
 }
 
-static void remove(__cluster_idles & this, processor & proc) {
+static void mark_awake(__cluster_proc_list & this, processor & proc) {
 	/* paranoid */ verify( ! __preemption_enabled() );
 	lock( this );
 		this.idle--;
 		/* paranoid */ verify( this.idle >= 0 );
-
 		remove(proc);
+		insert_last(this.actives, proc);
 	unlock( this );
 	/* paranoid */ verify( ! __preemption_enabled() );
 }
 
-static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) {
+static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list this ) {
+	/* paranoid */ verify( ! __preemption_enabled() );
+	/* paranoid */ verify( ready_schedule_islocked() );
+
 	for() {
 		uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST);
@@ -678,5 +685,5 @@
 		unsigned idle    = this.idle;
 		unsigned total   = this.total;
-		processor * proc = &this.list`first;
+		processor * proc = &this.idles`first;
 		// Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it
 		asm volatile("": : :"memory");
@@ -684,4 +691,7 @@
 		return [idle, total, proc];
 	}
+
+	/* paranoid */ verify( ready_schedule_islocked() );
+	/* paranoid */ verify( ! __preemption_enabled() );
 }
 
Index: libcfa/src/concurrency/kernel.hfa
===================================================================
--- libcfa/src/concurrency/kernel.hfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/kernel.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -69,6 +69,12 @@
 	struct cluster * cltr;
 
-	// Id within the cluster
-	unsigned cltr_id;
+	// Ready Queue state per processor
+	struct {
+		unsigned short its;
+		unsigned short itr;
+		unsigned id;
+		unsigned target;
+		unsigned long long int cutoff;
+	} rdq;
 
 	// Set to true to notify the processor should terminate
@@ -140,27 +146,17 @@
 // Cluster Tools
 
-// Intrusives lanes which are used by the relaxed ready queue
+// Intrusives lanes which are used by the ready queue
 struct __attribute__((aligned(128))) __intrusive_lane_t;
 void  ?{}(__intrusive_lane_t & this);
 void ^?{}(__intrusive_lane_t & this);
 
-// Counter used for wether or not the lanes are all empty
-struct __attribute__((aligned(128))) __snzi_node_t;
-struct __snzi_t {
-	unsigned mask;
-	int root;
-	__snzi_node_t * nodes;
-};
-
-void  ?{}( __snzi_t & this, unsigned depth );
-void ^?{}( __snzi_t & this );
+// Aligned timestamps which are used by the relaxed ready queue
+struct __attribute__((aligned(128))) __timestamp_t;
+void  ?{}(__timestamp_t & this);
+void ^?{}(__timestamp_t & this);
 
 //TODO adjust cache size to ARCHITECTURE
 // Structure holding the relaxed ready queue
 struct __ready_queue_t {
-	// Data tracking how many/which lanes are used
-	// Aligned to 128 for cache locality
-	__snzi_t snzi;
-
 	// Data tracking the actual lanes
 	// On a seperate cacheline from the used struct since
@@ -171,4 +167,7 @@
 		__intrusive_lane_t * volatile data;
 
+		// Array of times
+		__timestamp_t * volatile tscs;
+
 		// Number of lanes (empty or not)
 		volatile size_t count;
@@ -180,5 +179,5 @@
 
 // Idle Sleep
-struct __cluster_idles {
+struct __cluster_proc_list {
 	// Spin lock protecting the queue
 	volatile uint64_t lock;
@@ -191,5 +190,8 @@
 
 	// List of idle processors
-	dlist(processor, processor) list;
+	dlist(processor, processor) idles;
+
+	// List of active processors
+	dlist(processor, processor) actives;
 };
 
@@ -207,5 +209,5 @@
 
 	// List of idle processors
-	__cluster_idles idles;
+	__cluster_proc_list procs;
 
 	// List of threads
Index: libcfa/src/concurrency/kernel/startup.cfa
===================================================================
--- libcfa/src/concurrency/kernel/startup.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/kernel/startup.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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
 
@@ -463,4 +469,9 @@
 	this.name = name;
 	this.cltr = &_cltr;
+	this.rdq.its = 0;
+	this.rdq.itr = 0;
+	this.rdq.id  = -1u;
+	this.rdq.target = -1u;
+	this.rdq.cutoff = -1ull;
 	do_terminate = false;
 	preemption_alarm = 0p;
@@ -483,39 +494,30 @@
 	#endif
 
-	lock( this.cltr->idles );
-		int target = this.cltr->idles.total += 1u;
-	unlock( this.cltr->idles );
-
-	id = doregister((__processor_id_t*)&this);
-
+	// Register and Lock the RWlock so no-one pushes/pops while we are changing the queue
+	uint_fast32_t last_size = ready_mutate_register((__processor_id_t*)&this);
+		this.cltr->procs.total += 1u;
+		insert_last(this.cltr->procs.actives, this);
+
+		// Adjust the ready queue size
+		ready_queue_grow( cltr );
+
+	// Unlock the RWlock
+	ready_mutate_unlock( last_size );
+
+	__cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this);
+}
+
+// Not a ctor, it just preps the destruction but should not destroy members
+static void deinit(processor & this) {
 	// Lock the RWlock so no-one pushes/pops while we are changing the queue
 	uint_fast32_t last_size = ready_mutate_lock();
+		this.cltr->procs.total -= 1u;
+		remove(this);
 
 		// Adjust the ready queue size
-		this.cltr_id = ready_queue_grow( cltr, target );
-
-	// Unlock the RWlock
-	ready_mutate_unlock( last_size );
-
-	__cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this);
-}
-
-// Not a ctor, it just preps the destruction but should not destroy members
-static void deinit(processor & this) {
-	lock( this.cltr->idles );
-		int target = this.cltr->idles.total -= 1u;
-	unlock( this.cltr->idles );
-
-	// Lock the RWlock so no-one pushes/pops while we are changing the queue
-	uint_fast32_t last_size = ready_mutate_lock();
-
-		// Adjust the ready queue size
-		ready_queue_shrink( this.cltr, target );
-
-	// Unlock the RWlock
-	ready_mutate_unlock( last_size );
-
-	// Finally we don't need the read_lock any more
-	unregister((__processor_id_t*)&this);
+		ready_queue_shrink( this.cltr );
+
+	// Unlock the RWlock and unregister: we don't need the read_lock any more
+	ready_mutate_unregister((__processor_id_t*)&this, last_size );
 
 	close(this.idle);
@@ -560,9 +562,8 @@
 //-----------------------------------------------------------------------------
 // Cluster
-static void ?{}(__cluster_idles & this) {
+static void ?{}(__cluster_proc_list & this) {
 	this.lock  = 0;
 	this.idle  = 0;
 	this.total = 0;
-	(this.list){};
 }
 
@@ -590,5 +591,5 @@
 
 		// Adjust the ready queue size
-		ready_queue_grow( &this, 0 );
+		ready_queue_grow( &this );
 
 	// Unlock the RWlock
@@ -605,5 +606,5 @@
 
 		// Adjust the ready queue size
-		ready_queue_shrink( &this, 0 );
+		ready_queue_shrink( &this );
 
 	// Unlock the RWlock
@@ -615,4 +616,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/kernel_private.hfa
===================================================================
--- libcfa/src/concurrency/kernel_private.hfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/kernel_private.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -83,46 +83,10 @@
 // Cluster lock API
 //=======================================================================
-// Cells use by the reader writer lock
-// while not generic it only relies on a opaque pointer
-struct __attribute__((aligned(128))) __scheduler_lock_id_t {
-	// Spin lock used as the underlying lock
-	volatile bool lock;
-
-	// Handle pointing to the proc owning this cell
-	// Used for allocating cells and debugging
-	__processor_id_t * volatile handle;
-
-	#ifdef __CFA_WITH_VERIFY__
-		// Debug, check if this is owned for reading
-		bool owned;
-	#endif
-};
-
-static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));
-
 // Lock-Free registering/unregistering of threads
 // Register a processor to a given cluster and get its unique id in return
-unsigned doregister( struct __processor_id_t * proc );
+void register_proc_id( struct __processor_id_t * );
 
 // Unregister a processor from a given cluster using its id, getting back the original pointer
-void     unregister( struct __processor_id_t * proc );
-
-//-----------------------------------------------------------------------
-// Cluster idle lock/unlock
-static inline void lock(__cluster_idles & this) {
-	for() {
-		uint64_t l = this.lock;
-		if(
-			(0 == (l % 2))
-			&& __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
-		) return;
-		Pause();
-	}
-}
-
-static inline void unlock(__cluster_idles & this) {
-	/* paranoid */ verify( 1 == (this.lock % 2) );
-	__atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
-}
+void unregister_proc_id( struct __processor_id_t * proc );
 
 //=======================================================================
@@ -152,4 +116,22 @@
 	__atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE);
 }
+
+// Cells use by the reader writer lock
+// while not generic it only relies on a opaque pointer
+struct __attribute__((aligned(128))) __scheduler_lock_id_t {
+	// Spin lock used as the underlying lock
+	volatile bool lock;
+
+	// Handle pointing to the proc owning this cell
+	// Used for allocating cells and debugging
+	__processor_id_t * volatile handle;
+
+	#ifdef __CFA_WITH_VERIFY__
+		// Debug, check if this is owned for reading
+		bool owned;
+	#endif
+};
+
+static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));
 
 //-----------------------------------------------------------------------
@@ -247,15 +229,62 @@
 void ready_mutate_unlock( uint_fast32_t /* value returned by lock */ );
 
+//-----------------------------------------------------------------------
+// Lock-Free registering/unregistering of threads
+// Register a processor to a given cluster and get its unique id in return
+// For convenience, also acquires the lock
+static inline uint_fast32_t ready_mutate_register( struct __processor_id_t * proc ) {
+	register_proc_id( proc );
+	return ready_mutate_lock();
+}
+
+// Unregister a processor from a given cluster using its id, getting back the original pointer
+// assumes the lock is acquired
+static inline void ready_mutate_unregister( struct __processor_id_t * proc, uint_fast32_t last_s ) {
+	ready_mutate_unlock( last_s );
+	unregister_proc_id( proc );
+}
+
+//-----------------------------------------------------------------------
+// Cluster idle lock/unlock
+static inline void lock(__cluster_proc_list & this) {
+	/* paranoid */ verify( ! __preemption_enabled() );
+
+	// Start by locking the global RWlock so that we know no-one is
+	// adding/removing processors while we mess with the idle lock
+	ready_schedule_lock();
+
+	// Simple counting lock, acquired, acquired by incrementing the counter
+	// to an odd number
+	for() {
+		uint64_t l = this.lock;
+		if(
+			(0 == (l % 2))
+			&& __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+		) return;
+		Pause();
+	}
+
+	/* paranoid */ verify( ! __preemption_enabled() );
+}
+
+static inline void unlock(__cluster_proc_list & this) {
+	/* paranoid */ verify( ! __preemption_enabled() );
+
+	/* paranoid */ verify( 1 == (this.lock % 2) );
+	// Simple couting lock, release by incrementing to an even number
+	__atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
+
+	// Release the global lock, which we acquired when locking
+	ready_schedule_unlock();
+
+	/* paranoid */ verify( ! __preemption_enabled() );
+}
+
 //=======================================================================
 // Ready-Queue API
 //-----------------------------------------------------------------------
-// pop thread from the ready queue of a cluster
-// returns 0p if empty
-__attribute__((hot)) bool query(struct cluster * cltr);
-
-//-----------------------------------------------------------------------
 // push thread onto a ready queue for a cluster
 // returns true if the list was previously empty, false otherwise
-__attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd);
+__attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd);
 
 //-----------------------------------------------------------------------
@@ -263,5 +292,5 @@
 // returns 0p if empty
 // May return 0p spuriously
-__attribute__((hot)) struct $thread * pop(struct cluster * cltr);
+__attribute__((hot)) struct $thread * pop_fast(struct cluster * cltr);
 
 //-----------------------------------------------------------------------
@@ -272,15 +301,10 @@
 
 //-----------------------------------------------------------------------
-// remove thread from the ready queue of a cluster
-// returns bool if it wasn't found
-bool remove_head(struct cluster * cltr, struct $thread * thrd);
-
-//-----------------------------------------------------------------------
 // Increase the width of the ready queue (number of lanes) by 4
-unsigned ready_queue_grow  (struct cluster * cltr, int target);
+void ready_queue_grow  (struct cluster * cltr);
 
 //-----------------------------------------------------------------------
 // Decrease the width of the ready queue (number of lanes) by 4
-void ready_queue_shrink(struct cluster * cltr, int target);
+void ready_queue_shrink(struct cluster * cltr);
 
 
Index: libcfa/src/concurrency/preemption.cfa
===================================================================
--- libcfa/src/concurrency/preemption.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/preemption.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -712,5 +712,5 @@
 static void * alarm_loop( __attribute__((unused)) void * args ) {
 	__processor_id_t id;
-	id.id = doregister(&id);
+	register_proc_id(&id);
 	__cfaabi_tls.this_proc_id = &id;
 
@@ -773,5 +773,5 @@
 EXIT:
 	__cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" );
-	unregister(&id);
+	register_proc_id(&id);
 
 	return 0p;
Index: libcfa/src/concurrency/ready_queue.cfa
===================================================================
--- libcfa/src/concurrency/ready_queue.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/ready_queue.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -17,6 +17,8 @@
 // #define __CFA_DEBUG_PRINT_READY_QUEUE__
 
-// #define USE_SNZI
 // #define USE_MPSC
+
+#define USE_RELAXED_FIFO
+// #define USE_WORK_STEALING
 
 #include "bits/defs.hfa"
@@ -29,5 +31,4 @@
 #include <unistd.h>
 
-#include "snzi.hfa"
 #include "ready_subqueue.hfa"
 
@@ -40,5 +41,20 @@
 #endif
 
-#define BIAS 4
+#if   defined(USE_RELAXED_FIFO)
+	#define BIAS 4
+	#define READYQ_SHARD_FACTOR 4
+	#define SEQUENTIAL_SHARD 1
+#elif defined(USE_WORK_STEALING)
+	#define READYQ_SHARD_FACTOR 2
+	#define SEQUENTIAL_SHARD 2
+#else
+	#error no scheduling strategy selected
+#endif
+
+static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred);
+static inline struct $thread * try_pop(struct cluster * cltr, unsigned w);
+static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j);
+static inline struct $thread * search(struct cluster * cltr);
+
 
 // returns the maximum number of processors the RWLock support
@@ -94,5 +110,5 @@
 //=======================================================================
 // Lock-Free registering/unregistering of threads
-unsigned doregister( struct __processor_id_t * proc ) with(*__scheduler_lock) {
+void register_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
 	__cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p for RW-Lock\n", proc);
 
@@ -108,5 +124,5 @@
 			/*paranoid*/ verify(0 == (__alignof__(data[i]) % cache_line_size));
 			/*paranoid*/ verify((((uintptr_t)&data[i]) % cache_line_size) == 0);
-			return i;
+			proc->id = i;
 		}
 	}
@@ -135,8 +151,8 @@
 	/*paranoid*/ verify(__alignof__(data[n]) == (2 * cache_line_size));
 	/*paranoid*/ verify((((uintptr_t)&data[n]) % cache_line_size) == 0);
-	return n;
-}
-
-void unregister( struct __processor_id_t * proc ) with(*__scheduler_lock) {
+	proc->id = n;
+}
+
+void unregister_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
 	unsigned id = proc->id;
 	/*paranoid*/ verify(id < ready);
@@ -193,31 +209,25 @@
 
 //=======================================================================
-// Cforall Reqdy Queue used for scheduling
+// Cforall Ready Queue used for scheduling
 //=======================================================================
 void ?{}(__ready_queue_t & this) with (this) {
 	lanes.data  = 0p;
+	lanes.tscs  = 0p;
 	lanes.count = 0;
 }
 
 void ^?{}(__ready_queue_t & this) with (this) {
-	verify( 1 == lanes.count );
-	#ifdef USE_SNZI
-		verify( !query( snzi ) );
-	#endif
+	verify( SEQUENTIAL_SHARD == lanes.count );
 	free(lanes.data);
+	free(lanes.tscs);
 }
 
 //-----------------------------------------------------------------------
-__attribute__((hot)) bool query(struct cluster * cltr) {
-	#ifdef USE_SNZI
-		return query(cltr->ready_queue.snzi);
-	#endif
-	return true;
-}
-
-static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) {
-	unsigned i;
-	bool local;
-	#if defined(BIAS)
+#if defined(USE_RELAXED_FIFO)
+	//-----------------------------------------------------------------------
+	// get index from random number with or without bias towards queues
+	static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) {
+		unsigned i;
+		bool local;
 		unsigned rlow  = r % BIAS;
 		unsigned rhigh = r / BIAS;
@@ -225,5 +235,5 @@
 			// (BIAS - 1) out of BIAS chances
 			// Use perferred queues
-			i = preferred + (rhigh % 4);
+			i = preferred + (rhigh % READYQ_SHARD_FACTOR);
 			local = true;
 		}
@@ -234,160 +244,256 @@
 			local = false;
 		}
-	#else
-		i = r;
-		local = false;
-	#endif
-	return [i, local];
-}
-
-//-----------------------------------------------------------------------
-__attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
-	__cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
-
-	const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
-
-	// write timestamp
-	thrd->link.ts = rdtscl();
-
-	bool first = false;
-	__attribute__((unused)) bool local;
-	__attribute__((unused)) int preferred;
-	#if defined(BIAS)
-		preferred =
-			//*
-			external ? -1 : kernelTLS().this_processor->cltr_id;
-			/*/
-			thrd->link.preferred * 4;
-			//*/
-	#endif
-
-	// Try to pick a lane and lock it
-	unsigned i;
-	do {
-		// Pick the index of a lane
-		// unsigned r = __tls_rand();
-		unsigned r = __tls_rand_fwd();
-		[i, local] = idx_from_r(r, preferred);
-
-		i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
-
+		return [i, local];
+	}
+
+	__attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
+		__cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
+
+		const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
+		/* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
+
+		// write timestamp
+		thrd->link.ts = rdtscl();
+
+		bool local;
+		int preferred = external ? -1 : kernelTLS().this_processor->rdq.id;
+
+		// Try to pick a lane and lock it
+		unsigned i;
+		do {
+			// Pick the index of a lane
+			unsigned r = __tls_rand_fwd();
+			[i, local] = idx_from_r(r, preferred);
+
+			i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
+
+			#if !defined(__CFA_NO_STATISTICS__)
+				if(external) {
+					if(local) __atomic_fetch_add(&cltr->stats->ready.pick.ext.local, 1, __ATOMIC_RELAXED);
+					__atomic_fetch_add(&cltr->stats->ready.pick.ext.attempt, 1, __ATOMIC_RELAXED);
+				}
+				else {
+					if(local) __tls_stats()->ready.pick.push.local++;
+					__tls_stats()->ready.pick.push.attempt++;
+				}
+			#endif
+
+		#if defined(USE_MPSC)
+			// mpsc always succeeds
+		} while( false );
+		#else
+			// If we can't lock it retry
+		} while( !__atomic_try_acquire( &lanes.data[i].lock ) );
+		#endif
+
+		// Actually push it
+		push(lanes.data[i], thrd);
+
+		#if !defined(USE_MPSC)
+			// Unlock and return
+			__atomic_unlock( &lanes.data[i].lock );
+		#endif
+
+		// Mark the current index in the tls rng instance as having an item
+		__tls_rand_advance_bck();
+
+		__cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first);
+
+		// Update statistics
 		#if !defined(__CFA_NO_STATISTICS__)
 			if(external) {
-				if(local) __atomic_fetch_add(&cltr->stats->ready.pick.ext.local, 1, __ATOMIC_RELAXED);
-				__atomic_fetch_add(&cltr->stats->ready.pick.ext.attempt, 1, __ATOMIC_RELAXED);
+				if(local) __atomic_fetch_add(&cltr->stats->ready.pick.ext.lsuccess, 1, __ATOMIC_RELAXED);
+				__atomic_fetch_add(&cltr->stats->ready.pick.ext.success, 1, __ATOMIC_RELAXED);
 			}
 			else {
-				if(local) __tls_stats()->ready.pick.push.local++;
-				__tls_stats()->ready.pick.push.attempt++;
+				if(local) __tls_stats()->ready.pick.push.lsuccess++;
+				__tls_stats()->ready.pick.push.success++;
 			}
 		#endif
-
-	#if defined(USE_MPSC)
-		// mpsc always succeeds
-	} while( false );
-	#else
-		// If we can't lock it retry
-	} while( !__atomic_try_acquire( &lanes.data[i].lock ) );
-	#endif
-
-	// Actually push it
-	#ifdef USE_SNZI
-		bool lane_first =
-	#endif
-
-	push(lanes.data[i], thrd);
-
-	#ifdef USE_SNZI
-		// If this lane used to be empty we need to do more
-		if(lane_first) {
-			// Check if the entire queue used to be empty
-			first = !query(snzi);
-
-			// Update the snzi
-			arrive( snzi, i );
-		}
-	#endif
-
-	#if !defined(USE_MPSC)
-		// Unlock and return
-		__atomic_unlock( &lanes.data[i].lock );
-	#endif
-
-	// Mark the current index in the tls rng instance as having an item
-	__tls_rand_advance_bck();
-
-	__cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first);
+	}
+
+	// Pop from the ready queue from a given cluster
+	__attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) {
+		/* paranoid */ verify( lanes.count > 0 );
+		/* paranoid */ verify( kernelTLS().this_processor );
+		/* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count );
+
+		unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
+		int preferred = kernelTLS().this_processor->rdq.id;
+
+
+		// As long as the list is not empty, try finding a lane that isn't empty and pop from it
+		for(25) {
+			// Pick two lists at random
+			unsigned ri = __tls_rand_bck();
+			unsigned rj = __tls_rand_bck();
+
+			unsigned i, j;
+			__attribute__((unused)) bool locali, localj;
+			[i, locali] = idx_from_r(ri, preferred);
+			[j, localj] = idx_from_r(rj, preferred);
+
+			#if !defined(__CFA_NO_STATISTICS__)
+				if(locali && localj) {
+					__tls_stats()->ready.pick.pop.local++;
+				}
+			#endif
+
+			i %= count;
+			j %= count;
+
+			// try popping from the 2 picked lists
+			struct $thread * thrd = try_pop(cltr, i, j);
+			if(thrd) {
+				#if !defined(__CFA_NO_STATISTICS__)
+					if( locali || localj ) __tls_stats()->ready.pick.pop.lsuccess++;
+				#endif
+				return thrd;
+			}
+		}
+
+		// All lanes where empty return 0p
+		return 0p;
+	}
+
+	__attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) {
+		return search(cltr);
+	}
+#endif
+#if defined(USE_WORK_STEALING)
+	__attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
+		__cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
+
+		const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
+		/* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
+
+		// write timestamp
+		thrd->link.ts = rdtscl();
+
+		// Try to pick a lane and lock it
+		unsigned i;
+		do {
+			if(unlikely(external)) {
+				i = __tls_rand() % lanes.count;
+			}
+			else {
+				processor * proc = kernelTLS().this_processor;
+				unsigned r = proc->rdq.its++;
+				i =  proc->rdq.id + (r % READYQ_SHARD_FACTOR);
+			}
+
+
+		#if defined(USE_MPSC)
+			// mpsc always succeeds
+		} while( false );
+		#else
+			// If we can't lock it retry
+		} while( !__atomic_try_acquire( &lanes.data[i].lock ) );
+		#endif
+
+		// Actually push it
+		push(lanes.data[i], thrd);
+
+		#if !defined(USE_MPSC)
+			// Unlock and return
+			__atomic_unlock( &lanes.data[i].lock );
+		#endif
+
+		__cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first);
+	}
+
+	// Pop from the ready queue from a given cluster
+	__attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) {
+		/* paranoid */ verify( lanes.count > 0 );
+		/* paranoid */ verify( kernelTLS().this_processor );
+		/* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count );
+
+		processor * proc = kernelTLS().this_processor;
+
+		if(proc->rdq.target == -1u) {
+			proc->rdq.target = __tls_rand() % lanes.count;
+			unsigned it1  = proc->rdq.itr;
+			unsigned it2  = proc->rdq.itr + 1;
+			unsigned idx1 = proc->rdq.id + (it1 % READYQ_SHARD_FACTOR);
+			unsigned idx2 = proc->rdq.id + (it1 % READYQ_SHARD_FACTOR);
+			unsigned long long tsc1 = ts(lanes.data[idx1]);
+			unsigned long long tsc2 = ts(lanes.data[idx2]);
+			proc->rdq.cutoff = min(tsc1, tsc2);
+		}
+		else if(lanes.tscs[proc->rdq.target].tv < proc->rdq.cutoff) {
+			$thread * t = try_pop(cltr, proc->rdq.target);
+			proc->rdq.target = -1u;
+			if(t) return t;
+		}
+
+		for(READYQ_SHARD_FACTOR) {
+			unsigned i = proc->rdq.id + (--proc->rdq.itr % READYQ_SHARD_FACTOR);
+			if($thread * t = try_pop(cltr, i)) return t;
+		}
+		return 0p;
+	}
+
+	__attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
+		for(25) {
+			unsigned i = __tls_rand() % lanes.count;
+			$thread * t = try_pop(cltr, i);
+			if(t) return t;
+		}
+
+		return search(cltr);
+	}
+#endif
+
+//=======================================================================
+// Various Ready Queue utilities
+//=======================================================================
+// these function work the same or almost the same
+// whether they are using work-stealing or relaxed fifo scheduling
+
+//-----------------------------------------------------------------------
+// try to pop from a lane given by index w
+static inline struct $thread * try_pop(struct cluster * cltr, unsigned w) with (cltr->ready_queue) {
+	// Get relevant elements locally
+	__intrusive_lane_t & lane = lanes.data[w];
+
+	// If list looks empty retry
+	if( is_empty(lane) ) return 0p;
+
+	// If we can't get the lock retry
+	if( !__atomic_try_acquire(&lane.lock) ) return 0p;
+
+	// If list is empty, unlock and retry
+	if( is_empty(lane) ) {
+		__atomic_unlock(&lane.lock);
+		return 0p;
+	}
+
+	// Actually pop the list
+	struct $thread * thrd;
+	thrd = pop(lane);
+
+	/* paranoid */ verify(thrd);
+	/* paranoid */ verify(lane.lock);
+
+	// Unlock and return
+	__atomic_unlock(&lane.lock);
 
 	// Update statistics
 	#if !defined(__CFA_NO_STATISTICS__)
-		if(external) {
-			if(local) __atomic_fetch_add(&cltr->stats->ready.pick.ext.lsuccess, 1, __ATOMIC_RELAXED);
-			__atomic_fetch_add(&cltr->stats->ready.pick.ext.success, 1, __ATOMIC_RELAXED);
-		}
-		else {
-			if(local) __tls_stats()->ready.pick.push.lsuccess++;
-			__tls_stats()->ready.pick.push.success++;
-		}
+		__tls_stats()->ready.pick.pop.success++;
 	#endif
 
-	// return whether or not the list was empty before this push
-	return first;
-}
-
-static struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j);
-static struct $thread * try_pop(struct cluster * cltr, unsigned i);
-
-// Pop from the ready queue from a given cluster
-__attribute__((hot)) $thread * pop(struct cluster * cltr) with (cltr->ready_queue) {
-	/* paranoid */ verify( lanes.count > 0 );
-	unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
-	int preferred;
-	#if defined(BIAS)
-		// Don't bother trying locally too much
-		preferred = kernelTLS().this_processor->cltr_id;
+	#if defined(USE_WORK_STEALING)
+		lanes.tscs[w].tv = thrd->link.ts;
 	#endif
 
-
-	// As long as the list is not empty, try finding a lane that isn't empty and pop from it
-	#ifdef USE_SNZI
-		while( query(snzi) ) {
-	#else
-		for(25) {
-	#endif
-		// Pick two lists at random
-		// unsigned ri = __tls_rand();
-		// unsigned rj = __tls_rand();
-		unsigned ri = __tls_rand_bck();
-		unsigned rj = __tls_rand_bck();
-
-		unsigned i, j;
-		__attribute__((unused)) bool locali, localj;
-		[i, locali] = idx_from_r(ri, preferred);
-		[j, localj] = idx_from_r(rj, preferred);
-
-		#if !defined(__CFA_NO_STATISTICS__)
-			if(locali && localj) {
-				__tls_stats()->ready.pick.pop.local++;
-			}
-		#endif
-
-		i %= count;
-		j %= count;
-
-		// try popping from the 2 picked lists
-		struct $thread * thrd = try_pop(cltr, i, j);
-		if(thrd) {
-			#if defined(BIAS) && !defined(__CFA_NO_STATISTICS__)
-				if( locali || localj ) __tls_stats()->ready.pick.pop.lsuccess++;
-			#endif
-			return thrd;
-		}
-	}
-
-	// All lanes where empty return 0p
-	return 0p;
-}
-
-__attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
+	// return the popped thread
+	return thrd;
+}
+
+//-----------------------------------------------------------------------
+// try to pop from any lanes making sure you don't miss any threads push
+// before the start of the function
+static inline struct $thread * search(struct cluster * cltr) with (cltr->ready_queue) {
 	/* paranoid */ verify( lanes.count > 0 );
 	unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
@@ -405,97 +511,6 @@
 }
 
-
 //-----------------------------------------------------------------------
-// Given 2 indexes, pick the list with the oldest push an try to pop from it
-static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j) with (cltr->ready_queue) {
-	#if !defined(__CFA_NO_STATISTICS__)
-		__tls_stats()->ready.pick.pop.attempt++;
-	#endif
-
-	// Pick the bet list
-	int w = i;
-	if( __builtin_expect(!is_empty(lanes.data[j]), true) ) {
-		w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j;
-	}
-
-	return try_pop(cltr, w);
-}
-
-static inline struct $thread * try_pop(struct cluster * cltr, unsigned w) with (cltr->ready_queue) {
-	// Get relevant elements locally
-	__intrusive_lane_t & lane = lanes.data[w];
-
-	// If list looks empty retry
-	if( is_empty(lane) ) return 0p;
-
-	// If we can't get the lock retry
-	if( !__atomic_try_acquire(&lane.lock) ) return 0p;
-
-
-	// If list is empty, unlock and retry
-	if( is_empty(lane) ) {
-		__atomic_unlock(&lane.lock);
-		return 0p;
-	}
-
-	// Actually pop the list
-	struct $thread * thrd;
-	thrd = pop(lane);
-
-	/* paranoid */ verify(thrd);
-	/* paranoid */ verify(lane.lock);
-
-	#ifdef USE_SNZI
-		// If this was the last element in the lane
-		if(emptied) {
-			depart( snzi, w );
-		}
-	#endif
-
-	// Unlock and return
-	__atomic_unlock(&lane.lock);
-
-	// Update statistics
-	#if !defined(__CFA_NO_STATISTICS__)
-		__tls_stats()->ready.pick.pop.success++;
-	#endif
-
-	// Update the thread bias
-	thrd->link.preferred = w / 4;
-
-	// return the popped thread
-	return thrd;
-}
-//-----------------------------------------------------------------------
-
-bool remove_head(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
-	for(i; lanes.count) {
-		__intrusive_lane_t & lane = lanes.data[i];
-
-		bool removed = false;
-
-		__atomic_acquire(&lane.lock);
-			if(head(lane)->link.next == thrd) {
-				$thread * pthrd;
-				pthrd = pop(lane);
-
-				/* paranoid */ verify( pthrd == thrd );
-
-				removed = true;
-				#ifdef USE_SNZI
-					if(emptied) {
-						depart( snzi, i );
-					}
-				#endif
-			}
-		__atomic_unlock(&lane.lock);
-
-		if( removed ) return true;
-	}
-	return false;
-}
-
-//-----------------------------------------------------------------------
-
+// Check that all the intrusive queues in the data structure are still consistent
 static void check( __ready_queue_t & q ) with (q) {
 	#if defined(__CFA_WITH_VERIFY__) && !defined(USE_MPSC)
@@ -522,4 +537,20 @@
 }
 
+//-----------------------------------------------------------------------
+// Given 2 indexes, pick the list with the oldest push an try to pop from it
+static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j) with (cltr->ready_queue) {
+	#if !defined(__CFA_NO_STATISTICS__)
+		__tls_stats()->ready.pick.pop.attempt++;
+	#endif
+
+	// Pick the bet list
+	int w = i;
+	if( __builtin_expect(!is_empty(lanes.data[j]), true) ) {
+		w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j;
+	}
+
+	return try_pop(cltr, w);
+}
+
 // Call this function of the intrusive list was moved using memcpy
 // fixes the list so that the pointers back to anchors aren't left dangling
@@ -541,8 +572,34 @@
 }
 
+static void assign_list(unsigned & value, dlist(processor, processor) & list, unsigned count) {
+	processor * it = &list`first;
+	for(unsigned i = 0; i < count; i++) {
+		/* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count);
+		it->rdq.id = value;
+		it->rdq.target = -1u;
+		value += READYQ_SHARD_FACTOR;
+		it = &(*it)`next;
+	}
+}
+
+static void reassign_cltr_id(struct cluster * cltr) {
+	unsigned preferred = 0;
+	assign_list(preferred, cltr->procs.actives, cltr->procs.total - cltr->procs.idle);
+	assign_list(preferred, cltr->procs.idles  , cltr->procs.idle );
+}
+
+static void fix_times( struct cluster * cltr ) with( cltr->ready_queue ) {
+	#if defined(USE_WORK_STEALING)
+		lanes.tscs = alloc(lanes.count, lanes.tscs`realloc);
+		for(i; lanes.count) {
+			lanes.tscs[i].tv = ts(lanes.data[i]);
+		}
+	#endif
+}
+
 // Grow the ready queue
-unsigned ready_queue_grow(struct cluster * cltr, int target) {
-	unsigned preferred;
+void ready_queue_grow(struct cluster * cltr) {
 	size_t ncount;
+	int target = cltr->procs.total;
 
 	/* paranoid */ verify( ready_mutate_islocked() );
@@ -554,16 +611,10 @@
 	// grow the ready queue
 	with( cltr->ready_queue ) {
-		#ifdef USE_SNZI
-			^(snzi){};
-		#endif
-
 		// Find new count
 		// Make sure we always have atleast 1 list
 		if(target >= 2) {
-			ncount = target * 4;
-			preferred = ncount - 4;
+			ncount = target * READYQ_SHARD_FACTOR;
 		} else {
-			ncount = 1;
-			preferred = 0;
+			ncount = SEQUENTIAL_SHARD;
 		}
 
@@ -583,15 +634,9 @@
 		// Update original
 		lanes.count = ncount;
-
-		#ifdef USE_SNZI
-			// Re-create the snzi
-			snzi{ log2( lanes.count / 8 ) };
-			for( idx; (size_t)lanes.count ) {
-				if( !is_empty(lanes.data[idx]) ) {
-					arrive(snzi, idx);
-				}
-			}
-		#endif
-	}
+	}
+
+	fix_times(cltr);
+
+	reassign_cltr_id(cltr);
 
 	// Make sure that everything is consistent
@@ -601,9 +646,8 @@
 
 	/* paranoid */ verify( ready_mutate_islocked() );
-	return preferred;
 }
 
 // Shrink the ready queue
-void ready_queue_shrink(struct cluster * cltr, int target) {
+void ready_queue_shrink(struct cluster * cltr) {
 	/* paranoid */ verify( ready_mutate_islocked() );
 	__cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue\n");
@@ -612,9 +656,7 @@
 	/* paranoid */ check( cltr->ready_queue );
 
+	int target = cltr->procs.total;
+
 	with( cltr->ready_queue ) {
-		#ifdef USE_SNZI
-			^(snzi){};
-		#endif
-
 		// Remember old count
 		size_t ocount = lanes.count;
@@ -622,7 +664,7 @@
 		// Find new count
 		// Make sure we always have atleast 1 list
-		lanes.count = target >= 2 ? target * 4: 1;
+		lanes.count = target >= 2 ? target * READYQ_SHARD_FACTOR: SEQUENTIAL_SHARD;
 		/* paranoid */ verify( ocount >= lanes.count );
-		/* paranoid */ verify( lanes.count == target * 4 || target < 2 );
+		/* paranoid */ verify( lanes.count == target * READYQ_SHARD_FACTOR || target < 2 );
 
 		// for printing count the number of displaced threads
@@ -667,15 +709,9 @@
 			fix(lanes.data[idx]);
 		}
-
-		#ifdef USE_SNZI
-			// Re-create the snzi
-			snzi{ log2( lanes.count / 8 ) };
-			for( idx; (size_t)lanes.count ) {
-				if( !is_empty(lanes.data[idx]) ) {
-					arrive(snzi, idx);
-				}
-			}
-		#endif
-	}
+	}
+
+	fix_times(cltr);
+
+	reassign_cltr_id(cltr);
 
 	// Make sure that everything is consistent
Index: libcfa/src/concurrency/ready_subqueue.hfa
===================================================================
--- libcfa/src/concurrency/ready_subqueue.hfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/ready_subqueue.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -246,2 +246,10 @@
 	#endif
 }
+
+// Aligned timestamps which are used by the relaxed ready queue
+struct __attribute__((aligned(128))) __timestamp_t {
+	volatile unsigned long long tv;
+};
+
+void  ?{}(__timestamp_t & this) { this.tv = 0; }
+void ^?{}(__timestamp_t & this) {}
Index: libcfa/src/concurrency/stats.cfa
===================================================================
--- libcfa/src/concurrency/stats.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/stats.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/stats.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/thread.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -39,5 +39,4 @@
 	link.next = 0p;
 	link.prev = 0p;
-	link.preferred = -1;
 	#if defined( __CFA_WITH_VERIFY__ )
 		canary = 0x0D15EA5E0D15EA5Ep;
@@ -62,5 +61,5 @@
 }
 
-FORALL_DATA_INSTANCE(ThreadCancelled, (thread_t &), (thread_t))
+EHM_VIRTUAL_TABLE(SomeThreadCancelled, std_thread_cancelled);
 
 forall(T &)
@@ -73,21 +72,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 +108,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 +164,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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/concurrency/thread.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/exception.c	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/exception.h	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/exception.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/fstream.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/fstream.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -133,5 +133,5 @@
 
 
-DATA_EXCEPTION(Open_Failure)(
+EHM_EXCEPTION(Open_Failure)(
 	union {
 		ofstream * ostream;
Index: libcfa/src/iostream.cfa
===================================================================
--- libcfa/src/iostream.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/iostream.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Mar  2 14:51:30 2021
-// Update Count     : 1151
+// Last Modified On : Tue Apr 13 13:05:24 2021
+// Update Count     : 1324
 //
 
@@ -195,8 +195,8 @@
 			int len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \
 			fmt( os, "%s", buf ); \
-			if ( isfinite( val ) ) {					/* if number, always print decimal point */ \
+			if ( isfinite( val ) ) { /* if number, print decimal point when no fraction or exponent */ \
 				for ( int i = 0;; i += 1 ) { \
 					if ( i == len ) { fmt( os, "." ); break; } \
-					if ( buf[i] == '.' ) break; \
+					if ( buf[i] == '.' || buf[i] == 'e' || buf[i] == 'E' ) break; /* decimal point or scientific ? */ \
 				} /* for */ \
 			} /* if */ \
@@ -525,136 +525,16 @@
 } // distribution
 
-IntegralFMTImpl( signed char, "%    *hh ", "%    *.*hh " )
-IntegralFMTImpl( unsigned char, "%    *hh ", "%    *.*hh " )
-IntegralFMTImpl( signed short int, "%    *h ", "%    *.*h " )
-IntegralFMTImpl( unsigned short int, "%    *h ", "%    *.*h " )
-IntegralFMTImpl( signed int, "%    * ", "%    *.* " )
-IntegralFMTImpl( unsigned int, "%    * ", "%    *.* " )
-IntegralFMTImpl( signed long int, "%    *l ", "%    *.*l " )
-IntegralFMTImpl( unsigned long int, "%    *l ", "%    *.*l " )
-IntegralFMTImpl( signed long long int, "%    *ll ", "%    *.*ll " )
-IntegralFMTImpl( unsigned long long int, "%    *ll ", "%    *.*ll " )
-
-#if 0
-#if defined( __SIZEOF_INT128__ )
-// Default prefix for non-decimal prints is 0b, 0, 0x.
-#define IntegralFMTImpl128( T, SIGNED, CODE, IFMTNP, IFMTP ) \
-forall( ostype & | ostream( ostype ) ) \
-static void base10_128( ostype & os, _Ostream_Manip(T) f ) { \
-	if ( f.val > UINT64_MAX ) { \
-		unsigned long long int lsig = f.val % P10_UINT64; \
-		f.val /= P10_UINT64; /* msig */ \
-		base10_128( os, f ); /* recursion */ \
-		_Ostream_Manip(unsigned long long int) fmt @= { lsig, 0, 19, 'u', { .all : 0 } }; \
-		fmt.flags.nobsdp = true; \
-		/* printf( "fmt1 %c %lld %d\n", fmt.base, fmt.val, fmt.all ); */ \
-		sepOff( os ); \
-		(ostype &)(os | fmt); \
-	} else { \
-		/* printf( "fmt2 %c %lld %d\n", f.base, (unsigned long long int)f.val, f.all ); */ \
-		_Ostream_Manip(SIGNED long long int) fmt @= { (SIGNED long long int)f.val, f.wd, f.pc, f.base, { .all : f.all } }; \
-		(ostype &)(os | fmt); \
-	} /* if */ \
-} /* base10_128 */ \
-forall( ostype & | ostream( ostype ) ) { \
-	ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
-		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
-\
-		if ( f.base == 'b' | f.base == 'B' | f.base == 'o' | f.base == 'x' | f.base == 'X' ) { \
-			unsigned long long int msig = (unsigned long long int)(f.val >> 64); \
-			unsigned long long int lsig = (unsigned long long int)(f.val); \
-			_Ostream_Manip(SIGNED long long int) fmt @= { msig, f.wd, f.pc, f.base, { .all : f.all } }; \
-			_Ostream_Manip(unsigned long long int) fmt2 @= { lsig, 0, 0, f.base, { .all : 0 } }; \
-			if ( msig == 0 ) { \
-				fmt.val = lsig; \
-				(ostype &)(os | fmt); \
-			} else { \
-				fmt2.flags.pad0 = fmt2.flags.nobsdp = true;	\
-				if ( f.base == 'b' | f.base == 'B' ) { \
-					if ( fmt.flags.pc && fmt.pc > 64 ) fmt.pc -= 64; else { fmt.flags.pc = false; fmt.pc = 0; } \
-					if ( fmt.flags.left ) { \
-						fmt.flags.left = false; \
-						fmt.wd = 0; \
-						/* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
-						fmt2.flags.left = true;	\
-						int msigd = high1( msig ); \
-						fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
-						if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0b base specifier */ \
-						if ( (int)fmt2.wd < 64 ) fmt2.wd = 64; /* cast deals with negative value */ \
-						fmt2.flags.pc = true; fmt2.pc = 64; \
-					} else { \
-						if ( fmt.wd > 64 ) fmt.wd -= 64; \
-						else fmt.wd = 1; \
-						/* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
-						fmt2.wd = 64; \
-					} /* if */ \
-					/* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
-					(ostype &)(os | fmt | "" | fmt2); \
-				} else if ( f.base == 'o' ) { \
-					if ( fmt.flags.pc && fmt.pc > 22 ) fmt.pc -= 22; else { fmt.flags.pc = false; fmt.pc = 0; } \
-					fmt.val = (unsigned long long int)fmt.val >> 2; \
-					fmt2.val = ((msig & 0x3) << 1) + ((lsig & 0x8000000000000000U) != 0); \
-					if ( fmt.flags.left ) { \
-						fmt.flags.left = false; \
-						fmt.wd = 0; \
-						/* printf( "L %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
-						(ostype &)(os | fmt | "" | fmt2); \
-						sepOff( os ); \
-						fmt2.flags.left = true;	\
-						int msigd = ceiling_div( high1( fmt.val ), 3 ); \
-						fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
-						if ( ! fmt.flags.nobsdp ) fmt2.wd -= 1; /* compensate for 0 base specifier */ \
-						if ( (int)fmt2.wd < 21 ) fmt2.wd = 21; /* cast deals with negative value */ \
-						fmt2.flags.pc = true; fmt2.pc = 21; \
-					} else { \
-						if ( fmt.wd > 22 ) fmt.wd -= 22; \
-						else fmt.wd = 1; \
-						/* printf( "R %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
-						(ostype &)(os | fmt | "" | fmt2); \
-						sepOff( os ); \
-						fmt2.wd = 21; \
-					} /* if */ \
-					fmt2.val = lsig & 0x7fffffffffffffffU; \
-					/* printf( "\nC %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
-					(ostype &)(os | fmt2); \
-				} else { /* f.base == 'x'  | f.base == 'X' */ \
-					if ( fmt.flags.pc && fmt.pc > 16 ) fmt.pc -= 16; else { fmt.flags.pc = false; fmt.pc = 0; } \
-					if ( fmt.flags.left ) { \
-						fmt.flags.left = false; \
-						fmt.wd = 0; \
-						/* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
-						fmt2.flags.left = true;	\
-						int msigd = high1( msig ); \
-						fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
-						if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0x base specifier */ \
-						if ( (int)fmt2.wd < 16 ) fmt2.wd = 16; /* cast deals with negative value */ \
-						fmt2.flags.pc = true; fmt2.pc = 16; \
-					} else { \
-						if ( fmt.wd > 16 ) fmt.wd -= 16; \
-						else fmt.wd = 1; \
-						/* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
-						fmt2.wd = 16; \
-					} /* if */ \
-					/* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
-					(ostype &)(os | fmt | "" | fmt2); \
-				} /* if */ \
-			} /* if */ \
-		} else { \
-			if ( CODE == 'd' ) { \
-				if ( f.val < 0 )  { fmt( os, "-" ); sepOff( os ); f.val = -f.val; f.flags.sign = false; } \
-			} /* if */ \
-			base10_128( os, f ); \
-		} /* if */ \
-		return os; \
-	} /* ?|? */ \
-	void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
-} // distribution
-
-IntegralFMTImpl128( int128, signed, 'd', "%    *ll ", "%    *.*ll " )
-IntegralFMTImpl128( unsigned int128, unsigned, 'u', "%    *ll ", "%    *.*ll " )
-#endif // __SIZEOF_INT128__
-#endif // 0
-
-#if 1
+IntegralFMTImpl( signed char, "     *hh ", "     *.*hh " )
+IntegralFMTImpl( unsigned char, "     *hh ", "     *.*hh " )
+IntegralFMTImpl( signed short int, "     *h ", "     *.*h " )
+IntegralFMTImpl( unsigned short int, "     *h ", "     *.*h " )
+IntegralFMTImpl( signed int, "     * ", "     *.* " )
+IntegralFMTImpl( unsigned int, "     * ", "     *.* " )
+IntegralFMTImpl( signed long int, "     *l ", "     *.*l " )
+IntegralFMTImpl( unsigned long int, "     *l ", "     *.*l " )
+IntegralFMTImpl( signed long long int, "     *ll ", "     *.*ll " )
+IntegralFMTImpl( unsigned long long int, "     *ll ", "     *.*ll " )
+
+
 #if defined( __SIZEOF_INT128__ )
 // Default prefix for non-decimal prints is 0b, 0, 0x.
@@ -746,25 +626,50 @@
 IntegralFMTImpl128( unsigned int128 )
 #endif // __SIZEOF_INT128__
-#endif // 0
 
 // *********************************** floating point ***********************************
 
-#define PrintWithDP2( os, format, val, ... ) \
+static const char *suffixes[] = {
+	"y", "z", "a", "f", "p", "n", "u", "m", "",
+	"K", "M", "G", "T", "P", "E", "Z", "Y"
+}; 
+#define SUFFIXES_START (-24) /* Smallest power for which there is a suffix defined. */
+#define SUFFIXES_END (SUFFIXES_START + (int)((sizeof(suffixes) / sizeof(char *) - 1) * 3))
+
+#define PrintWithDP2( os, format, ... ) \
 	{ \
-		enum { size = 48 }; \
-		char buf[size]; \
-		int bufbeg = 0, i, len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \
-		if ( isfinite( val ) && (f.base != 'g' || f.pc != 0) ) { /* if number, print decimal point */ \
-			for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E'; i += 1 ); /* decimal point or scientific ? */ \
-			if ( i == len && ! f.flags.nobsdp ) { \
-				if ( ! f.flags.left ) { \
-					buf[i] = '.'; buf[i + 1] = '\0'; \
-					if ( buf[0] == ' ' ) bufbeg = 1;	/* decimal point within width */ \
-				} else { \
-					for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */ \
-					buf[i] = '.'; \
-					if ( i == len ) buf[i + 1] = '\0'; \
+		if ( ! f.flags.eng ) { \
+			len = snprintf( buf, size, format, ##__VA_ARGS__ ); \
+			if ( isfinite( f.val ) && ( f.pc != 0 || ! f.flags.nobsdp ) ) { /* if number, print decimal point when no fraction or exponent */ \
+				for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E'; i += 1 ); /* decimal point or scientific ? */ \
+				if ( i == len ) { \
+					if ( ! f.flags.left ) { \
+						buf[i] = '.'; buf[i + 1] = '\0'; \
+						if ( buf[0] == ' ' ) bufbeg = 1; /* decimal point within width */ \
+					} else { \
+						for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */ \
+						buf[i] = '.'; \
+						if ( i == len ) buf[i + 1] = '\0'; \
+					} /* if */ \
 				} /* if */ \
 			} /* if */ \
+		} else { \
+			int exp10, len2; \
+			eng( f.val, f.pc, exp10 );					/* changes arguments */ \
+			if ( ! f.flags.left && f.wd > 1 ) { \
+				/* Exponent size (number of digits, 'e', optional minus sign) */ \
+				f.wd -= lrint( floor( log10( abs( exp10 ) ) ) ) + 1 + 1 + (exp10 < 0 ? 1 : 0); \
+				if ( f.wd < 1 ) f.wd = 1; \
+			} /* if */ \
+			len = snprintf( buf, size, format, ##__VA_ARGS__ ); \
+			if ( f.flags.left ) { \
+				for ( len -= 1; len > 0 && buf[len] == ' '; len -= 1 ); \
+				len += 1; \
+			} /* if */ \
+			if ( ! f.flags.nobsdp || (exp10 < SUFFIXES_START) || (exp10 > SUFFIXES_END) ) { \
+				len2 = snprintf( &buf[len], size - len, "e%d", exp10 ); \
+			} else { \
+				len2 = snprintf( &buf[len], size - len, "%s", suffixes[(exp10 - SUFFIXES_START) / 3] ); \
+			} /* if */ \
+			if ( f.flags.left && len + len2 < f.wd ) buf[len + len2] = ' '; \
 		} /* if */ \
 		fmt( os, "%s", &buf[bufbeg] ); \
@@ -773,7 +678,19 @@
 #define FloatingPointFMTImpl( T, DFMTNP, DFMTP ) \
 forall( ostype & | ostream( ostype ) ) { \
+	static void eng( T &value, int & pc, int & exp10 ) { \
+		exp10 = lrint( floor( log10( abs( value ) ) ) ); /* round to desired precision */ \
+		if ( exp10 < 0 ) exp10 -= 2; \
+		exp10 = floor( exp10, 3 ); \
+		value *= pow( 10.0, -exp10 ); \
+		if ( pc <= 3 ) pc = 3; \
+	} /* eng */ \
+\
 	ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
+		enum { size = 48 }; \
+		char buf[size]; \
+		int bufbeg = 0, i, len; \
+\
 		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
-		char fmtstr[sizeof(DFMTP)];						/* sizeof includes '\0' */ \
+		char fmtstr[sizeof(DFMTP) + 8];					/* sizeof includes '\0' */ \
 		if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \
 		else memcpy( &fmtstr, DFMTP, sizeof(DFMTP) ); \
@@ -789,9 +706,9 @@
 			fmtstr[sizeof(DFMTNP)-2] = f.base;			/* sizeof includes '\0' */ \
 			/* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star]); */ \
-			PrintWithDP2( os, &fmtstr[star], f.val, f.wd ) \
+			PrintWithDP2( os, &fmtstr[star], f.wd, f.val ) \
 		} else {										/* precision */ \
 			fmtstr[sizeof(DFMTP)-2] = f.base;			/* sizeof includes '\0' */ \
 			/* printf( "%g %d %d %s\n", f.val, f.wd, f.pc, &fmtstr[star] ); */ \
-			PrintWithDP2( os, &fmtstr[star], f.val, f.wd, f.pc ) \
+			PrintWithDP2( os, &fmtstr[star], f.wd, f.pc, f.val ) \
 		} /* if */ \
 		return os; \
@@ -801,6 +718,6 @@
 } // distribution
 
-FloatingPointFMTImpl( double, "%    * ", "%    *.* " )
-FloatingPointFMTImpl( long double, "%    *L ", "%    *.*L " )
+FloatingPointFMTImpl( double, "     * ", "     *.* " )
+FloatingPointFMTImpl( long double, "     *L ", "     *.*L " )
 
 // *********************************** character ***********************************
Index: libcfa/src/iostream.hfa
===================================================================
--- libcfa/src/iostream.hfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/iostream.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Mar  2 14:05:08 2021
-// Update Count     : 369
+// Last Modified On : Tue Apr 13 13:05:11 2021
+// Update Count     : 384
 //
 
@@ -158,9 +158,10 @@
 struct _Ostream_Manip {
 	T val;												// polymorphic base-type
-	unsigned int wd, pc;								// width, precision
+	int wd, pc;											// width, precision
 	char base;											// numeric base / floating-point style
 	union {
 		unsigned char all;
 		struct {
+			unsigned char eng:1;						// engineering notation
 			unsigned char neg:1;						// val is negative
 			unsigned char pc:1;							// precision specified
@@ -222,9 +223,11 @@
 	_Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'a', { .all : 0 } }; } \
 	_Ostream_Manip(T) sci( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'e', { .all : 0 } }; } \
-	_Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'f', { .all : 0 } }; } \
+	_Ostream_Manip(T) eng( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.eng : true } }; } \
+	_Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'g', { .all : 0 } }; } \
 	_Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \
 	_Ostream_Manip(T) ws( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \
-	_Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
-	_Ostream_Manip(T) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
+	_Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = w; return fmt; } \
+	_Ostream_Manip(T) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
+	_Ostream_Manip(T) & ws( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
 	_Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \
 	_Ostream_Manip(T) upcase( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'G', { .all : 0 } }; } \
@@ -235,4 +238,6 @@
 	_Ostream_Manip(T) nodp( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \
 	_Ostream_Manip(T) & nodp( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
+	_Ostream_Manip(T) unit( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \
+	_Ostream_Manip(T) & unit( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
 } /* distribution */ \
 forall( ostype & | ostream( ostype ) ) { \
Index: libcfa/src/math.hfa
===================================================================
--- libcfa/src/math.hfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/math.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -5,11 +5,11 @@
 // file "LICENCE" distributed with Cforall.
 //
-// math --
+// math.hfa --
 //
 // Author           : Peter A. Buhr
 // Created On       : Mon Apr 18 23:37:04 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Aug 24 08:56:20 2020
-// Update Count     : 126
+// Last Modified On : Thu Apr 15 11:47:56 2021
+// Update Count     : 132
 //
 
@@ -100,4 +100,9 @@
 	long double _Complex log( long double _Complex x ) { return clogl( x ); }
 
+	// O(1) polymorphic integer log2, using clz, which returns the number of leading 0-bits, starting at the most
+	// significant bit (single instruction on x86)
+	int log2( unsigned int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clz( n ); }
+	long int log2( unsigned long int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clzl( n ); }
+	long long int log2( unsigned long long int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clzll( n ); }
 	float log2( float x ) { return log2f( x ); }
 	// extern "C" { double log2( double ); }
Index: libcfa/src/time.hfa
===================================================================
--- libcfa/src/time.hfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/time.hfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -10,6 +10,6 @@
 // Created On       : Wed Mar 14 23:18:57 2018
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jun 17 16:13:00 2020
-// Update Count     : 663
+// Last Modified On : Wed Apr 14 09:30:30 2021
+// Update Count     : 664
 //
 
@@ -29,4 +29,16 @@
 static inline {
 	Duration ?=?( Duration & dur, __attribute__((unused)) zero_t ) { return dur{ 0 }; }
+
+	void ?{}( Duration & dur, timeval t ) with( dur ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }
+	Duration ?=?( Duration & dur, timeval t ) with( dur ) {
+		tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * (TIMEGRAN / 1_000_000LL);
+		return dur;
+	} // ?=?
+
+	void ?{}( Duration & dur, timespec t ) with( dur ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }
+	Duration ?=?( Duration & dur, timespec t ) with( dur ) {
+		tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
+		return dur;
+	} // ?=?
 
 	Duration +?( Duration rhs ) with( rhs ) { return (Duration)@{ +tn }; }
Index: libcfa/src/virtual.c
===================================================================
--- libcfa/src/virtual.c	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ libcfa/src/virtual.c	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ src/AST/Expr.cpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ src/AST/Expr.hpp	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ src/Concurrency/Keywords.cc	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ src/Parser/parser.yy	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Apr  1 14:43:24 2021
-// Update Count     : 4978
+// Last Modified On : Wed Apr 14 18:13:44 2021
+// Update Count     : 4983
 //
 
@@ -281,5 +281,6 @@
 %token ATTRIBUTE EXTENSION								// GCC
 %token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN
-%token CHOOSE DISABLE ENABLE FALLTHRU FALLTHROUGH TRY THROW THROWRESUME AT WITH WHEN WAITFOR // CFA
+%token CHOOSE FALLTHRU FALLTHROUGH WITH WHEN WAITFOR	// CFA
+%token DISABLE ENABLE TRY THROW THROWRESUME AT			// CFA
 %token ASM												// C99, extension ISO/IEC 9899:1999 Section J.5.10(1)
 %token ALIGNAS ALIGNOF GENERIC STATICASSERT				// C11
Index: src/SynTree/Constant.cc
===================================================================
--- src/SynTree/Constant.cc	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ src/SynTree/Constant.cc	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ src/SynTree/Constant.h	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ src/Virtual/ExpandCasts.cc	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ src/Virtual/Tables.cc	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ src/Virtual/Tables.h	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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/.expect/KRfunctions.nast.arm64.txt
===================================================================
--- tests/.expect/KRfunctions.nast.arm64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/KRfunctions.nast.arm64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -104,6 +104,6 @@
     signed int _X1bi_2;
     {
-        signed int *(*_tmp_cp_ret4)(signed int __param_0, signed int __param_1);
-        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
+        signed int *(*_tmp_cp_ret6)(signed int __param_0, signed int __param_1);
+        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));
     }
 
Index: tests/.expect/KRfunctions.nast.x64.txt
===================================================================
--- tests/.expect/KRfunctions.nast.x64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/KRfunctions.nast.x64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -104,6 +104,6 @@
     signed int _X1bi_2;
     {
-        signed int *(*_tmp_cp_ret4)(signed int __param_0, signed int __param_1);
-        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
+        signed int *(*_tmp_cp_ret6)(signed int __param_0, signed int __param_1);
+        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));
     }
 
Index: tests/.expect/KRfunctions.nast.x86.txt
===================================================================
--- tests/.expect/KRfunctions.nast.x86.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/KRfunctions.nast.x86.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -104,6 +104,6 @@
     signed int _X1bi_2;
     {
-        signed int *(*_tmp_cp_ret4)(signed int __param_0, signed int __param_1);
-        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
+        signed int *(*_tmp_cp_ret6)(signed int __param_0, signed int __param_1);
+        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));
     }
 
Index: tests/.expect/KRfunctions.oast.x64.txt
===================================================================
--- tests/.expect/KRfunctions.oast.x64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/KRfunctions.oast.x64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -104,6 +104,6 @@
     signed int _X1bi_2;
     {
-        signed int *(*_tmp_cp_ret4)(signed int _X1xi_1, signed int _X1yi_1);
-        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
+        signed int *(*_tmp_cp_ret6)(signed int _X1xi_1, signed int _X1yi_1);
+        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));
     }
 
Index: tests/.expect/declarationSpecifier.arm64.txt
===================================================================
--- tests/.expect/declarationSpecifier.arm64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/declarationSpecifier.arm64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -1147,6 +1147,6 @@
 
     {
-        signed int _tmp_cp_ret4;
-        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
+        signed int _tmp_cp_ret6;
+        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     }
 
Index: tests/.expect/declarationSpecifier.x64.txt
===================================================================
--- tests/.expect/declarationSpecifier.x64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/declarationSpecifier.x64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -1147,6 +1147,6 @@
 
     {
-        signed int _tmp_cp_ret4;
-        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
+        signed int _tmp_cp_ret6;
+        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     }
 
Index: tests/.expect/declarationSpecifier.x86.txt
===================================================================
--- tests/.expect/declarationSpecifier.x86.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/declarationSpecifier.x86.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -1147,6 +1147,6 @@
 
     {
-        signed int _tmp_cp_ret4;
-        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
+        signed int _tmp_cp_ret6;
+        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     }
 
Index: tests/.expect/extension.arm64.txt
===================================================================
--- tests/.expect/extension.arm64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/extension.arm64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -457,6 +457,6 @@
 
     {
-        signed int _tmp_cp_ret4;
-        ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
+        signed int _tmp_cp_ret6;
+        ((void)(((void)(_tmp_cp_ret6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6));
     }
 
Index: tests/.expect/extension.x64.txt
===================================================================
--- tests/.expect/extension.x64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/extension.x64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -457,6 +457,6 @@
 
     {
-        signed int _tmp_cp_ret4;
-        ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
+        signed int _tmp_cp_ret6;
+        ((void)(((void)(_tmp_cp_ret6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6));
     }
 
Index: tests/.expect/extension.x86.txt
===================================================================
--- tests/.expect/extension.x86.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/extension.x86.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -457,6 +457,6 @@
 
     {
-        signed int _tmp_cp_ret4;
-        ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
+        signed int _tmp_cp_ret6;
+        ((void)(((void)(_tmp_cp_ret6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6));
     }
 
Index: tests/.expect/gccExtensions.arm64.txt
===================================================================
--- tests/.expect/gccExtensions.arm64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/gccExtensions.arm64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -339,6 +339,6 @@
 
     {
-        signed int _tmp_cp_ret4;
-        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
+        signed int _tmp_cp_ret6;
+        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     }
 
Index: tests/.expect/gccExtensions.x64.txt
===================================================================
--- tests/.expect/gccExtensions.x64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/gccExtensions.x64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -339,6 +339,6 @@
 
     {
-        signed int _tmp_cp_ret4;
-        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
+        signed int _tmp_cp_ret6;
+        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     }
 
Index: tests/.expect/gccExtensions.x86.txt
===================================================================
--- tests/.expect/gccExtensions.x86.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/gccExtensions.x86.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -317,6 +317,6 @@
 
     {
-        signed int _tmp_cp_ret4;
-        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
+        signed int _tmp_cp_ret6;
+        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     }
 
Index: tests/.expect/math.nast.arm64.txt
===================================================================
--- tests/.expect/math.nast.arm64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/math.nast.arm64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -17,4 +17,8 @@
 4 16
 log:0. 0. 0. 0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972654708616060729088+0.785398163397448309615660845819876i
+log2:10 17 23
+log2:10 17 23
+log2:10 17 23
+log2:10. 17. 23.
 log2:3. 3. 3.
 log10:2. 2. 2.
Index: tests/.expect/math.nast.x64.txt
===================================================================
--- tests/.expect/math.nast.x64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/math.nast.x64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -17,4 +17,8 @@
 4 16
 log:0. 0. 0. 0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972655+0.78539816339744831i
+log2:10 17 23
+log2:10 17 23
+log2:10 17 23
+log2:10. 17. 23.
 log2:3. 3. 3.
 log10:2. 2. 2.
Index: tests/.expect/math.nast.x86.txt
===================================================================
--- tests/.expect/math.nast.x86.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/.expect/math.nast.x86.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -17,4 +17,7 @@
 4 16
 log:0. 0. 0. 0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972655+0.78539816339744831i
+log2:10 17 23
+log2:10 17 23
+log2:10 17 23
 log2:3. 3. 3.
 log10:2. 2. 2.
Index: tests/concurrent/futures/multi.cfa
===================================================================
--- tests/concurrent/futures/multi.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/concurrent/futures/multi.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -5,10 +5,12 @@
 
 thread Server {
-	int cnt, iteration;
+	int pending, done, iteration;
 	multi_future(int) * request;
 };
 
 void ?{}( Server & this ) {
-	this.cnt = 0;
+	((thread&)this){"Server Thread"};
+	this.pending = 0;
+	this.done = 0;
 	this.iteration = 0;
 	this.request = 0p;
@@ -16,6 +18,6 @@
 
 void ^?{}( Server & mutex this ) {
-	assert(this.cnt == 0);
-    this.request = 0p;
+	assert(this.pending == 0);
+	this.request = 0p;
 }
 
@@ -24,30 +26,31 @@
 }
 
-void process( Server & mutex this ) {
-	fulfil( *this.request, this.iteration );
-	this.iteration++;
+void call( Server & mutex this ) {
+	this.pending++;
 }
 
-void call( Server & mutex this ) {
-	this.cnt++;
+void finish( Server & mutex this ) {
+	this.done++;
 }
 
-void finish( Server & mutex this ) { }
-
 void main( Server & this ) {
+	MAIN_LOOP:
 	for() {
 		waitfor( ^?{} : this ) {
 			break;
 		}
-		or when( this.cnt < NFUTURES ) waitfor( call: this ) {
-			if (this.cnt == NFUTURES) {
-				process(this);
+		or waitfor( call: this ) {
+			if (this.pending != NFUTURES) { continue MAIN_LOOP; }
+
+			this.pending = 0;
+			fulfil( *this.request, this.iteration );
+			this.iteration++;
+
+			for(NFUTURES) {
+				waitfor( finish: this );
 			}
-		}
-		or waitfor( finish: this ) {
-			if (this.cnt == NFUTURES) {
-				reset( *this.request );
-				this.cnt = 0;
-			}
+
+			reset( *this.request );
+			this.done = 0;
 		}
 	}
@@ -57,4 +60,8 @@
 Server * the_server;
 thread Worker {};
+void ?{}(Worker & this) {
+	((thread&)this){"Worker Thread"};
+}
+
 multi_future(int) * shared_future;
 
Index: tests/concurrent/spinaphore.cfa
===================================================================
--- tests/concurrent/spinaphore.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/concurrent/spinaphore.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -49,10 +49,10 @@
 void main(Unblocker & this) {
 	this.sum = 0;
-	unsigned me = (unsigned)&this;
+	unsigned me = (unsigned)(uintptr_t)&this;
 	for(num_unblocks) {
 		$thread * t = V(sem, false);
 		Blocker * b = from_thread(t);
 		b->sum += me;
-		this.sum += (unsigned)b;
+		this.sum += (unsigned)(uintptr_t)b;
 		unpark(t);
 		yield(random(10));
@@ -73,10 +73,10 @@
 		for(i;num_blockers) {
 			for(num_blocks)
-				usum += (unsigned)&blockers[i];
+				usum += (unsigned)(uintptr_t)&blockers[i];
 		}
 
 		for(i;num_unblockers) {
 			for(num_unblocks)
-				bsum += (unsigned)&unblockers[i];
+				bsum += (unsigned)(uintptr_t)&unblockers[i];
 		}
 
Index: tests/errors/.expect/completeType.nast.arm64.txt
===================================================================
--- tests/errors/.expect/completeType.nast.arm64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/errors/.expect/completeType.nast.arm64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -12,5 +12,5 @@
       Application of
         Variable Expression: *?: forall
-          DT: data type
+          instance of type DT (not function type)
           function
         ... with parameters
@@ -21,5 +21,40 @@
         ... with resolved type:
           pointer to forall
-            [unbound]:data type
+            instance of type [unbound] (not function type)
+            function
+          ... with parameters
+            pointer to instance of type [unbound] (not function type)
+          ... returning
+            reference to instance of type [unbound] (not function type)
+
+        ... to arguments
+        Variable Expression: x: pointer to instance of struct A without body
+        ... with resolved type:
+          pointer to instance of struct A without body
+
+      ... with resolved type:
+        reference to instance of struct A without body
+    ... to: nothing
+    ... with resolved type:
+      void
+  (types:
+    void
+  )
+  Environment:([unbound]DT) -> instance of struct A without body (no widening)
+
+
+Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
+      Application of
+        Variable Expression: *?: forall
+          instance of type DT (not function type)
+          function
+        ... with parameters
+          pointer to instance of type DT (not function type)
+        ... returning
+          reference to instance of type DT (not function type)
+
+        ... with resolved type:
+          pointer to forall
+            instance of type [unbound] (not function type)
             function
           ... with parameters
@@ -41,40 +76,5 @@
     void
   )
-  Environment:([unbound]) -> instance of struct B with body (no widening)
-
-
-Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
-      Application of
-        Variable Expression: *?: forall
-          DT: data type
-          function
-        ... with parameters
-          pointer to instance of type DT (not function type)
-        ... returning
-          reference to instance of type DT (not function type)
-
-        ... with resolved type:
-          pointer to forall
-            [unbound]:data type
-            function
-          ... with parameters
-            pointer to instance of type [unbound] (not function type)
-          ... returning
-            reference to instance of type [unbound] (not function type)
-
-        ... to arguments
-        Variable Expression: x: pointer to instance of struct A without body
-        ... with resolved type:
-          pointer to instance of struct A without body
-
-      ... with resolved type:
-        reference to instance of struct A without body
-    ... to: nothing
-    ... with resolved type:
-      void
-  (types:
-    void
-  )
-  Environment:([unbound]) -> instance of struct A without body (no widening)
+  Environment:([unbound]DT) -> instance of struct B with body (no widening)
 
 
@@ -113,7 +113,15 @@
 Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of
             Variable Expression: baz: forall
-              T: sized data type
-              ... with assertions
-                ?=?: pointer to function
+              instance of type T (not function type)
+              with assertions
+              Variable Expression: ?=?: pointer to function
+              ... with parameters
+                reference to instance of type T (not function type)
+                instance of type T (not function type)
+              ... returning
+                instance of type T (not function type)
+
+              ... with resolved type:
+                pointer to function
                 ... with parameters
                   reference to instance of type T (not function type)
@@ -122,20 +130,38 @@
                   instance of type T (not function type)
 
-                ?{}: pointer to function
-                ... with parameters
-                  reference to instance of type T (not function type)
-                ... returning nothing
-
-                ?{}: pointer to function
-                ... with parameters
-                  reference to instance of type T (not function type)
-                  instance of type T (not function type)
-                ... returning nothing
-
-                ^?{}: pointer to function
-                ... with parameters
-                  reference to instance of type T (not function type)
-                ... returning nothing
-
+              Variable Expression: ?{}: pointer to function
+              ... with parameters
+                reference to instance of type T (not function type)
+              ... returning nothing
+
+              ... with resolved type:
+                pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
+
+              Variable Expression: ?{}: pointer to function
+              ... with parameters
+                reference to instance of type T (not function type)
+                instance of type T (not function type)
+              ... returning nothing
+
+              ... with resolved type:
+                pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                  instance of type T (not function type)
+                ... returning nothing
+
+              Variable Expression: ^?{}: pointer to function
+              ... with parameters
+                reference to instance of type T (not function type)
+              ... returning nothing
+
+              ... with resolved type:
+                pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
 
               function
@@ -146,7 +172,15 @@
             ... with resolved type:
               pointer to forall
-                [unbound]:sized data type
-                ... with assertions
-                  ?=?: pointer to function
+                instance of type [unbound] (not function type)
+                with assertions
+                Variable Expression: ?=?: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                  instance of type T (not function type)
+                ... returning
+                  instance of type T (not function type)
+
+                ... with resolved type:
+                  pointer to function
                   ... with parameters
                     reference to instance of type [unbound] (not function type)
@@ -155,10 +189,23 @@
                     instance of type [unbound] (not function type)
 
-                  ?{}: pointer to function
+                Variable Expression: ?{}: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
+
+                ... with resolved type:
+                  pointer to function
                   ... with parameters
                     reference to instance of type [unbound] (not function type)
                   ... returning nothing
 
-                  ?{}: pointer to function
+                Variable Expression: ?{}: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                  instance of type T (not function type)
+                ... returning nothing
+
+                ... with resolved type:
+                  pointer to function
                   ... with parameters
                     reference to instance of type [unbound] (not function type)
@@ -166,9 +213,14 @@
                   ... returning nothing
 
-                  ^?{}: pointer to function
+                Variable Expression: ^?{}: pointer to function
+                ... with parameters
+                  reference to instance of type T (not function type)
+                ... returning nothing
+
+                ... with resolved type:
+                  pointer to function
                   ... with parameters
                     reference to instance of type [unbound] (not function type)
                   ... returning nothing
-
 
                 function
@@ -188,12 +240,20 @@
           void
         )
-        Environment:([unbound]) -> instance of type T (not function type) (no widening)
+        Environment:([unbound]T) -> instance of type T (not function type) (no widening)
 
       Could not satisfy assertion:
-?=?: pointer to function
+Variable Expression: ?=?: pointer to function
         ... with parameters
-          reference to instance of type [unbound] (not function type)
-          instance of type [unbound] (not function type)
+          reference to instance of type T (not function type)
+          instance of type T (not function type)
         ... returning
-          instance of type [unbound] (not function type)
-
+          instance of type T (not function type)
+
+        ... with resolved type:
+          pointer to function
+          ... with parameters
+            reference to instance of type [unbound] (not function type)
+            instance of type [unbound] (not function type)
+          ... returning
+            instance of type [unbound] (not function type)
+
Index: tests/exceptions/.expect/resume-threads.txt
===================================================================
--- tests/exceptions/.expect/resume-threads.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/.expect/resume-threads.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/.expect/resume.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/.expect/terminate-threads.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/.expect/terminate.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/cancel/coroutine.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/cancel/thread.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/conditional.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/data-except.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/defaults.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/finally.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/interact.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/polymorphic.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/resume.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/terminate.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/trash.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/type-check.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/virtual-cast.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/exceptions/virtual-poly.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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/io/.expect/manipulatorsOutput1.arm64.txt
===================================================================
--- tests/io/.expect/manipulatorsOutput1.arm64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/io/.expect/manipulatorsOutput1.arm64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -29,11 +29,11 @@
 float
 0         3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
-0. 3.000000 3.000000 3.537 3.537000        4        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+0.       3.        3 3.537    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
 double
-0  3.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
-0. 3.000000 3.537 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+0         3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+0.       3.        3 3.537    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
 long double
-0  3.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
-0. 3.000000 3.53699999999999992184029906638898 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+0         3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+0.       3.        3 3.53699999999999992184029906638898    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
 
 char
Index: tests/io/.expect/manipulatorsOutput1.x64.txt
===================================================================
--- tests/io/.expect/manipulatorsOutput1.x64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/io/.expect/manipulatorsOutput1.x64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -29,11 +29,11 @@
 float
 0         3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
-0. 3.000000 3.000000 3.537 3.537000        4        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+0.       3.        3 3.537    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
 double
-0  3.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
-0. 3.000000 3.537 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+0         3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+0.       3.        3 3.537    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
 long double
-0  3.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
-0. 3.000000 3.53699999999999992 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
+0         3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
+0.       3.        3 3.53699999999999992    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
 
 char
Index: tests/io/.expect/manipulatorsOutput1.x86.txt
===================================================================
--- tests/io/.expect/manipulatorsOutput1.x86.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/io/.expect/manipulatorsOutput1.x86.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -29,11 +29,11 @@
 float
 0         3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
-0. 3.000000 3.000000 3.537 3.537000        4        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+0.       3.        3 3.537    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
 double
-0  3.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
-0. 3.000000 3.537 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+0         3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
+0.       3.        3 3.537    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
 long double
-0  3.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
-0. 3.000000 3.53699999999999992 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
+0         3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
+0.       3.        3 3.53699999999999992    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
 
 char
Index: tests/io/.expect/manipulatorsOutput2.arm64.txt
===================================================================
--- tests/io/.expect/manipulatorsOutput2.arm64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/io/.expect/manipulatorsOutput2.arm64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -9,13 +9,14 @@
 -0x1.b8p+4 -0x1.b8p+4 -0x1.b8p+4
 0.000000e+00 2.750000e+01 -2.750000e+01
+0e0 27.5e0 -27.5e0
 0B11011 0X1B 2.75E-09 0X1.B8P+4
 11011 33 1b
 0. 0 27. 27 27.5
-+27 -27 +27 -27 +27.5 -27.5
++27 -27 +27. -27. +27.5 -27.5
   34  34 34
-  4.000000  4.000000 4.000000
+        4.        4.       4.
   ab  ab ab
 34567 34567 34567
-3456.000000 3456.000000 3456.000000
+3456. 3456. 3456.
 abcde abcde abcde
  034     0034 0000000034
@@ -24,5 +25,5 @@
 27.500     27.5      28. 27.50000000
 27.000 27.500     27.5      28. 27.50000000
-27   27.000000  27.500000  027  27.500    
+27   27.        27.5       027  27.500    
 234.567 234.57  234.6   235.
 234567. 2.3457e+05 2.346e+05 2.35e+05
Index: tests/io/.expect/manipulatorsOutput2.x64.txt
===================================================================
--- tests/io/.expect/manipulatorsOutput2.x64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/io/.expect/manipulatorsOutput2.x64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -9,13 +9,14 @@
 -0x1.b8p+4 -0x1.b8p+4 -0xd.cp+1
 0.000000e+00 2.750000e+01 -2.750000e+01
+0e0 27.5e0 -27.5e0
 0B11011 0X1B 2.75E-09 0X1.B8P+4
 11011 33 1b
 0. 0 27. 27 27.5
-+27 -27 +27 -27 +27.5 -27.5
++27 -27 +27. -27. +27.5 -27.5
   34  34 34
-  4.000000  4.000000 4.000000
+        4.        4.       4.
   ab  ab ab
 34567 34567 34567
-3456.000000 3456.000000 3456.000000
+3456. 3456. 3456.
 abcde abcde abcde
  034     0034 0000000034
@@ -24,5 +25,5 @@
 27.500     27.5      28. 27.50000000
 27.000 27.500     27.5      28. 27.50000000
-27   27.000000  27.500000  027  27.500    
+27   27.        27.5       027  27.500    
 234.567 234.57  234.6   235.
 234567. 2.3457e+05 2.346e+05 2.35e+05
Index: tests/io/.expect/manipulatorsOutput2.x86.txt
===================================================================
--- tests/io/.expect/manipulatorsOutput2.x86.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/io/.expect/manipulatorsOutput2.x86.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -9,13 +9,14 @@
 -0x1.b8p+4 -0x1.b8p+4 -0xd.cp+1
 0.000000e+00 2.750000e+01 -2.750000e+01
+0e2147483646 27.5e0 -27.5e0
 0B11011 0X1B 2.75E-09 0X1.B8P+4
 11011 33 1b
 0. 0 27. 27 27.5
-+27 -27 +27 -27 +27.5 -27.5
++27 -27 +27. -27. +27.5 -27.5
   34  34 34
-  4.000000  4.000000 4.000000
+        4.        4.       4.
   ab  ab ab
 34567 34567 34567
-3456.000000 3456.000000 3456.000000
+3456. 3456. 3456.
 abcde abcde abcde
  034     0034 0000000034
@@ -24,5 +25,5 @@
 27.500     27.5      28. 27.50000000
 27.000 27.500     27.5      28. 27.50000000
-27   27.000000  27.500000  027  27.500    
+27   27.        27.5       027  27.500    
 234.567 234.57  234.6   235.
 234567. 2.3457e+05 2.346e+05 2.35e+05
Index: tests/io/.expect/manipulatorsOutput4.x64.txt
===================================================================
--- tests/io/.expect/manipulatorsOutput4.x64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
+++ tests/io/.expect/manipulatorsOutput4.x64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -0,0 +1,226 @@
+1e-27 1e-27 +1e-27        1e-27       +1e-27  1.00000e-27 +1.00000e-27 00000001e-27 +0000001e-27 01.00000e-27 +1.00000e-27 1e-27        +1e-27       1.00000e-27  +1.00000e-27 1e-27        +1e-27       1.00000e-27  +1.00000e-27
+1e-26 10e-27 +10e-27       10e-27      +10e-27 10.00000e-27 +10.00000e-27 00000010e-27 +0000010e-27 10.00000e-27 +10.00000e-27 10e-27       +10e-27      10.00000e-27 +10.00000e-27 10e-27       +10e-27      10.00000e-27 +10.00000e-27
+1e-25 100e-27 +100e-27      100e-27     +100e-27 100.00000e-27 +100.00000e-27 00000100e-27 +0000100e-27 100.00000e-27 +100.00000e-27 100e-27      +100e-27     100.00000e-27 +100.00000e-27 100e-27      +100e-27     100.00000e-27 +100.00000e-27
+1e-24 1e-24 +1e-24        1e-24       +1e-24  1.00000e-24 +1.00000e-24 00000001e-24 +0000001e-24 01.00000e-24 +1.00000e-24 1e-24        +1e-24       1.00000e-24  +1.00000e-24 1e-24        +1e-24       1.00000e-24  +1.00000e-24
+1e-23 10e-24 +10e-24       10e-24      +10e-24 10.00000e-24 +10.00000e-24 00000010e-24 +0000010e-24 10.00000e-24 +10.00000e-24 10e-24       +10e-24      10.00000e-24 +10.00000e-24 10e-24       +10e-24      10.00000e-24 +10.00000e-24
+1e-22 100e-24 +100e-24      100e-24     +100e-24 100.00000e-24 +100.00000e-24 00000100e-24 +0000100e-24 100.00000e-24 +100.00000e-24 100e-24      +100e-24     100.00000e-24 +100.00000e-24 100e-24      +100e-24     100.00000e-24 +100.00000e-24
+1e-21 1e-21 +1e-21        1e-21       +1e-21  1.00000e-21 +1.00000e-21 00000001e-21 +0000001e-21 01.00000e-21 +1.00000e-21 1e-21        +1e-21       1.00000e-21  +1.00000e-21 1e-21        +1e-21       1.00000e-21  +1.00000e-21
+1e-20 10e-21 +10e-21       10e-21      +10e-21 10.00000e-21 +10.00000e-21 00000010e-21 +0000010e-21 10.00000e-21 +10.00000e-21 10e-21       +10e-21      10.00000e-21 +10.00000e-21 10e-21       +10e-21      10.00000e-21 +10.00000e-21
+1e-19 100e-21 +100e-21      100e-21     +100e-21 100.00000e-21 +100.00000e-21 00000100e-21 +0000100e-21 100.00000e-21 +100.00000e-21 100e-21      +100e-21     100.00000e-21 +100.00000e-21 100e-21      +100e-21     100.00000e-21 +100.00000e-21
+1e-18 1e-18 +1e-18        1e-18       +1e-18  1.00000e-18 +1.00000e-18 00000001e-18 +0000001e-18 01.00000e-18 +1.00000e-18 1e-18        +1e-18       1.00000e-18  +1.00000e-18 1e-18        +1e-18       1.00000e-18  +1.00000e-18
+1e-17 10e-18 +10e-18       10e-18      +10e-18 10.00000e-18 +10.00000e-18 00000010e-18 +0000010e-18 10.00000e-18 +10.00000e-18 10e-18       +10e-18      10.00000e-18 +10.00000e-18 10e-18       +10e-18      10.00000e-18 +10.00000e-18
+1e-16 100e-18 +100e-18      100e-18     +100e-18 100.00000e-18 +100.00000e-18 00000100e-18 +0000100e-18 100.00000e-18 +100.00000e-18 100e-18      +100e-18     100.00000e-18 +100.00000e-18 100e-18      +100e-18     100.00000e-18 +100.00000e-18
+1e-15 1e-15 +1e-15        1e-15       +1e-15  1.00000e-15 +1.00000e-15 00000001e-15 +0000001e-15 01.00000e-15 +1.00000e-15 1e-15        +1e-15       1.00000e-15  +1.00000e-15 1e-15        +1e-15       1.00000e-15  +1.00000e-15
+1e-14 10e-15 +10e-15       10e-15      +10e-15 10.00000e-15 +10.00000e-15 00000010e-15 +0000010e-15 10.00000e-15 +10.00000e-15 10e-15       +10e-15      10.00000e-15 +10.00000e-15 10e-15       +10e-15      10.00000e-15 +10.00000e-15
+1e-13 100e-15 +100e-15      100e-15     +100e-15 100.00000e-15 +100.00000e-15 00000100e-15 +0000100e-15 100.00000e-15 +100.00000e-15 100e-15      +100e-15     100.00000e-15 +100.00000e-15 100e-15      +100e-15     100.00000e-15 +100.00000e-15
+1e-12 1e-12 +1e-12        1e-12       +1e-12  1.00000e-12 +1.00000e-12 00000001e-12 +0000001e-12 01.00000e-12 +1.00000e-12 1e-12        +1e-12       1.00000e-12  +1.00000e-12 1e-12        +1e-12       1.00000e-12  +1.00000e-12
+1e-11 10e-12 +10e-12       10e-12      +10e-12 10.00000e-12 +10.00000e-12 00000010e-12 +0000010e-12 10.00000e-12 +10.00000e-12 10e-12       +10e-12      10.00000e-12 +10.00000e-12 10e-12       +10e-12      10.00000e-12 +10.00000e-12
+1e-10 100e-12 +100e-12      100e-12     +100e-12 100.00000e-12 +100.00000e-12 00000100e-12 +0000100e-12 100.00000e-12 +100.00000e-12 100e-12      +100e-12     100.00000e-12 +100.00000e-12 100e-12      +100e-12     100.00000e-12 +100.00000e-12
+1e-09 1e-9 +1e-9         1e-9        +1e-9   1.00000e-9  +1.00000e-9 000000001e-9 +00000001e-9 001.00000e-9 +01.00000e-9 1e-9         +1e-9        1.00000e-9   +1.00000e-9  1e-9         +1e-9        1.00000e-9   +1.00000e-9 
+1e-08 10e-9 +10e-9        10e-9       +10e-9  10.00000e-9 +10.00000e-9 000000010e-9 +00000010e-9 010.00000e-9 +10.00000e-9 10e-9        +10e-9       10.00000e-9  +10.00000e-9 10e-9        +10e-9       10.00000e-9  +10.00000e-9
+1e-07 100e-9 +100e-9       100e-9      +100e-9 100.00000e-9 +100.00000e-9 000000100e-9 +00000100e-9 100.00000e-9 +100.00000e-9 100e-9       +100e-9      100.00000e-9 +100.00000e-9 100e-9       +100e-9      100.00000e-9 +100.00000e-9
+1e-06 1e-6 +1e-6         1e-6        +1e-6   1.00000e-6  +1.00000e-6 000000001e-6 +00000001e-6 001.00000e-6 +01.00000e-6 1e-6         +1e-6        1.00000e-6   +1.00000e-6  1e-6         +1e-6        1.00000e-6   +1.00000e-6 
+1e-05 10e-6 +10e-6        10e-6       +10e-6  10.00000e-6 +10.00000e-6 000000010e-6 +00000010e-6 010.00000e-6 +10.00000e-6 10e-6        +10e-6       10.00000e-6  +10.00000e-6 10e-6        +10e-6       10.00000e-6  +10.00000e-6
+0.0001 100e-6 +100e-6       100e-6      +100e-6 100.00000e-6 +100.00000e-6 000000100e-6 +00000100e-6 100.00000e-6 +100.00000e-6 100e-6       +100e-6      100.00000e-6 +100.00000e-6 100e-6       +100e-6      100.00000e-6 +100.00000e-6
+0.001 1e-3 +1e-3         1e-3        +1e-3   1.00000e-3  +1.00000e-3 000000001e-3 +00000001e-3 001.00000e-3 +01.00000e-3 1e-3         +1e-3        1.00000e-3   +1.00000e-3  1e-3         +1e-3        1.00000e-3   +1.00000e-3 
+0.01 10e-3 +10e-3        10e-3       +10e-3  10.00000e-3 +10.00000e-3 000000010e-3 +00000010e-3 010.00000e-3 +10.00000e-3 10e-3        +10e-3       10.00000e-3  +10.00000e-3 10e-3        +10e-3       10.00000e-3  +10.00000e-3
+0.1 100e-3 +100e-3       100e-3      +100e-3 100.00000e-3 +100.00000e-3 000000100e-3 +00000100e-3 100.00000e-3 +100.00000e-3 100e-3       +100e-3      100.00000e-3 +100.00000e-3 100e-3       +100e-3      100.00000e-3 +100.00000e-3
+1. 1e0 +1e0          1e0         +1e0    1.00000e0   +1.00000e0 0000000001e0 +000000001e0 0001.00000e0 +001.00000e0 1e0          +1e0         1.00000e0    +1.00000e0   1e0          +1e0         1.00000e0    +1.00000e0  
+10. 10e0 +10e0         10e0        +10e0   10.00000e0  +10.00000e0 0000000010e0 +000000010e0 0010.00000e0 +010.00000e0 10e0         +10e0        10.00000e0   +10.00000e0  10e0         +10e0        10.00000e0   +10.00000e0 
+100. 100e0 +100e0        100e0       +100e0  100.00000e0 +100.00000e0 0000000100e0 +000000100e0 0100.00000e0 +100.00000e0 100e0        +100e0       100.00000e0  +100.00000e0 100e0        +100e0       100.00000e0  +100.00000e0
+1000. 1e3 +1e3          1e3         +1e3    1.00000e3   +1.00000e3 0000000001e3 +000000001e3 0001.00000e3 +001.00000e3 1e3          +1e3         1.00000e3    +1.00000e3   1e3          +1e3         1.00000e3    +1.00000e3  
+10000. 10e3 +10e3         10e3        +10e3   10.00000e3  +10.00000e3 0000000010e3 +000000010e3 0010.00000e3 +010.00000e3 10e3         +10e3        10.00000e3   +10.00000e3  10e3         +10e3        10.00000e3   +10.00000e3 
+100000. 100e3 +100e3        100e3       +100e3  100.00000e3 +100.00000e3 0000000100e3 +000000100e3 0100.00000e3 +100.00000e3 100e3        +100e3       100.00000e3  +100.00000e3 100e3        +100e3       100.00000e3  +100.00000e3
+1000000. 1e6 +1e6          1e6         +1e6    1.00000e6   +1.00000e6 0000000001e6 +000000001e6 0001.00000e6 +001.00000e6 1e6          +1e6         1.00000e6    +1.00000e6   1e6          +1e6         1.00000e6    +1.00000e6  
+10000000. 10e6 +10e6         10e6        +10e6   10.00000e6  +10.00000e6 0000000010e6 +000000010e6 0010.00000e6 +010.00000e6 10e6         +10e6        10.00000e6   +10.00000e6  10e6         +10e6        10.00000e6   +10.00000e6 
+100000000. 100e6 +100e6        100e6       +100e6  100.00000e6 +100.00000e6 0000000100e6 +000000100e6 0100.00000e6 +100.00000e6 100e6        +100e6       100.00000e6  +100.00000e6 100e6        +100e6       100.00000e6  +100.00000e6
+1000000000. 1e9 +1e9          1e9         +1e9    1.00000e9   +1.00000e9 0000000001e9 +000000001e9 0001.00000e9 +001.00000e9 1e9          +1e9         1.00000e9    +1.00000e9   1e9          +1e9         1.00000e9    +1.00000e9  
+10000000000. 10e9 +10e9         10e9        +10e9   10.00000e9  +10.00000e9 0000000010e9 +000000010e9 0010.00000e9 +010.00000e9 10e9         +10e9        10.00000e9   +10.00000e9  10e9         +10e9        10.00000e9   +10.00000e9 
+100000000000. 100e9 +100e9        100e9       +100e9  100.00000e9 +100.00000e9 0000000100e9 +000000100e9 0100.00000e9 +100.00000e9 100e9        +100e9       100.00000e9  +100.00000e9 100e9        +100e9       100.00000e9  +100.00000e9
+1000000000000. 1e12 +1e12         1e12        +1e12   1.00000e12  +1.00000e12 000000001e12 +00000001e12 001.00000e12 +01.00000e12 1e12         +1e12        1.00000e12   +1.00000e12  1e12         +1e12        1.00000e12   +1.00000e12 
+10000000000000. 10e12 +10e12        10e12       +10e12  10.00000e12 +10.00000e12 000000010e12 +00000010e12 010.00000e12 +10.00000e12 10e12        +10e12       10.00000e12  +10.00000e12 10e12        +10e12       10.00000e12  +10.00000e12
+100000000000000. 100e12 +100e12       100e12      +100e12 100.00000e12 +100.00000e12 000000100e12 +00000100e12 100.00000e12 +100.00000e12 100e12       +100e12      100.00000e12 +100.00000e12 100e12       +100e12      100.00000e12 +100.00000e12
+1e+15 1e15 +1e15         1e15        +1e15   1.00000e15  +1.00000e15 000000001e15 +00000001e15 001.00000e15 +01.00000e15 1e15         +1e15        1.00000e15   +1.00000e15  1e15         +1e15        1.00000e15   +1.00000e15 
+1e+16 10e15 +10e15        10e15       +10e15  10.00000e15 +10.00000e15 000000010e15 +00000010e15 010.00000e15 +10.00000e15 10e15        +10e15       10.00000e15  +10.00000e15 10e15        +10e15       10.00000e15  +10.00000e15
+1e+17 100e15 +100e15       100e15      +100e15 100.00000e15 +100.00000e15 000000100e15 +00000100e15 100.00000e15 +100.00000e15 100e15       +100e15      100.00000e15 +100.00000e15 100e15       +100e15      100.00000e15 +100.00000e15
+1e+18 1e18 +1e18         1e18        +1e18   1.00000e18  +1.00000e18 000000001e18 +00000001e18 001.00000e18 +01.00000e18 1e18         +1e18        1.00000e18   +1.00000e18  1e18         +1e18        1.00000e18   +1.00000e18 
+1e+19 10e18 +10e18        10e18       +10e18  10.00000e18 +10.00000e18 000000010e18 +00000010e18 010.00000e18 +10.00000e18 10e18        +10e18       10.00000e18  +10.00000e18 10e18        +10e18       10.00000e18  +10.00000e18
+1e+20 100e18 +100e18       100e18      +100e18 100.00000e18 +100.00000e18 000000100e18 +00000100e18 100.00000e18 +100.00000e18 100e18       +100e18      100.00000e18 +100.00000e18 100e18       +100e18      100.00000e18 +100.00000e18
+1e+21 1e21 +1e21         1e21        +1e21   1.00000e21  +1.00000e21 000000001e21 +00000001e21 001.00000e21 +01.00000e21 1e21         +1e21        1.00000e21   +1.00000e21  1e21         +1e21        1.00000e21   +1.00000e21 
+1e+22 10e21 +10e21        10e21       +10e21  10.00000e21 +10.00000e21 000000010e21 +00000010e21 010.00000e21 +10.00000e21 10e21        +10e21       10.00000e21  +10.00000e21 10e21        +10e21       10.00000e21  +10.00000e21
+1e+23 100e21 +100e21       100e21      +100e21 100.00000e21 +100.00000e21 000000100e21 +00000100e21 100.00000e21 +100.00000e21 100e21       +100e21      100.00000e21 +100.00000e21 100e21       +100e21      100.00000e21 +100.00000e21
+1e+24 1e24 +1e24         1e24        +1e24   1.00000e24  +1.00000e24 000000001e24 +00000001e24 001.00000e24 +01.00000e24 1e24         +1e24        1.00000e24   +1.00000e24  1e24         +1e24        1.00000e24   +1.00000e24 
+1e+25 10e24 +10e24        10e24       +10e24  10.00000e24 +10.00000e24 000000010e24 +00000010e24 010.00000e24 +10.00000e24 10e24        +10e24       10.00000e24  +10.00000e24 10e24        +10e24       10.00000e24  +10.00000e24
+1e+26 100e24 +100e24       100e24      +100e24 100.00000e24 +100.00000e24 000000100e24 +00000100e24 100.00000e24 +100.00000e24 100e24       +100e24      100.00000e24 +100.00000e24 100e24       +100e24      100.00000e24 +100.00000e24
+1e+27 1e27 +1e27         1e27        +1e27   1.00000e27  +1.00000e27 000000001e27 +00000001e27 001.00000e27 +01.00000e27 1e27         +1e27        1.00000e27   +1.00000e27  1e27         +1e27        1.00000e27   +1.00000e27 
+1e+28 10e27 +10e27        10e27       +10e27  10.00000e27 +10.00000e27 000000010e27 +00000010e27 010.00000e27 +10.00000e27 10e27        +10e27       10.00000e27  +10.00000e27 10e27        +10e27       10.00000e27  +10.00000e27
+1e+29 100e27 +100e27       100e27      +100e27 100.00000e27 +100.00000e27 000000100e27 +00000100e27 100.00000e27 +100.00000e27 100e27       +100e27      100.00000e27 +100.00000e27 100e27       +100e27      100.00000e27 +100.00000e27
+
+1e-27 1e-27 +1e-27        1e-27       +1e-27  1.00000e-27 +1.00000e-27 00000001e-27 +0000001e-27 01.00000e-27 +1.00000e-27 1e-27        +1e-27       1.00000e-27  +1.00000e-27 1e-27        +1e-27       1.00000e-27  +1.00000e-27
+4.2e-26 42e-27 +42e-27       42e-27      +42e-27 42.00000e-27 +42.00000e-27 00000042e-27 +0000042e-27 42.00000e-27 +42.00000e-27 42e-27       +42e-27      42.00000e-27 +42.00000e-27 42e-27       +42e-27      42.00000e-27 +42.00000e-27
+1.764e-24 1.764e-24 +1.764e-24    1.764e-24   +1.764e-24  1.76400e-24 +1.76400e-24 0001.764e-24 +001.764e-24 01.76400e-24 +1.76400e-24 1.764e-24    +1.764e-24   1.76400e-24  +1.76400e-24 1.764e-24    +1.764e-24   1.76400e-24  +1.76400e-24
+7.4088e-23 74.088e-24 +74.088e-24   74.088e-24  +74.088e-24 74.08800e-24 +74.08800e-24 0074.088e-24 +074.088e-24 74.08800e-24 +74.08800e-24 74.088e-24   +74.088e-24  74.08800e-24 +74.08800e-24 74.088e-24   +74.088e-24  74.08800e-24 +74.08800e-24
+3.111696e-21 3.1117e-21 +3.1117e-21   3.1117e-21  +3.1117e-21  3.11170e-21 +3.11170e-21 003.1117e-21 +03.1117e-21 03.11170e-21 +3.11170e-21 3.1117e-21   +3.1117e-21  3.11170e-21  +3.11170e-21 3.1117e-21   +3.1117e-21  3.11170e-21  +3.11170e-21
+1.30691232e-19 130.691e-21 +130.691e-21   130.69e-21  +130.69e-21 130.69123e-21 +130.69123e-21 00130.69e-21 +0130.69e-21 130.69123e-21 +130.69123e-21 130.69e-21   +130.69e-21  130.69123e-21 +130.69123e-21 130.69e-21   +130.69e-21  130.69123e-21 +130.69123e-21
+5.489031744e-18 5.48903e-18 +5.48903e-18    5.489e-18   +5.489e-18  5.48903e-18 +5.48903e-18 0005.489e-18 +005.489e-18 05.48903e-18 +5.48903e-18 5.489e-18    +5.489e-18   5.48903e-18  +5.48903e-18 5.489e-18    +5.489e-18   5.48903e-18  +5.48903e-18
+2.30539333248e-16 230.539e-18 +230.539e-18   230.54e-18  +230.54e-18 230.53933e-18 +230.53933e-18 00230.54e-18 +0230.54e-18 230.53933e-18 +230.53933e-18 230.54e-18   +230.54e-18  230.53933e-18 +230.53933e-18 230.54e-18   +230.54e-18  230.53933e-18 +230.53933e-18
+9.682651996416e-15 9.68265e-15 +9.68265e-15   9.6827e-15  +9.6827e-15  9.68265e-15 +9.68265e-15 009.6827e-15 +09.6827e-15 09.68265e-15 +9.68265e-15 9.6827e-15   +9.6827e-15  9.68265e-15  +9.68265e-15 9.6827e-15   +9.6827e-15  9.68265e-15  +9.68265e-15
+4.06671383849472e-13 406.671e-15 +406.671e-15   406.67e-15  +406.67e-15 406.67138e-15 +406.67138e-15 00406.67e-15 +0406.67e-15 406.67138e-15 +406.67138e-15 406.67e-15   +406.67e-15  406.67138e-15 +406.67138e-15 406.67e-15   +406.67e-15  406.67138e-15 +406.67138e-15
+1.70801981216778e-11 17.0802e-12 +17.0802e-12    17.08e-12   +17.08e-12 17.08020e-12 +17.08020e-12 00017.08e-12 +0017.08e-12 17.08020e-12 +17.08020e-12 17.08e-12    +17.08e-12   17.08020e-12 +17.08020e-12 17.08e-12    +17.08e-12   17.08020e-12 +17.08020e-12
+7.17368321110469e-10 717.368e-12 +717.368e-12   717.37e-12  +717.37e-12 717.36832e-12 +717.36832e-12 00717.37e-12 +0717.37e-12 717.36832e-12 +717.36832e-12 717.37e-12   +717.37e-12  717.36832e-12 +717.36832e-12 717.37e-12   +717.37e-12  717.36832e-12 +717.36832e-12
+3.01294694866397e-08 30.1295e-9 +30.1295e-9    30.129e-9   +30.129e-9  30.12947e-9 +30.12947e-9 00030.129e-9 +0030.129e-9 030.12947e-9 +30.12947e-9 30.129e-9    +30.129e-9   30.12947e-9  +30.12947e-9 30.129e-9    +30.129e-9   30.12947e-9  +30.12947e-9
+1.26543771843887e-06 1.26544e-6 +1.26544e-6    1.2654e-6   +1.2654e-6   1.26544e-6  +1.26544e-6 0001.2654e-6 +001.2654e-6 001.26544e-6 +01.26544e-6 1.2654e-6    +1.2654e-6   1.26544e-6   +1.26544e-6  1.2654e-6    +1.2654e-6   1.26544e-6   +1.26544e-6 
+5.31483841744324e-05 53.1484e-6 +53.1484e-6    53.148e-6   +53.148e-6  53.14838e-6 +53.14838e-6 00053.148e-6 +0053.148e-6 053.14838e-6 +53.14838e-6 53.148e-6    +53.148e-6   53.14838e-6  +53.14838e-6 53.148e-6    +53.148e-6   53.14838e-6  +53.14838e-6
+0.00223223213532616 2.23223e-3 +2.23223e-3    2.2322e-3   +2.2322e-3   2.23223e-3  +2.23223e-3 0002.2322e-3 +002.2322e-3 002.23223e-3 +02.23223e-3 2.2322e-3    +2.2322e-3   2.23223e-3   +2.23223e-3  2.2322e-3    +2.2322e-3   2.23223e-3   +2.23223e-3 
+0.0937537496836987 93.7537e-3 +93.7537e-3    93.754e-3   +93.754e-3  93.75375e-3 +93.75375e-3 00093.754e-3 +0093.754e-3 093.75375e-3 +93.75375e-3 93.754e-3    +93.754e-3   93.75375e-3  +93.75375e-3 93.754e-3    +93.754e-3   93.75375e-3  +93.75375e-3
+3.93765748671535 3.93766e0 +3.93766e0     3.9377e0    +3.9377e0    3.93766e0   +3.93766e0 00003.9377e0 +0003.9377e0 0003.93766e0 +003.93766e0 3.9377e0     +3.9377e0    3.93766e0    +3.93766e0   3.9377e0     +3.9377e0    3.93766e0    +3.93766e0  
+165.381614442045 165.382e0 +165.382e0     165.38e0    +165.38e0  165.38161e0 +165.38161e0 0000165.38e0 +000165.38e0 0165.38161e0 +165.38161e0 165.38e0     +165.38e0    165.38161e0  +165.38161e0 165.38e0     +165.38e0    165.38161e0  +165.38161e0
+6946.02780656587 6.94603e3 +6.94603e3      6.946e3     +6.946e3    6.94603e3   +6.94603e3 000006.946e3 +00006.946e3 0006.94603e3 +006.94603e3 6.946e3      +6.946e3     6.94603e3    +6.94603e3   6.946e3      +6.946e3     6.94603e3    +6.94603e3  
+291733.167875767 291.733e3 +291.733e3     291.73e3    +291.73e3  291.73317e3 +291.73317e3 0000291.73e3 +000291.73e3 0291.73317e3 +291.73317e3 291.73e3     +291.73e3    291.73317e3  +291.73317e3 291.73e3     +291.73e3    291.73317e3  +291.73317e3
+12252793.0507822 12.2528e6 +12.2528e6     12.253e6    +12.253e6   12.25279e6  +12.25279e6 000012.253e6 +00012.253e6 0012.25279e6 +012.25279e6 12.253e6     +12.253e6    12.25279e6   +12.25279e6  12.253e6     +12.253e6    12.25279e6   +12.25279e6 
+514617308.132852 514.617e6 +514.617e6     514.62e6    +514.62e6  514.61731e6 +514.61731e6 0000514.62e6 +000514.62e6 0514.61731e6 +514.61731e6 514.62e6     +514.62e6    514.61731e6  +514.61731e6 514.62e6     +514.62e6    514.61731e6  +514.61731e6
+21613926941.5798 21.6139e9 +21.6139e9     21.614e9    +21.614e9   21.61393e9  +21.61393e9 000021.614e9 +00021.614e9 0021.61393e9 +021.61393e9 21.614e9     +21.614e9    21.61393e9   +21.61393e9  21.614e9     +21.614e9    21.61393e9   +21.61393e9 
+907784931546.352 907.785e9 +907.785e9     907.78e9    +907.78e9  907.78493e9 +907.78493e9 0000907.78e9 +000907.78e9 0907.78493e9 +907.78493e9 907.78e9     +907.78e9    907.78493e9  +907.78493e9 907.78e9     +907.78e9    907.78493e9  +907.78493e9
+38126967124946.8 38.127e12 +38.127e12    38.127e12   +38.127e12  38.12697e12 +38.12697e12 00038.127e12 +0038.127e12 038.12697e12 +38.12697e12 38.127e12    +38.127e12   38.12697e12  +38.12697e12 38.127e12    +38.127e12   38.12697e12  +38.12697e12
+1.60133261924776e+15 1.60133e15 +1.60133e15    1.6013e15   +1.6013e15   1.60133e15  +1.60133e15 0001.6013e15 +001.6013e15 001.60133e15 +01.60133e15 1.6013e15    +1.6013e15   1.60133e15   +1.60133e15  1.6013e15    +1.6013e15   1.60133e15   +1.60133e15 
+6.72559700084061e+16 67.256e15 +67.256e15    67.256e15   +67.256e15  67.25597e15 +67.25597e15 00067.256e15 +0067.256e15 067.25597e15 +67.25597e15 67.256e15    +67.256e15   67.25597e15  +67.25597e15 67.256e15    +67.256e15   67.25597e15  +67.25597e15
+2.82475074035306e+18 2.82475e18 +2.82475e18    2.8248e18   +2.8248e18   2.82475e18  +2.82475e18 0002.8248e18 +002.8248e18 002.82475e18 +02.82475e18 2.8248e18    +2.8248e18   2.82475e18   +2.82475e18  2.8248e18    +2.8248e18   2.82475e18   +2.82475e18 
+1.18639531094828e+20 118.64e18 +118.64e18    118.64e18   +118.64e18 118.63953e18 +118.63953e18 000118.64e18 +00118.64e18 118.63953e18 +118.63953e18 118.64e18    +118.64e18   118.63953e18 +118.63953e18 118.64e18    +118.64e18   118.63953e18 +118.63953e18
+4.98286030598279e+21 4.98286e21 +4.98286e21    4.9829e21   +4.9829e21   4.98286e21  +4.98286e21 0004.9829e21 +004.9829e21 004.98286e21 +04.98286e21 4.9829e21    +4.9829e21   4.98286e21   +4.98286e21  4.9829e21    +4.9829e21   4.98286e21   +4.98286e21 
+2.09280132851277e+23 209.28e21 +209.28e21    209.28e21   +209.28e21 209.28013e21 +209.28013e21 000209.28e21 +00209.28e21 209.28013e21 +209.28013e21 209.28e21    +209.28e21   209.28013e21 +209.28013e21 209.28e21    +209.28e21   209.28013e21 +209.28013e21
+8.78976557975365e+24 8.78977e24 +8.78977e24    8.7898e24   +8.7898e24   8.78977e24  +8.78977e24 0008.7898e24 +008.7898e24 008.78977e24 +08.78977e24 8.7898e24    +8.7898e24   8.78977e24   +8.78977e24  8.7898e24    +8.7898e24   8.78977e24   +8.78977e24 
+3.69170154349653e+26 369.17e24 +369.17e24    369.17e24   +369.17e24 369.17015e24 +369.17015e24 000369.17e24 +00369.17e24 369.17015e24 +369.17015e24 369.17e24    +369.17e24   369.17015e24 +369.17015e24 369.17e24    +369.17e24   369.17015e24 +369.17015e24
+1.55051464826854e+28 15.5051e27 +15.5051e27    15.505e27   +15.505e27  15.50515e27 +15.50515e27 00015.505e27 +0015.505e27 015.50515e27 +15.50515e27 15.505e27    +15.505e27   15.50515e27  +15.50515e27 15.505e27    +15.505e27   15.50515e27  +15.50515e27
+6.51216152272788e+29 651.216e27 +651.216e27    651.22e27   +651.22e27 651.21615e27 +651.21615e27 000651.22e27 +00651.22e27 651.21615e27 +651.21615e27 651.22e27    +651.22e27   651.21615e27 +651.21615e27 651.22e27    +651.22e27   651.21615e27 +651.21615e27
+
+1e-27 1e-27 +1e-27        1e-27       +1e-27  1.00000e-27 +1.00000e-27 00000001e-27 +0000001e-27 01.00000e-27 +1.00000e-27 1e-27        +1e-27       1.00000e-27  +1.00000e-27 1e-27        +1e-27       1.00000e-27  +1.00000e-27
+1e-26 10e-27 +10e-27       10e-27      +10e-27 10.00000e-27 +10.00000e-27 00000010e-27 +0000010e-27 10.00000e-27 +10.00000e-27 10e-27       +10e-27      10.00000e-27 +10.00000e-27 10e-27       +10e-27      10.00000e-27 +10.00000e-27
+1e-25 100e-27 +100e-27      100e-27     +100e-27 100.00000e-27 +100.00000e-27 00000100e-27 +0000100e-27 100.00000e-27 +100.00000e-27 100e-27      +100e-27     100.00000e-27 +100.00000e-27 100e-27      +100e-27     100.00000e-27 +100.00000e-27
+1e-24 1y +1y        1y       +1y  1.00000y +1.00000y 00000001y +0000001y 01.00000y +1.00000y 1y           +1y          1.00000y     +1.00000y    1y           +1y          1.00000y     +1.00000y   
+1e-23 10y +10y       10y      +10y 10.00000y +10.00000y 00000010y +0000010y 10.00000y +10.00000y 10y          +10y         10.00000y    +10.00000y   10y          +10y         10.00000y    +10.00000y  
+1e-22 100y +100y      100y     +100y 100.00000y +100.00000y 00000100y +0000100y 100.00000y +100.00000y 100y         +100y        100.00000y   +100.00000y  100y         +100y        100.00000y   +100.00000y 
+1e-21 1z +1z        1z       +1z  1.00000z +1.00000z 00000001z +0000001z 01.00000z +1.00000z 1z           +1z          1.00000z     +1.00000z    1z           +1z          1.00000z     +1.00000z   
+1e-20 10z +10z       10z      +10z 10.00000z +10.00000z 00000010z +0000010z 10.00000z +10.00000z 10z          +10z         10.00000z    +10.00000z   10z          +10z         10.00000z    +10.00000z  
+1e-19 100z +100z      100z     +100z 100.00000z +100.00000z 00000100z +0000100z 100.00000z +100.00000z 100z         +100z        100.00000z   +100.00000z  100z         +100z        100.00000z   +100.00000z 
+1e-18 1a +1a        1a       +1a  1.00000a +1.00000a 00000001a +0000001a 01.00000a +1.00000a 1a           +1a          1.00000a     +1.00000a    1a           +1a          1.00000a     +1.00000a   
+1e-17 10a +10a       10a      +10a 10.00000a +10.00000a 00000010a +0000010a 10.00000a +10.00000a 10a          +10a         10.00000a    +10.00000a   10a          +10a         10.00000a    +10.00000a  
+1e-16 100a +100a      100a     +100a 100.00000a +100.00000a 00000100a +0000100a 100.00000a +100.00000a 100a         +100a        100.00000a   +100.00000a  100a         +100a        100.00000a   +100.00000a 
+1e-15 1f +1f        1f       +1f  1.00000f +1.00000f 00000001f +0000001f 01.00000f +1.00000f 1f           +1f          1.00000f     +1.00000f    1f           +1f          1.00000f     +1.00000f   
+1e-14 10f +10f       10f      +10f 10.00000f +10.00000f 00000010f +0000010f 10.00000f +10.00000f 10f          +10f         10.00000f    +10.00000f   10f          +10f         10.00000f    +10.00000f  
+1e-13 100f +100f      100f     +100f 100.00000f +100.00000f 00000100f +0000100f 100.00000f +100.00000f 100f         +100f        100.00000f   +100.00000f  100f         +100f        100.00000f   +100.00000f 
+1e-12 1p +1p        1p       +1p  1.00000p +1.00000p 00000001p +0000001p 01.00000p +1.00000p 1p           +1p          1.00000p     +1.00000p    1p           +1p          1.00000p     +1.00000p   
+1e-11 10p +10p       10p      +10p 10.00000p +10.00000p 00000010p +0000010p 10.00000p +10.00000p 10p          +10p         10.00000p    +10.00000p   10p          +10p         10.00000p    +10.00000p  
+1e-10 100p +100p      100p     +100p 100.00000p +100.00000p 00000100p +0000100p 100.00000p +100.00000p 100p         +100p        100.00000p   +100.00000p  100p         +100p        100.00000p   +100.00000p 
+1e-09 1n +1n         1n        +1n   1.00000n  +1.00000n 000000001n +00000001n 001.00000n +01.00000n 1n           +1n          1.00000n     +1.00000n    1n           +1n          1.00000n     +1.00000n   
+1e-08 10n +10n        10n       +10n  10.00000n +10.00000n 000000010n +00000010n 010.00000n +10.00000n 10n          +10n         10.00000n    +10.00000n   10n          +10n         10.00000n    +10.00000n  
+1e-07 100n +100n       100n      +100n 100.00000n +100.00000n 000000100n +00000100n 100.00000n +100.00000n 100n         +100n        100.00000n   +100.00000n  100n         +100n        100.00000n   +100.00000n 
+1e-06 1u +1u         1u        +1u   1.00000u  +1.00000u 000000001u +00000001u 001.00000u +01.00000u 1u           +1u          1.00000u     +1.00000u    1u           +1u          1.00000u     +1.00000u   
+1e-05 10u +10u        10u       +10u  10.00000u +10.00000u 000000010u +00000010u 010.00000u +10.00000u 10u          +10u         10.00000u    +10.00000u   10u          +10u         10.00000u    +10.00000u  
+0.0001 100u +100u       100u      +100u 100.00000u +100.00000u 000000100u +00000100u 100.00000u +100.00000u 100u         +100u        100.00000u   +100.00000u  100u         +100u        100.00000u   +100.00000u 
+0.001 1m +1m         1m        +1m   1.00000m  +1.00000m 000000001m +00000001m 001.00000m +01.00000m 1m           +1m          1.00000m     +1.00000m    1m           +1m          1.00000m     +1.00000m   
+0.01 10m +10m        10m       +10m  10.00000m +10.00000m 000000010m +00000010m 010.00000m +10.00000m 10m          +10m         10.00000m    +10.00000m   10m          +10m         10.00000m    +10.00000m  
+0.1 100m +100m       100m      +100m 100.00000m +100.00000m 000000100m +00000100m 100.00000m +100.00000m 100m         +100m        100.00000m   +100.00000m  100m         +100m        100.00000m   +100.00000m 
+1. 1 +1          1         +1    1.00000   +1.00000 0000000001 +000000001 0001.00000 +001.00000 1            +1           1.00000      +1.00000     1            +1           1.00000      +1.00000    
+10. 10 +10         10        +10   10.00000  +10.00000 0000000010 +000000010 0010.00000 +010.00000 10           +10          10.00000     +10.00000    10           +10          10.00000     +10.00000   
+100. 100 +100        100       +100  100.00000 +100.00000 0000000100 +000000100 0100.00000 +100.00000 100          +100         100.00000    +100.00000   100          +100         100.00000    +100.00000  
+1000. 1K +1K          1K         +1K    1.00000K   +1.00000K 0000000001K +000000001K 0001.00000K +001.00000K 1K           +1K          1.00000K     +1.00000K    1K           +1K          1.00000K     +1.00000K   
+10000. 10K +10K         10K        +10K   10.00000K  +10.00000K 0000000010K +000000010K 0010.00000K +010.00000K 10K          +10K         10.00000K    +10.00000K   10K          +10K         10.00000K    +10.00000K  
+100000. 100K +100K        100K       +100K  100.00000K +100.00000K 0000000100K +000000100K 0100.00000K +100.00000K 100K         +100K        100.00000K   +100.00000K  100K         +100K        100.00000K   +100.00000K 
+1000000. 1M +1M          1M         +1M    1.00000M   +1.00000M 0000000001M +000000001M 0001.00000M +001.00000M 1M           +1M          1.00000M     +1.00000M    1M           +1M          1.00000M     +1.00000M   
+10000000. 10M +10M         10M        +10M   10.00000M  +10.00000M 0000000010M +000000010M 0010.00000M +010.00000M 10M          +10M         10.00000M    +10.00000M   10M          +10M         10.00000M    +10.00000M  
+100000000. 100M +100M        100M       +100M  100.00000M +100.00000M 0000000100M +000000100M 0100.00000M +100.00000M 100M         +100M        100.00000M   +100.00000M  100M         +100M        100.00000M   +100.00000M 
+1000000000. 1G +1G          1G         +1G    1.00000G   +1.00000G 0000000001G +000000001G 0001.00000G +001.00000G 1G           +1G          1.00000G     +1.00000G    1G           +1G          1.00000G     +1.00000G   
+10000000000. 10G +10G         10G        +10G   10.00000G  +10.00000G 0000000010G +000000010G 0010.00000G +010.00000G 10G          +10G         10.00000G    +10.00000G   10G          +10G         10.00000G    +10.00000G  
+100000000000. 100G +100G        100G       +100G  100.00000G +100.00000G 0000000100G +000000100G 0100.00000G +100.00000G 100G         +100G        100.00000G   +100.00000G  100G         +100G        100.00000G   +100.00000G 
+1000000000000. 1T +1T         1T        +1T   1.00000T  +1.00000T 000000001T +00000001T 001.00000T +01.00000T 1T           +1T          1.00000T     +1.00000T    1T           +1T          1.00000T     +1.00000T   
+10000000000000. 10T +10T        10T       +10T  10.00000T +10.00000T 000000010T +00000010T 010.00000T +10.00000T 10T          +10T         10.00000T    +10.00000T   10T          +10T         10.00000T    +10.00000T  
+100000000000000. 100T +100T       100T      +100T 100.00000T +100.00000T 000000100T +00000100T 100.00000T +100.00000T 100T         +100T        100.00000T   +100.00000T  100T         +100T        100.00000T   +100.00000T 
+1e+15 1P +1P         1P        +1P   1.00000P  +1.00000P 000000001P +00000001P 001.00000P +01.00000P 1P           +1P          1.00000P     +1.00000P    1P           +1P          1.00000P     +1.00000P   
+1e+16 10P +10P        10P       +10P  10.00000P +10.00000P 000000010P +00000010P 010.00000P +10.00000P 10P          +10P         10.00000P    +10.00000P   10P          +10P         10.00000P    +10.00000P  
+1e+17 100P +100P       100P      +100P 100.00000P +100.00000P 000000100P +00000100P 100.00000P +100.00000P 100P         +100P        100.00000P   +100.00000P  100P         +100P        100.00000P   +100.00000P 
+1e+18 1E +1E         1E        +1E   1.00000E  +1.00000E 000000001E +00000001E 001.00000E +01.00000E 1E           +1E          1.00000E     +1.00000E    1E           +1E          1.00000E     +1.00000E   
+1e+19 10E +10E        10E       +10E  10.00000E +10.00000E 000000010E +00000010E 010.00000E +10.00000E 10E          +10E         10.00000E    +10.00000E   10E          +10E         10.00000E    +10.00000E  
+1e+20 100E +100E       100E      +100E 100.00000E +100.00000E 000000100E +00000100E 100.00000E +100.00000E 100E         +100E        100.00000E   +100.00000E  100E         +100E        100.00000E   +100.00000E 
+1e+21 1Z +1Z         1Z        +1Z   1.00000Z  +1.00000Z 000000001Z +00000001Z 001.00000Z +01.00000Z 1Z           +1Z          1.00000Z     +1.00000Z    1Z           +1Z          1.00000Z     +1.00000Z   
+1e+22 10Z +10Z        10Z       +10Z  10.00000Z +10.00000Z 000000010Z +00000010Z 010.00000Z +10.00000Z 10Z          +10Z         10.00000Z    +10.00000Z   10Z          +10Z         10.00000Z    +10.00000Z  
+1e+23 100Z +100Z       100Z      +100Z 100.00000Z +100.00000Z 000000100Z +00000100Z 100.00000Z +100.00000Z 100Z         +100Z        100.00000Z   +100.00000Z  100Z         +100Z        100.00000Z   +100.00000Z 
+1e+24 1Y +1Y         1Y        +1Y   1.00000Y  +1.00000Y 000000001Y +00000001Y 001.00000Y +01.00000Y 1Y           +1Y          1.00000Y     +1.00000Y    1Y           +1Y          1.00000Y     +1.00000Y   
+1e+25 10Y +10Y        10Y       +10Y  10.00000Y +10.00000Y 000000010Y +00000010Y 010.00000Y +10.00000Y 10Y          +10Y         10.00000Y    +10.00000Y   10Y          +10Y         10.00000Y    +10.00000Y  
+1e+26 100Y +100Y       100Y      +100Y 100.00000Y +100.00000Y 000000100Y +00000100Y 100.00000Y +100.00000Y 100Y         +100Y        100.00000Y   +100.00000Y  100Y         +100Y        100.00000Y   +100.00000Y 
+1e+27 1e27 +1e27         1e27        +1e27   1.00000e27  +1.00000e27 000000001e27 +00000001e27 001.00000e27 +01.00000e27 1e27         +1e27        1.00000e27   +1.00000e27  1e27         +1e27        1.00000e27   +1.00000e27 
+1e+28 10e27 +10e27        10e27       +10e27  10.00000e27 +10.00000e27 000000010e27 +00000010e27 010.00000e27 +10.00000e27 10e27        +10e27       10.00000e27  +10.00000e27 10e27        +10e27       10.00000e27  +10.00000e27
+1e+29 100e27 +100e27       100e27      +100e27 100.00000e27 +100.00000e27 000000100e27 +00000100e27 100.00000e27 +100.00000e27 100e27       +100e27      100.00000e27 +100.00000e27 100e27       +100e27      100.00000e27 +100.00000e27
+
+1e-27 1e-27 +1e-27        1e-27       +1e-27  1.00000e-27 +1.00000e-27 00000001e-27 +0000001e-27 01.00000e-27 +1.00000e-27 1e-27        +1e-27       1.00000e-27  +1.00000e-27 1e-27        +1e-27       1.00000e-27  +1.00000e-27
+4.2e-26 42e-27 +42e-27       42e-27      +42e-27 42.00000e-27 +42.00000e-27 00000042e-27 +0000042e-27 42.00000e-27 +42.00000e-27 42e-27       +42e-27      42.00000e-27 +42.00000e-27 42e-27       +42e-27      42.00000e-27 +42.00000e-27
+1.764e-24 1.764y +1.764y    1.764y   +1.764y  1.76400y +1.76400y 0001.764y +001.764y 01.76400y +1.76400y 1.764y       +1.764y      1.76400y     +1.76400y    1.764y       +1.764y      1.76400y     +1.76400y   
+7.4088e-23 74.088y +74.088y   74.088y  +74.088y 74.08800y +74.08800y 0074.088y +074.088y 74.08800y +74.08800y 74.088y      +74.088y     74.08800y    +74.08800y   74.088y      +74.088y     74.08800y    +74.08800y  
+3.111696e-21 3.1117z +3.1117z   3.1117z  +3.1117z  3.11170z +3.11170z 003.1117z +03.1117z 03.11170z +3.11170z 3.1117z      +3.1117z     3.11170z     +3.11170z    3.1117z      +3.1117z     3.11170z     +3.11170z   
+1.30691232e-19 130.691z +130.691z   130.69z  +130.69z 130.69123z +130.69123z 00130.69z +0130.69z 130.69123z +130.69123z 130.69z      +130.69z     130.69123z   +130.69123z  130.69z      +130.69z     130.69123z   +130.69123z 
+5.489031744e-18 5.48903a +5.48903a    5.489a   +5.489a  5.48903a +5.48903a 0005.489a +005.489a 05.48903a +5.48903a 5.489a       +5.489a      5.48903a     +5.48903a    5.489a       +5.489a      5.48903a     +5.48903a   
+2.30539333248e-16 230.539a +230.539a   230.54a  +230.54a 230.53933a +230.53933a 00230.54a +0230.54a 230.53933a +230.53933a 230.54a      +230.54a     230.53933a   +230.53933a  230.54a      +230.54a     230.53933a   +230.53933a 
+9.682651996416e-15 9.68265f +9.68265f   9.6827f  +9.6827f  9.68265f +9.68265f 009.6827f +09.6827f 09.68265f +9.68265f 9.6827f      +9.6827f     9.68265f     +9.68265f    9.6827f      +9.6827f     9.68265f     +9.68265f   
+4.06671383849472e-13 406.671f +406.671f   406.67f  +406.67f 406.67138f +406.67138f 00406.67f +0406.67f 406.67138f +406.67138f 406.67f      +406.67f     406.67138f   +406.67138f  406.67f      +406.67f     406.67138f   +406.67138f 
+1.70801981216778e-11 17.0802p +17.0802p    17.08p   +17.08p 17.08020p +17.08020p 00017.08p +0017.08p 17.08020p +17.08020p 17.08p       +17.08p      17.08020p    +17.08020p   17.08p       +17.08p      17.08020p    +17.08020p  
+7.17368321110469e-10 717.368p +717.368p   717.37p  +717.37p 717.36832p +717.36832p 00717.37p +0717.37p 717.36832p +717.36832p 717.37p      +717.37p     717.36832p   +717.36832p  717.37p      +717.37p     717.36832p   +717.36832p 
+3.01294694866397e-08 30.1295n +30.1295n    30.129n   +30.129n  30.12947n +30.12947n 00030.129n +0030.129n 030.12947n +30.12947n 30.129n      +30.129n     30.12947n    +30.12947n   30.129n      +30.129n     30.12947n    +30.12947n  
+1.26543771843887e-06 1.26544u +1.26544u    1.2654u   +1.2654u   1.26544u  +1.26544u 0001.2654u +001.2654u 001.26544u +01.26544u 1.2654u      +1.2654u     1.26544u     +1.26544u    1.2654u      +1.2654u     1.26544u     +1.26544u   
+5.31483841744324e-05 53.1484u +53.1484u    53.148u   +53.148u  53.14838u +53.14838u 00053.148u +0053.148u 053.14838u +53.14838u 53.148u      +53.148u     53.14838u    +53.14838u   53.148u      +53.148u     53.14838u    +53.14838u  
+0.00223223213532616 2.23223m +2.23223m    2.2322m   +2.2322m   2.23223m  +2.23223m 0002.2322m +002.2322m 002.23223m +02.23223m 2.2322m      +2.2322m     2.23223m     +2.23223m    2.2322m      +2.2322m     2.23223m     +2.23223m   
+0.0937537496836987 93.7537m +93.7537m    93.754m   +93.754m  93.75375m +93.75375m 00093.754m +0093.754m 093.75375m +93.75375m 93.754m      +93.754m     93.75375m    +93.75375m   93.754m      +93.754m     93.75375m    +93.75375m  
+3.93765748671535 3.93766 +3.93766     3.9377    +3.9377    3.93766   +3.93766 00003.9377 +0003.9377 0003.93766 +003.93766 3.9377       +3.9377      3.93766      +3.93766     3.9377       +3.9377      3.93766      +3.93766    
+165.381614442045 165.382 +165.382     165.38    +165.38  165.38161 +165.38161 0000165.38 +000165.38 0165.38161 +165.38161 165.38       +165.38      165.38161    +165.38161   165.38       +165.38      165.38161    +165.38161  
+6946.02780656587 6.94603K +6.94603K      6.946K     +6.946K    6.94603K   +6.94603K 000006.946K +00006.946K 0006.94603K +006.94603K 6.946K       +6.946K      6.94603K     +6.94603K    6.946K       +6.946K      6.94603K     +6.94603K   
+291733.167875767 291.733K +291.733K     291.73K    +291.73K  291.73317K +291.73317K 0000291.73K +000291.73K 0291.73317K +291.73317K 291.73K      +291.73K     291.73317K   +291.73317K  291.73K      +291.73K     291.73317K   +291.73317K 
+12252793.0507822 12.2528M +12.2528M     12.253M    +12.253M   12.25279M  +12.25279M 000012.253M +00012.253M 0012.25279M +012.25279M 12.253M      +12.253M     12.25279M    +12.25279M   12.253M      +12.253M     12.25279M    +12.25279M  
+514617308.132852 514.617M +514.617M     514.62M    +514.62M  514.61731M +514.61731M 0000514.62M +000514.62M 0514.61731M +514.61731M 514.62M      +514.62M     514.61731M   +514.61731M  514.62M      +514.62M     514.61731M   +514.61731M 
+21613926941.5798 21.6139G +21.6139G     21.614G    +21.614G   21.61393G  +21.61393G 000021.614G +00021.614G 0021.61393G +021.61393G 21.614G      +21.614G     21.61393G    +21.61393G   21.614G      +21.614G     21.61393G    +21.61393G  
+907784931546.352 907.785G +907.785G     907.78G    +907.78G  907.78493G +907.78493G 0000907.78G +000907.78G 0907.78493G +907.78493G 907.78G      +907.78G     907.78493G   +907.78493G  907.78G      +907.78G     907.78493G   +907.78493G 
+38126967124946.8 38.127T +38.127T    38.127T   +38.127T  38.12697T +38.12697T 00038.127T +0038.127T 038.12697T +38.12697T 38.127T      +38.127T     38.12697T    +38.12697T   38.127T      +38.127T     38.12697T    +38.12697T  
+1.60133261924776e+15 1.60133P +1.60133P    1.6013P   +1.6013P   1.60133P  +1.60133P 0001.6013P +001.6013P 001.60133P +01.60133P 1.6013P      +1.6013P     1.60133P     +1.60133P    1.6013P      +1.6013P     1.60133P     +1.60133P   
+6.72559700084061e+16 67.256P +67.256P    67.256P   +67.256P  67.25597P +67.25597P 00067.256P +0067.256P 067.25597P +67.25597P 67.256P      +67.256P     67.25597P    +67.25597P   67.256P      +67.256P     67.25597P    +67.25597P  
+2.82475074035306e+18 2.82475E +2.82475E    2.8248E   +2.8248E   2.82475E  +2.82475E 0002.8248E +002.8248E 002.82475E +02.82475E 2.8248E      +2.8248E     2.82475E     +2.82475E    2.8248E      +2.8248E     2.82475E     +2.82475E   
+1.18639531094828e+20 118.64E +118.64E    118.64E   +118.64E 118.63953E +118.63953E 000118.64E +00118.64E 118.63953E +118.63953E 118.64E      +118.64E     118.63953E   +118.63953E  118.64E      +118.64E     118.63953E   +118.63953E 
+4.98286030598279e+21 4.98286Z +4.98286Z    4.9829Z   +4.9829Z   4.98286Z  +4.98286Z 0004.9829Z +004.9829Z 004.98286Z +04.98286Z 4.9829Z      +4.9829Z     4.98286Z     +4.98286Z    4.9829Z      +4.9829Z     4.98286Z     +4.98286Z   
+2.09280132851277e+23 209.28Z +209.28Z    209.28Z   +209.28Z 209.28013Z +209.28013Z 000209.28Z +00209.28Z 209.28013Z +209.28013Z 209.28Z      +209.28Z     209.28013Z   +209.28013Z  209.28Z      +209.28Z     209.28013Z   +209.28013Z 
+8.78976557975365e+24 8.78977Y +8.78977Y    8.7898Y   +8.7898Y   8.78977Y  +8.78977Y 0008.7898Y +008.7898Y 008.78977Y +08.78977Y 8.7898Y      +8.7898Y     8.78977Y     +8.78977Y    8.7898Y      +8.7898Y     8.78977Y     +8.78977Y   
+3.69170154349653e+26 369.17Y +369.17Y    369.17Y   +369.17Y 369.17015Y +369.17015Y 000369.17Y +00369.17Y 369.17015Y +369.17015Y 369.17Y      +369.17Y     369.17015Y   +369.17015Y  369.17Y      +369.17Y     369.17015Y   +369.17015Y 
+1.55051464826854e+28 15.5051e27 +15.5051e27    15.505e27   +15.505e27  15.50515e27 +15.50515e27 00015.505e27 +0015.505e27 015.50515e27 +15.50515e27 15.505e27    +15.505e27   15.50515e27  +15.50515e27 15.505e27    +15.505e27   15.50515e27  +15.50515e27
+6.51216152272788e+29 651.216e27 +651.216e27    651.22e27   +651.22e27 651.21615e27 +651.21615e27 000651.22e27 +00651.22e27 651.21615e27 +651.21615e27 651.22e27    +651.22e27   651.21615e27 +651.21615e27 651.22e27    +651.22e27   651.21615e27 +651.21615e27
+
+-1e-27 -1e-27 -1e-27       -1e-27       -1e-27 -1.00000e-27 -1.00000e-27 -0000001e-27 -0000001e-27 -1.00000e-27 -1.00000e-27 -1e-27       -1e-27       -1.00000e-27 -1.00000e-27 -1e-27       -1e-27       -1.00000e-27 -1.00000e-27
+-4.2e-26 -42e-27 -42e-27      -42e-27      -42e-27 -42.00000e-27 -42.00000e-27 -0000042e-27 -0000042e-27 -42.00000e-27 -42.00000e-27 -42e-27      -42e-27      -42.00000e-27 -42.00000e-27 -42e-27      -42e-27      -42.00000e-27 -42.00000e-27
+-1.764e-24 -1.764e-24 -1.764e-24   -1.764e-24   -1.764e-24 -1.76400e-24 -1.76400e-24 -001.764e-24 -001.764e-24 -1.76400e-24 -1.76400e-24 -1.764e-24   -1.764e-24   -1.76400e-24 -1.76400e-24 -1.764e-24   -1.764e-24   -1.76400e-24 -1.76400e-24
+-7.4088e-23 -74.088e-24 -74.088e-24  -74.088e-24  -74.088e-24 -74.08800e-24 -74.08800e-24 -074.088e-24 -074.088e-24 -74.08800e-24 -74.08800e-24 -74.088e-24  -74.088e-24  -74.08800e-24 -74.08800e-24 -74.088e-24  -74.088e-24  -74.08800e-24 -74.08800e-24
+-3.111696e-21 -3.1117e-21 -3.1117e-21  -3.1117e-21  -3.1117e-21 -3.11170e-21 -3.11170e-21 -03.1117e-21 -03.1117e-21 -3.11170e-21 -3.11170e-21 -3.1117e-21  -3.1117e-21  -3.11170e-21 -3.11170e-21 -3.1117e-21  -3.1117e-21  -3.11170e-21 -3.11170e-21
+-1.30691232e-19 -130.691e-21 -130.691e-21  -130.69e-21  -130.69e-21 -130.69123e-21 -130.69123e-21 -0130.69e-21 -0130.69e-21 -130.69123e-21 -130.69123e-21 -130.69e-21  -130.69e-21  -130.69123e-21 -130.69123e-21 -130.69e-21  -130.69e-21  -130.69123e-21 -130.69123e-21
+-5.489031744e-18 -5.48903e-18 -5.48903e-18   -5.489e-18   -5.489e-18 -5.48903e-18 -5.48903e-18 -005.489e-18 -005.489e-18 -5.48903e-18 -5.48903e-18 -5.489e-18   -5.489e-18   -5.48903e-18 -5.48903e-18 -5.489e-18   -5.489e-18   -5.48903e-18 -5.48903e-18
+-2.30539333248e-16 -230.539e-18 -230.539e-18  -230.54e-18  -230.54e-18 -230.53933e-18 -230.53933e-18 -0230.54e-18 -0230.54e-18 -230.53933e-18 -230.53933e-18 -230.54e-18  -230.54e-18  -230.53933e-18 -230.53933e-18 -230.54e-18  -230.54e-18  -230.53933e-18 -230.53933e-18
+-9.682651996416e-15 -9.68265e-15 -9.68265e-15  -9.6827e-15  -9.6827e-15 -9.68265e-15 -9.68265e-15 -09.6827e-15 -09.6827e-15 -9.68265e-15 -9.68265e-15 -9.6827e-15  -9.6827e-15  -9.68265e-15 -9.68265e-15 -9.6827e-15  -9.6827e-15  -9.68265e-15 -9.68265e-15
+-4.06671383849472e-13 -406.671e-15 -406.671e-15  -406.67e-15  -406.67e-15 -406.67138e-15 -406.67138e-15 -0406.67e-15 -0406.67e-15 -406.67138e-15 -406.67138e-15 -406.67e-15  -406.67e-15  -406.67138e-15 -406.67138e-15 -406.67e-15  -406.67e-15  -406.67138e-15 -406.67138e-15
+-1.70801981216778e-11 -17.0802e-12 -17.0802e-12   -17.08e-12   -17.08e-12 -17.08020e-12 -17.08020e-12 -0017.08e-12 -0017.08e-12 -17.08020e-12 -17.08020e-12 -17.08e-12   -17.08e-12   -17.08020e-12 -17.08020e-12 -17.08e-12   -17.08e-12   -17.08020e-12 -17.08020e-12
+-7.17368321110469e-10 -717.368e-12 -717.368e-12  -717.37e-12  -717.37e-12 -717.36832e-12 -717.36832e-12 -0717.37e-12 -0717.37e-12 -717.36832e-12 -717.36832e-12 -717.37e-12  -717.37e-12  -717.36832e-12 -717.36832e-12 -717.37e-12  -717.37e-12  -717.36832e-12 -717.36832e-12
+-3.01294694866397e-08 -30.1295e-9 -30.1295e-9   -30.129e-9   -30.129e-9 -30.12947e-9 -30.12947e-9 -0030.129e-9 -0030.129e-9 -30.12947e-9 -30.12947e-9 -30.129e-9   -30.129e-9   -30.12947e-9 -30.12947e-9 -30.129e-9   -30.129e-9   -30.12947e-9 -30.12947e-9
+-1.26543771843887e-06 -1.26544e-6 -1.26544e-6   -1.2654e-6   -1.2654e-6  -1.26544e-6  -1.26544e-6 -001.2654e-6 -001.2654e-6 -01.26544e-6 -01.26544e-6 -1.2654e-6   -1.2654e-6   -1.26544e-6  -1.26544e-6  -1.2654e-6   -1.2654e-6   -1.26544e-6  -1.26544e-6 
+-5.31483841744324e-05 -53.1484e-6 -53.1484e-6   -53.148e-6   -53.148e-6 -53.14838e-6 -53.14838e-6 -0053.148e-6 -0053.148e-6 -53.14838e-6 -53.14838e-6 -53.148e-6   -53.148e-6   -53.14838e-6 -53.14838e-6 -53.148e-6   -53.148e-6   -53.14838e-6 -53.14838e-6
+-0.00223223213532616 -2.23223e-3 -2.23223e-3   -2.2322e-3   -2.2322e-3  -2.23223e-3  -2.23223e-3 -002.2322e-3 -002.2322e-3 -02.23223e-3 -02.23223e-3 -2.2322e-3   -2.2322e-3   -2.23223e-3  -2.23223e-3  -2.2322e-3   -2.2322e-3   -2.23223e-3  -2.23223e-3 
+-0.0937537496836987 -93.7537e-3 -93.7537e-3   -93.754e-3   -93.754e-3 -93.75375e-3 -93.75375e-3 -0093.754e-3 -0093.754e-3 -93.75375e-3 -93.75375e-3 -93.754e-3   -93.754e-3   -93.75375e-3 -93.75375e-3 -93.754e-3   -93.754e-3   -93.75375e-3 -93.75375e-3
+-3.93765748671535 -3.93766e0 -3.93766e0    -3.9377e0    -3.9377e0   -3.93766e0   -3.93766e0 -0003.9377e0 -0003.9377e0 -003.93766e0 -003.93766e0 -3.9377e0    -3.9377e0    -3.93766e0   -3.93766e0   -3.9377e0    -3.9377e0    -3.93766e0   -3.93766e0  
+-165.381614442045 -165.382e0 -165.382e0    -165.38e0    -165.38e0 -165.38161e0 -165.38161e0 -000165.38e0 -000165.38e0 -165.38161e0 -165.38161e0 -165.38e0    -165.38e0    -165.38161e0 -165.38161e0 -165.38e0    -165.38e0    -165.38161e0 -165.38161e0
+-6946.02780656587 -6.94603e3 -6.94603e3     -6.946e3     -6.946e3   -6.94603e3   -6.94603e3 -00006.946e3 -00006.946e3 -006.94603e3 -006.94603e3 -6.946e3     -6.946e3     -6.94603e3   -6.94603e3   -6.946e3     -6.946e3     -6.94603e3   -6.94603e3  
+-291733.167875767 -291.733e3 -291.733e3    -291.73e3    -291.73e3 -291.73317e3 -291.73317e3 -000291.73e3 -000291.73e3 -291.73317e3 -291.73317e3 -291.73e3    -291.73e3    -291.73317e3 -291.73317e3 -291.73e3    -291.73e3    -291.73317e3 -291.73317e3
+-12252793.0507822 -12.2528e6 -12.2528e6    -12.253e6    -12.253e6  -12.25279e6  -12.25279e6 -00012.253e6 -00012.253e6 -012.25279e6 -012.25279e6 -12.253e6    -12.253e6    -12.25279e6  -12.25279e6  -12.253e6    -12.253e6    -12.25279e6  -12.25279e6 
+-514617308.132852 -514.617e6 -514.617e6    -514.62e6    -514.62e6 -514.61731e6 -514.61731e6 -000514.62e6 -000514.62e6 -514.61731e6 -514.61731e6 -514.62e6    -514.62e6    -514.61731e6 -514.61731e6 -514.62e6    -514.62e6    -514.61731e6 -514.61731e6
+-21613926941.5798 -21.6139e9 -21.6139e9    -21.614e9    -21.614e9  -21.61393e9  -21.61393e9 -00021.614e9 -00021.614e9 -021.61393e9 -021.61393e9 -21.614e9    -21.614e9    -21.61393e9  -21.61393e9  -21.614e9    -21.614e9    -21.61393e9  -21.61393e9 
+-907784931546.352 -907.785e9 -907.785e9    -907.78e9    -907.78e9 -907.78493e9 -907.78493e9 -000907.78e9 -000907.78e9 -907.78493e9 -907.78493e9 -907.78e9    -907.78e9    -907.78493e9 -907.78493e9 -907.78e9    -907.78e9    -907.78493e9 -907.78493e9
+-38126967124946.8 -38.127e12 -38.127e12   -38.127e12   -38.127e12 -38.12697e12 -38.12697e12 -0038.127e12 -0038.127e12 -38.12697e12 -38.12697e12 -38.127e12   -38.127e12   -38.12697e12 -38.12697e12 -38.127e12   -38.127e12   -38.12697e12 -38.12697e12
+-1.60133261924776e+15 -1.60133e15 -1.60133e15   -1.6013e15   -1.6013e15  -1.60133e15  -1.60133e15 -001.6013e15 -001.6013e15 -01.60133e15 -01.60133e15 -1.6013e15   -1.6013e15   -1.60133e15  -1.60133e15  -1.6013e15   -1.6013e15   -1.60133e15  -1.60133e15 
+-6.72559700084061e+16 -67.256e15 -67.256e15   -67.256e15   -67.256e15 -67.25597e15 -67.25597e15 -0067.256e15 -0067.256e15 -67.25597e15 -67.25597e15 -67.256e15   -67.256e15   -67.25597e15 -67.25597e15 -67.256e15   -67.256e15   -67.25597e15 -67.25597e15
+-2.82475074035306e+18 -2.82475e18 -2.82475e18   -2.8248e18   -2.8248e18  -2.82475e18  -2.82475e18 -002.8248e18 -002.8248e18 -02.82475e18 -02.82475e18 -2.8248e18   -2.8248e18   -2.82475e18  -2.82475e18  -2.8248e18   -2.8248e18   -2.82475e18  -2.82475e18 
+-1.18639531094828e+20 -118.64e18 -118.64e18   -118.64e18   -118.64e18 -118.63953e18 -118.63953e18 -00118.64e18 -00118.64e18 -118.63953e18 -118.63953e18 -118.64e18   -118.64e18   -118.63953e18 -118.63953e18 -118.64e18   -118.64e18   -118.63953e18 -118.63953e18
+-4.98286030598279e+21 -4.98286e21 -4.98286e21   -4.9829e21   -4.9829e21  -4.98286e21  -4.98286e21 -004.9829e21 -004.9829e21 -04.98286e21 -04.98286e21 -4.9829e21   -4.9829e21   -4.98286e21  -4.98286e21  -4.9829e21   -4.9829e21   -4.98286e21  -4.98286e21 
+-2.09280132851277e+23 -209.28e21 -209.28e21   -209.28e21   -209.28e21 -209.28013e21 -209.28013e21 -00209.28e21 -00209.28e21 -209.28013e21 -209.28013e21 -209.28e21   -209.28e21   -209.28013e21 -209.28013e21 -209.28e21   -209.28e21   -209.28013e21 -209.28013e21
+-8.78976557975365e+24 -8.78977e24 -8.78977e24   -8.7898e24   -8.7898e24  -8.78977e24  -8.78977e24 -008.7898e24 -008.7898e24 -08.78977e24 -08.78977e24 -8.7898e24   -8.7898e24   -8.78977e24  -8.78977e24  -8.7898e24   -8.7898e24   -8.78977e24  -8.78977e24 
+-3.69170154349653e+26 -369.17e24 -369.17e24   -369.17e24   -369.17e24 -369.17015e24 -369.17015e24 -00369.17e24 -00369.17e24 -369.17015e24 -369.17015e24 -369.17e24   -369.17e24   -369.17015e24 -369.17015e24 -369.17e24   -369.17e24   -369.17015e24 -369.17015e24
+-1.55051464826854e+28 -15.5051e27 -15.5051e27   -15.505e27   -15.505e27 -15.50515e27 -15.50515e27 -0015.505e27 -0015.505e27 -15.50515e27 -15.50515e27 -15.505e27   -15.505e27   -15.50515e27 -15.50515e27 -15.505e27   -15.505e27   -15.50515e27 -15.50515e27
+-6.51216152272788e+29 -651.216e27 -651.216e27   -651.22e27   -651.22e27 -651.21615e27 -651.21615e27 -00651.22e27 -00651.22e27 -651.21615e27 -651.21615e27 -651.22e27   -651.22e27   -651.21615e27 -651.21615e27 -651.22e27   -651.22e27   -651.21615e27 -651.21615e27
Index: tests/io/manipulatorsOutput1.cfa
===================================================================
--- tests/io/manipulatorsOutput1.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/io/manipulatorsOutput1.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -7,6 +7,6 @@
 // Created On       : Sat Jun  8 18:04:11 2019
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri May  1 11:51:44 2020
-// Update Count     : 9
+// Last Modified On : Sat Apr 10 08:42:15 2021
+// Update Count     : 18
 // 
 
@@ -85,16 +85,17 @@
 	sout | "double";
 	double d = 3.537;
-	printf( "%g  %#8f %g %8f %#8.0f %8.0f %8.2f %-8.2f %-+#8.2f %08.2F %8.2E %8.2a %8.2A %8.2e\n",
-			0.0,  3.0, d,  d,     d,    d,    d,     d,       d,     d,    d,    d,    d,    d );
-	sout | 0.0 | wd(8, 3.0) | d | wd(8, d) | nodp(wd(8,0, d)) | wd(8,0, d) | wd(8,2, d) | nonl;
-	sout | left(wd(8,2, d)) | left(sign(wd(8,2, d))) | pad0(upcase(wd(8,2, d))) | upcase(wd(8,2, sci(d))) | wd(8,2, hex(d)) | upcase(wd(8,2, hex(d))) | wd(8,2, sci(d));
+	printf( "%g  %8g %#8g %g %8g %8.0g %#8.0g %8.2g %#8.2g %-8.2g %-8.2g %-#8.2g %-+8.2g %-+#8.2g %08.2g %8.2E %8.2a %#8.2A %#8.2e\n",
+		    0.0, 3.0, 3.0, d,  d,    d,     d,    d,     d,   3.0,     d,      d,      d,       d,     d,    d,    d,     d,     d );
+	sout | 0.0 | wd(8, 3.0) | nodp(wd(8, 3.0)) | d | wd(8, d) | ws(8,0, d) | nodp(ws(8,0, d)) | ws(8,2, d) | nodp(ws(8,2, d)) | nonl;
+	sout | left(ws(8,2, 3.0)) | left(ws(8,2, d)) | left(nodp(ws(8,2, d))) | left(sign(ws(8,2, d))) | left(sign(nodp(ws(8,2, d)))) | nonl;
+	sout | pad0(ws(8,2, d)) | upcase(wd(8,2, sci(d))) | wd(8,2, hex(d)) | upcase(wd(8,2, hex(d))) | nodp(wd(8,2, sci(d)));
 
 	sout | "long double";
 	long double ld = 3.537;
-	printf( "%Lg  %#8Lf %Lg %8Lf %#8.0Lf %8.0Lf %8.2Lf %-8.2Lf %-+#8.2Lf %08.2LF %8.2LE %8.2La %8.2LA %8.2Le\n",
-			0.0L,  3.0L, ld,  ld,     ld,    ld,    ld,     ld,       ld,     ld,    ld,    ld,    ld,    ld );
-	sout | 0.0L | wd(8, 3.0L) | ld | wd(8, ld) | nodp(wd(8,0, ld)) | wd(8,0, ld) | wd(8,2, ld) | nonl;
-	sout | left(wd(8,2, ld)) | left(sign(wd(8,2, ld))) | pad0(upcase(wd(8,2, ld))) | upcase(wd(8,2, sci(ld))) | wd(8,2, hex(ld)) | upcase(wd(8,2, hex(ld))) | wd(8,2, sci(ld));
-
+	printf( "%Lg  %8Lg %#8Lg %Lg %8Lg %8.0Lg %#8.0Lg %8.2Lg %#8.2Lg %-8.2Lg %-8.2Lg %-#8.2Lg %-+8.2Lg %-+#8.2Lg %08.2Lg %8.2LE %8.2La %#8.2LA %#8.2Le\n",
+		    0.0L, 3.0L, 3.0L, ld,  ld,    ld,     ld,    ld,     ld,   3.0L,     ld,      ld,      ld,       ld,     ld,    ld,    ld,     ld,     ld );
+	sout | 0.0L | wd(8, 3.0L) | nodp(wd(8, 3.0L)) | ld | wd(8, ld) | ws(8,0, ld) | nodp(ws(8,0, ld)) | ws(8,2, ld) | nodp(ws(8,2, ld)) | nonl;
+	sout | left(ws(8,2, 3.0L)) | left(ws(8,2, ld)) | left(nodp(ws(8,2, ld))) | left(sign(ws(8,2, ld))) | left(sign(nodp(ws(8,2, ld)))) | nonl;
+	sout | pad0(ws(8,2, ld)) | upcase(wd(8,2, sci(ld))) | wd(8,2, hex(ld)) | upcase(wd(8,2, hex(ld))) | nodp(wd(8,2, sci(ld)));
 
 	sout | nl | "char";
@@ -117,4 +118,4 @@
 // Local Variables: //
 // tab-width: 4 //
-// compile-command: "cfa -Wall -Wextra amanipulatorsOutput1.cfa" //
+// compile-command: "cfa -Wall -Wextra manipulatorsOutput1.cfa" //
 // End: //
Index: tests/io/manipulatorsOutput2.cfa
===================================================================
--- tests/io/manipulatorsOutput2.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/io/manipulatorsOutput2.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -7,6 +7,6 @@
 // Created On       : Sat Jun  8 18:04:11 2019
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Nov 15 08:11:53 2020
-// Update Count     : 9
+// Last Modified On : Sat Apr 10 09:16:09 2021
+// Update Count     : 11
 // 
 
@@ -24,4 +24,5 @@
     sout | hex(-27.5F) | hex(-27.5) | hex(-27.5L);
 	sout | sci(0.0) | sci(27.5) | sci(-27.5);
+	sout | eng(0.0) | eng(27.5) | eng(-27.5);
 	sout | upcase(bin(27)) | upcase(hex(27)) | upcase(27.5e-10) | upcase(hex(27.5));
 	sout | nobase(bin(27)) | nobase(oct(27)) | nobase(hex(27));
Index: tests/io/manipulatorsOutput3.cfa
===================================================================
--- tests/io/manipulatorsOutput3.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/io/manipulatorsOutput3.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -1,2 +1,14 @@
+// 
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+// 
+// manipulatorsOutput3.cfa -- 
+// 
+// Author           : Peter A. Buhr
+// Created On       : Tue Apr 13 17:54:23 2021
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Tue Apr 13 17:54:48 2021
+// Update Count     : 1
+// 
+
 #include <fstream.hfa>
 
Index: tests/io/manipulatorsOutput4.cfa
===================================================================
--- tests/io/manipulatorsOutput4.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
+++ tests/io/manipulatorsOutput4.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -0,0 +1,49 @@
+// 
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+// 
+// manipulatorsOutput4.cfa -- 
+// 
+// Author           : Peter A. Buhr
+// Created On       : Tue Apr 13 17:55:02 2021
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Tue Apr 13 18:00:33 2021
+// Update Count     : 4
+// 
+
+#include <fstream.hfa>
+
+int main() {
+	for ( double w = 1e-27; w < 1e30; w *= 10 ) {
+		sout | w | eng(w) | sign(eng(w)) | ws(12,5, eng(w) ) | sign(ws(12,5, eng(w) )) | wd(12,5, eng(w) ) | sign(wd(12,5, eng(w) )) | pad0(ws(12,5, eng(w) )) | pad0(sign(ws(12,5, eng(w) ))) | pad0(wd(12,5, eng(w) )) | pad0(sign(wd(12,5, eng(w) )))
+			 | left(ws(12,5, eng(w) )) | left(sign(ws(12,5, eng(w) ))) | left(wd(12,5, eng(w) )) | left(sign(wd(12,5, eng(w) ))) | left(pad0(ws(12,5, eng(w) ))) | left(pad0(sign(ws(12,5, eng(w) )))) | left(pad0(wd(12,5, eng(w) ))) | left(pad0(sign(wd(12,5, eng(w) ))));
+	} // for
+	sout | nl;
+
+	for ( double w = 1e-27; w < 1e30; w *= 42 ) {
+		sout | w | eng(w) | sign(eng(w)) | ws(12,5, eng(w) ) | sign(ws(12,5, eng(w) )) | wd(12,5, eng(w) ) | sign(wd(12,5, eng(w) )) | pad0(ws(12,5, eng(w) )) | pad0(sign(ws(12,5, eng(w) ))) | pad0(wd(12,5, eng(w) )) | pad0(sign(wd(12,5, eng(w) )))
+			 | left(ws(12,5, eng(w) )) | left(sign(ws(12,5, eng(w) ))) | left(wd(12,5, eng(w) )) | left(sign(wd(12,5, eng(w) ))) | left(pad0(ws(12,5, eng(w) ))) | left(pad0(sign(ws(12,5, eng(w) )))) | left(pad0(wd(12,5, eng(w) ))) | left(pad0(sign(wd(12,5, eng(w) ))));
+	} // for
+	sout | nl;
+
+	for ( double w = 1e-27; w < 1e30; w *= 10 ) {
+		sout | w | unit(eng(w)) | unit(sign(eng(w))) | unit(ws(12,5, eng(w) )) | unit(sign(ws(12,5, eng(w) ))) | unit(wd(12,5, eng(w) )) | unit(sign(wd(12,5, eng(w) ))) | unit(pad0(ws(12,5, eng(w) ))) | unit(pad0(sign(ws(12,5, eng(w) )))) | unit(pad0(wd(12,5, eng(w) ))) | unit(pad0(sign(wd(12,5, eng(w) ))))
+			| unit(left(ws(12,5, eng(w) ))) | unit(left(sign(ws(12,5, eng(w) )))) | unit(left(wd(12,5, eng(w) ))) | unit(left(sign(wd(12,5, eng(w) )))) | unit(left(pad0(ws(12,5, eng(w) )))) | unit(left(pad0(sign(ws(12,5, eng(w) ))))) | unit(left(pad0(wd(12,5, eng(w) )))) | unit(left(pad0(sign(wd(12,5, eng(w) )))));
+	} // for
+	sout | nl;
+
+	for ( double w = 1e-27; w < 1e30; w *= 42 ) {
+		sout | w | unit(eng(w)) | unit(sign(eng(w))) | unit(ws(12,5, eng(w) )) | unit(sign(ws(12,5, eng(w) ))) | unit(wd(12,5, eng(w) )) | unit(sign(wd(12,5, eng(w) ))) | unit(pad0(ws(12,5, eng(w) ))) | unit(pad0(sign(ws(12,5, eng(w) )))) | unit(pad0(wd(12,5, eng(w) ))) | unit(pad0(sign(wd(12,5, eng(w) ))))
+			| unit(left(ws(12,5, eng(w) ))) | unit(left(sign(ws(12,5, eng(w) )))) | unit(left(wd(12,5, eng(w) ))) | unit(left(sign(wd(12,5, eng(w) )))) | unit(left(pad0(ws(12,5, eng(w) )))) | unit(left(pad0(sign(ws(12,5, eng(w) ))))) | unit(left(pad0(wd(12,5, eng(w) )))) | unit(left(pad0(sign(wd(12,5, eng(w) )))));
+	} // for
+	sout | nl;
+
+	for ( double w = -1e-27; w > -1e30; w *= 42 ) {
+		sout | w | eng(w) | sign(eng(w)) | ws(12,5, eng(w) ) | sign(ws(12,5, eng(w) )) | wd(12,5, eng(w) ) | sign(wd(12,5, eng(w) )) | pad0(ws(12,5, eng(w) )) | pad0(sign(ws(12,5, eng(w) ))) | pad0(wd(12,5, eng(w) )) | pad0(sign(wd(12,5, eng(w) )))
+			 | left(ws(12,5, eng(w) )) | left(sign(ws(12,5, eng(w) ))) | left(wd(12,5, eng(w) )) | left(sign(wd(12,5, eng(w) ))) | left(pad0(ws(12,5, eng(w) ))) | left(pad0(sign(ws(12,5, eng(w) )))) | left(pad0(wd(12,5, eng(w) ))) | left(pad0(sign(wd(12,5, eng(w) ))));
+	} // for
+} // main
+
+// Local Variables: //
+// tab-width: 4 //
+// compile-command: "cfa -Wall -Wextra manipulatorsOutput4.cfa" //
+// End: //
Index: tests/linking/exception-nothreads.cfa
===================================================================
--- tests/linking/exception-nothreads.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/linking/exception-nothreads.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/linking/exception-withthreads.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -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/math.cfa
===================================================================
--- tests/math.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/math.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -10,6 +10,6 @@
 // Created On       : Fri Apr 22 14:59:21 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Feb 20 18:00:48 2021
-// Update Count     : 115
+// Last Modified On : Tue Apr 13 21:04:48 2021
+// Update Count     : 123
 //
 
@@ -69,4 +69,10 @@
 	sout | "log:" | log( 1.0F ) | log( 1.0D ) | log( 1.0L ) | nonl;
 	sout | log( 1.0F+1.0FI ) | log( 1.0D+1.0DI ) | log( 1.0DL+1.0LI );
+	sout | "log2:" | log2( 1024 ) | log2( 2 \ 17u ) | log2( 2 \ 23u );
+	sout | "log2:" | log2( 1024l ) | log2( 2l \ 17u ) | log2( 2l \ 23u );
+	sout | "log2:" | log2( 1024ll ) | log2( 2ll \ 17u ) | log2( 2ll \ 23u );
+#if defined( __SIZEOF_INT128__ )
+	sout | "log2:" | log2( 1024l128 ) | log2( 2l128 \ 17u ) | log2( 2l128 \ 23u );
+#endif // __SIZEOF_INT128__
 	sout | "log2:" | log2( 8.0F ) | log2( 8.0D ) | log2( 8.0L );
 	sout | "log10:" | log10( 100.0F ) | log10( 100.0D ) | log10( 100.0L );
Index: tests/meta/.expect/archVast.nast.arm64.txt
===================================================================
--- tests/meta/.expect/archVast.nast.arm64.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/meta/.expect/archVast.nast.arm64.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -7,7 +7,7 @@
   char Alternatives are:
 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
-      Variable Expression: FA64: signed int
+      Variable Expression: FA64: double
       ... with resolved type:
-        signed int
+        double
     ... to:
       char
@@ -39,7 +39,7 @@
 
 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
-      Variable Expression: FA64: double
+      Variable Expression: FA64: signed int
       ... with resolved type:
-        double
+        signed int
     ... to:
       char
Index: tests/quasiKeyword.cfa
===================================================================
--- tests/quasiKeyword.cfa	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/quasiKeyword.cfa	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -14,5 +14,5 @@
 #include <exception.hfa>
 
-TRIVIAL_EXCEPTION( E );
+EHM_EXCEPTION( E )();
 
 void catch( int i ) {}
Index: tests/vector_math/.expect/vec4_float.txt
===================================================================
--- tests/vector_math/.expect/vec4_float.txt	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tests/vector_math/.expect/vec4_float.txt	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -6,7 +6,7 @@
 zero-assign:<0.,0.,0.,0.>
 fill-ctor:<1.23,1.23,1.23,1.23>
-?-?:<0.02,0.43,-0.999998,-1e-06.>
-?-=?:<0.02,0.43,-0.999998,-1e-06.>
--?:<-0.02,-0.43,0.999998,1e-06.>
+?-?:<0.02,0.43,-0.999998,-1e-06>
+?-=?:<0.02,0.43,-0.999998,-1e-06>
+-?:<-0.02,-0.43,0.999998,1e-06>
 ?+?:<2.3,2.45,-9.2,-12.5>
 ?+=?:<2.3,2.45,-9.2,-12.5>
Index: tools/gdb/utils-gdb.py
===================================================================
--- tools/gdb/utils-gdb.py	(revision 857a1c6a4dd8ee60c80b5150cef3cc8cc5ff7685)
+++ tools/gdb/utils-gdb.py	(revision c8a02103529bbac3a87ecc27896ddaea00e4e292)
@@ -23,5 +23,5 @@
 gdb.execute('handle SIGUSR1 nostop noprint pass')
 
-CfaTypes = collections.namedtuple('CfaTypes', 'cluster_ptr processor_ptr thread_ptr int_ptr thread_state')
+CfaTypes = collections.namedtuple('CfaTypes', 'cluster_ptr processor_ptr thread_ptr int_ptr thread_state yield_state')
 
 class ThreadInfo:
@@ -52,8 +52,9 @@
 	# GDB types for various structures/types in CFA
 	return CfaTypes(cluster_ptr = gdb.lookup_type('struct cluster').pointer(),
-				  processor_ptr = gdb.lookup_type('struct processor').pointer(),
-					 thread_ptr = gdb.lookup_type('struct $thread').pointer(),
-						int_ptr = gdb.lookup_type('int').pointer(),
-				   thread_state = gdb.lookup_type('enum __Coroutine_State'))
+		processor_ptr = gdb.lookup_type('struct processor').pointer(),
+		thread_ptr = gdb.lookup_type('struct $thread').pointer(),
+		int_ptr = gdb.lookup_type('int').pointer(),
+		thread_state = gdb.lookup_type('enum __Coroutine_State'),
+		yield_state = gdb.lookup_type('enum __Preemption_Reason'))
 
 def get_addr(addr):
@@ -371,5 +372,17 @@
 	def print_thread(self, thread, tid, marked):
 		cfa_t = get_cfa_types()
-		self.print_formatted(marked, tid, thread['self_cor']['name'].string(), str(thread['state'].cast(cfa_t.thread_state)), str(thread))
+		ys = str(thread['preempted'].cast(cfa_t.yield_state))
+		if ys == '_X15__NO_PREEMPTIONKM19__Preemption_Reason_1':
+			state = str(thread['state'].cast(cfa_t.thread_state))
+		elif ys == '_X18__ALARM_PREEMPTIONKM19__Preemption_Reason_1':
+			state = 'preempted'
+		elif ys == '_X19__MANUAL_PREEMPTIONKM19__Preemption_Reason_1':
+			state = 'yield'
+		elif ys == '_X17__POLL_PREEMPTIONKM19__Preemption_Reason_1':
+			state = 'poll'
+		else:
+			print("error: thread {} in undefined preemption state {}".format(thread, ys))
+			state = 'error'
+		self.print_formatted(marked, tid, thread['self_cor']['name'].string(), state, str(thread))
 
 	def print_threads_by_cluster(self, cluster, print_system = False):
@@ -480,17 +493,24 @@
 		context = thread['context']
 
+
+
+		# must be at frame 0 to set pc register
+		gdb.execute('select-frame 0')
+		if gdb.selected_frame().architecture().name() != 'i386:x86-64':
+			print('gdb debugging only supported for i386:x86-64 for now')
+			return
+
+		# gdb seems to handle things much better if we pretend we just entered the context switch
+		# pretend the pc is __cfactx_switch and adjust the sp, base pointer doesn't need to change
 		# lookup for sp,fp and uSwitch
-		xsp = context['SP'] + 48
+		xsp = context['SP'] + 40 # 40 = 5 64bit registers : %r15, %r14, %r13, %r12, %rbx WARNING: x64 specific
 		xfp = context['FP']
 
 		# convert string so we can strip out the address
 		try:
-			xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address + 28)
+			xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address)
 		except:
 			print("here")
 			return
-
-		# must be at frame 0 to set pc register
-		gdb.execute('select-frame 0')
 
 		# push sp, fp, pc into a global stack
@@ -503,5 +523,6 @@
 
 		# update registers for new task
-		print('switching to ')
+		# print('switching to {} ({}) : [{}, {}, {}]'.format(thread['self_cor']['name'].string(), str(thread), str(xsp), str(xfp), str(xpc)))
+		print('switching to thread {} ({})'.format(str(thread), thread['self_cor']['name'].string()))
 		gdb.execute('set $rsp={}'.format(xsp))
 		gdb.execute('set $rbp={}'.format(xfp))
@@ -552,5 +573,4 @@
 
 		argv = parse(arg)
-		print(argv)
 		if argv[0].isdigit():
 			cname = " ".join(argv[1:]) if len(argv) > 1 else None
