Index: src/CodeTools/DeclStats.cc
===================================================================
--- src/CodeTools/DeclStats.cc	(revision d0ffed1543e8d376c606a33965ddc98eef7ec641)
+++ src/CodeTools/DeclStats.cc	(revision f37147bb7b7c99554bd122576a0404e84685a68b)
@@ -63,4 +63,7 @@
 			std::map<unsigned, unsigned> p_poly;   ///< Count of decls with each percentage of polymorphic elements
 			VectorMap<unsigned> n_types;           ///< Count of decls with each number of distinct types in the pack
+			/// Count of decls with each percentage of new types in lists.
+			/// Types used in the parameter list that recur in the return list are not considered to be new.
+			std::map<unsigned, unsigned> p_new;
 
 			ArgPackStats& operator+= (const ArgPackStats& o) {
@@ -71,4 +74,5 @@
 				sum(p_poly, o.p_poly);
 				sum(n_types, o.n_types);
+				sum(p_new, o.p_new);
 				
 				return *this;
@@ -86,4 +90,8 @@
 			/// Count of uses of each non-basic type
 			std::unordered_map<std::string, unsigned> compound_type_names;
+			/// Count of decls using each basic type
+			std::unordered_map<std::string, unsigned> basic_type_decls;
+			/// Count of decls using each compound type
+			std::unordered_map<std::string, unsigned> compound_type_decls;
 			/// Stats for the parameter list
 			ArgPackStats params;
@@ -98,5 +106,5 @@
 			ArgPackStats assn_returns;
 			
-			Stats() : n_decls(0), n_type_params(), by_name(), basic_type_names(), compound_type_names(), params(), returns(), n_assns(), assn_params(), assn_returns() {}
+			Stats() : n_decls(0), n_type_params(), by_name(), basic_type_names(), compound_type_names(), basic_type_decls(), compound_type_decls(), params(), returns(), n_assns(), assn_params(), assn_returns() {}
 
 		public:
@@ -107,4 +115,6 @@
 				sum( basic_type_names, o.basic_type_names );
 				sum( compound_type_names, o.compound_type_names );
+				sum( basic_type_decls, o.basic_type_decls );
+				sum( compound_type_decls, o.compound_type_decls );
 				sum( params, o.params );
 				sum( returns, o.returns );
@@ -120,11 +130,14 @@
 		std::unordered_set<std::string> seen_names;  ///< Stores manglenames already seen to avoid double-counting
 		Stats total;
+		/// Count of expressions with (depth, fanout)
+		std::map<std::pair<unsigned, unsigned>, unsigned> exprs_by_fanout_at_depth;
 
 		/// Update arg pack stats based on a declaration list
-		void analyze( Stats& stats, ArgPackStats& pstats, std::list<DeclarationWithType*>& decls ) {
+		void analyze( Stats& stats, std::unordered_set<std::string>& seen, ArgPackStats& pstats, std::list<DeclarationWithType*>& decls ) {
 			std::unordered_set<std::string> types;
-			unsigned n = 0;
-			unsigned n_basic = 0;
-			unsigned n_poly = 0;
+			unsigned n = 0;        ///< number of args/returns
+			unsigned n_basic = 0;  ///< number of basic types
+			unsigned n_poly = 0;   ///< number of polymorphic types
+			unsigned n_new = 0;    ///< number of new types
 			for ( auto decl : decls ) {
 				Type* dt = decl->get_type();
@@ -135,12 +148,20 @@
 				dt->print( ss );
 				types.insert( ss.str() );
+				bool this_new = seen.insert( ss.str() ).second;
+				if ( this_new ) { ++n_new; }
 
 				if ( dynamic_cast<BasicType*>( dt ) ) {
 					++n_basic;
 					++stats.basic_type_names[ ss.str() ];
+					if ( this_new ) {
+						++stats.basic_type_decls[ ss.str() ];
+					}
 				} else if ( GenPoly::hasPolyBase( dt ) ) {
 					++n_poly;
 				} else {
 					++stats.compound_type_names[ ss.str() ];
+					if ( this_new ) {
+						++stats.compound_type_decls[ ss.str() ];
+					}
 				}
 			}
@@ -151,4 +172,5 @@
 				++pstats.p_basic[ n_basic*100/n ];
 				++pstats.p_poly[ n_poly*100/n ];
+				++pstats.p_new[ n_new*100/n ];
 			}
 			++pstats.n_types.at( types.size() );
@@ -156,6 +178,18 @@
 		
 		void analyzeFunc( FunctionType* fnTy, Stats& stats, ArgPackStats& params, ArgPackStats& returns ) {
-			analyze( stats, params, fnTy->get_parameters() );
-			analyze( stats, returns, fnTy->get_returnVals() );
+			std::unordered_set<std::string> seen;
+			analyze( stats, seen, params, fnTy->get_parameters() );
+			analyze( stats, seen, returns, fnTy->get_returnVals() );
+		}
+
+		void analyzeExpr( UntypedExpr *expr, unsigned depth ) {
+			auto& args = expr->get_args();
+			unsigned fanout = args.size();
+			++exprs_by_fanout_at_depth[ std::make_pair(depth, fanout) ];
+			for ( Expression* arg : args ) {
+				if ( UntypedExpr *uearg = dynamic_cast<UntypedExpr*>(arg) ) {
+					analyzeExpr( uearg, depth+1 );
+				}
+			}
 		}
 
@@ -196,4 +230,8 @@
 		}
 
+		virtual void visit( UntypedExpr *expr ) {
+			analyzeExpr( expr, 0 );
+		}
+
 	private:
 		template<typename F>
@@ -275,4 +313,14 @@
 			printAllMap("%_poly_" + name, [&extract](const Stats& stats) { return extract(stats).p_poly; });
 			printAllMap("n_distinct_types_" + name, [&extract](const Stats& stats) { return extract(stats).n_types; });
+			printAllMap("%_new_types_in_" + name, [&extract](const Stats& stats) { return extract(stats).p_new; });
+		}
+
+		void printPairMap( const std::string& name, 
+		                   const std::map<std::pair<unsigned, unsigned>, unsigned>& map ) {
+			for ( const auto& entry : map ) {
+				const auto& key = entry.first;
+				std::cout << "\"" << name << "\"," << key.first << "," << key.second << "," 
+				          << entry.second << std::endl;
+			}
 		}
 		
@@ -291,6 +339,8 @@
 			printAll("basic_type_names", [](const Stats& stats) { return stats.basic_type_names.size(); });
 			printAllSparseHisto("basic_type_uses", [](const Stats& stats) { return stats.basic_type_names; });
+			printAllSparseHisto("decls_using_basic_type", [](const Stats& stats) { return stats.basic_type_decls; });
 			printAll("compound_type_names", [](const Stats& stats) { return stats.compound_type_names.size(); });
 			printAllSparseHisto("compound_type_uses", [](const Stats& stats) { return stats.compound_type_names; });
+			printAllSparseHisto("decls_using_compound_type", [](const Stats& stats) { return stats.compound_type_decls; });
 			printAllPack("params", [](const Stats& stats) { return stats.params; });
 			printAllPack("returns", [](const Stats& stats) { return stats.returns; });
@@ -298,4 +348,7 @@
 			printAllPack("assn_params", [](const Stats& stats) { return stats.assn_params; });
 			printAllPack("assn_returns", [](const Stats& stats) { return stats.assn_returns; });
+			std::cout << std::endl;
+
+			printPairMap("exprs_by_depth+fanout", exprs_by_fanout_at_depth);
 		}
 	};
Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision d0ffed1543e8d376c606a33965ddc98eef7ec641)
+++ src/Parser/ParseNode.h	(revision f37147bb7b7c99554bd122576a0404e84685a68b)
@@ -109,5 +109,5 @@
 	ExpressionNode( const ExpressionNode &other );
 	virtual ~ExpressionNode() {}
-	virtual ExpressionNode * clone() const { return expr ? new ExpressionNode( expr->clone() ) : nullptr; }
+	virtual ExpressionNode * clone() const override { return expr ? new ExpressionNode( expr->clone() ) : nullptr; }
 
 	bool get_extension() const { return extension; }
@@ -259,5 +259,5 @@
 	DeclarationNode();
 	~DeclarationNode();
-	DeclarationNode * clone() const;
+	DeclarationNode * clone() const override;
 
 	DeclarationNode * addQualifiers( DeclarationNode * );
Index: src/libcfa/concurrency/invoke.h
===================================================================
--- src/libcfa/concurrency/invoke.h	(revision d0ffed1543e8d376c606a33965ddc98eef7ec641)
+++ src/libcfa/concurrency/invoke.h	(revision f37147bb7b7c99554bd122576a0404e84685a68b)
@@ -60,10 +60,10 @@
 
       struct coStack_t {
-            unsigned int size;		// size of stack
-            void *storage;			// pointer to stack
-            void *limit;			// stack grows towards stack limit
-            void *base;				// base of stack
-            void *context;			// address of cfa_context_t
-            void *top;				// address of top of storage
+            unsigned int size;		      // size of stack
+            void *storage;			      // pointer to stack
+            void *limit;			      // stack grows towards stack limit
+            void *base;				      // base of stack
+            void *context;			      // address of cfa_context_t
+            void *top;				      // address of top of storage
             bool userStack;	
       };
@@ -73,15 +73,15 @@
       struct coroutine {
             struct coStack_t stack;
-            const char *name;			// textual name for coroutine/task, initialized by uC++ generated code
-            int errno_;				// copy of global UNIX variable errno
-            enum coroutine_state state;	// current execution status for coroutine
-            struct coroutine *starter;	// first coroutine to resume this one
-            struct coroutine *last;		// last coroutine to resume this one
+            const char *name;			      // textual name for coroutine/task, initialized by uC++ generated code
+            int errno_;				      // copy of global UNIX variable errno
+            enum coroutine_state state;	      // current execution status for coroutine
+            struct coroutine *starter;	      // first coroutine to resume this one
+            struct coroutine *last;		      // last coroutine to resume this one
       };
 
       struct thread {
-            struct coroutine c;           // coroutine body used to store context
-            struct signal_once terminated;// indicate if execuation state is not halted
-            struct thread * next;         // instrusive link field for threads
+            struct coroutine c;                 // coroutine body used to store context
+            struct signal_once terminated;      // indicate if execuation state is not halted
+            struct thread * next;               // instrusive link field for threads
       };
 
Index: src/libcfa/concurrency/monitor
===================================================================
--- src/libcfa/concurrency/monitor	(revision d0ffed1543e8d376c606a33965ddc98eef7ec641)
+++ src/libcfa/concurrency/monitor	(revision f37147bb7b7c99554bd122576a0404e84685a68b)
@@ -21,23 +21,29 @@
 #include "invoke.h"
 
-struct monitor {
+struct __monitor_t {
 	spinlock lock;
-	thread * holder;
+	thread * owner;
 	simple_thread_list entry_queue;
+	unsigned int recursion;
 };
 
-void enter(monitor *);
-void leave(monitor *);
+static inline void ?{}(__monitor_t * this) {
+	this->owner = 0;
+	this->recursion = 0;
+}
 
-struct monitor_guard {
-	monitor * m;
+void enter(__monitor_t *);
+void leave(__monitor_t *);
+
+struct monitor_guard_t {
+	__monitor_t * m;
 };
 
-static inline void ?{}( monitor_guard * this, monitor * m ) {
+static inline void ?{}( monitor_guard_t * this, __monitor_t * m ) {
 	this->m = m;
 	enter( this->m );
 }
 
-static inline void ^?{}( monitor_guard * this ) {
+static inline void ^?{}( monitor_guard_t * this ) {
 	leave( this->m );
 }
Index: src/libcfa/concurrency/monitor.c
===================================================================
--- src/libcfa/concurrency/monitor.c	(revision d0ffed1543e8d376c606a33965ddc98eef7ec641)
+++ src/libcfa/concurrency/monitor.c	(revision f37147bb7b7c99554bd122576a0404e84685a68b)
@@ -6,5 +6,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// monitor.c --
+// __monitor_t.c --
 //
 // Author           : Thierry Delisle
@@ -19,15 +19,25 @@
 #include "kernel_private.h"
 
-void enter(monitor * this) {
+void enter(__monitor_t * this) {
 	lock( &this->lock );
 	thread * thrd = this_thread();
 
-	if( this->holder ) {
+	if( !this->owner ) {
+		//No one has the monitor, just take it
+		this->owner = thrd;
+		this->recursion = 1;
+	}
+	else if( this->owner == thrd) {
+		//We already have the monitor, just not how many times we took it
+		assert( this->recursion > 0 );
+		this->recursion += 1;
+	}
+	else {
+		//Some one else has the monitor, wait in line for it
 		append( &this->entry_queue, thrd );
 		ScheduleInternal( &this->lock );
-		return;
-	}
-	else {
-		this->holder = thrd;
+
+		//ScheduleInternal will unlock spinlock, no need to unlock ourselves
+		return; 
 	}
 
@@ -35,14 +45,28 @@
 }
 
-void leave(monitor * this) {
+void leave(__monitor_t * this) {
 	lock( &this->lock );
 
 	thread * thrd = this_thread();
-	assert( thrd == this->holder );
+	assert( thrd == this->owner );
 
-	this->holder = pop_head( &this->entry_queue );
+	//Leaving a recursion level, decrement the counter
+	this->recursion -= 1;
+
+	//If we left the last level of recursion it means we are changing who owns the monitor
+	thread * new_owner = 0;
+	if( this->recursion == 0) {
+		//Get the next thread in the list
+		new_owner = this->owner = pop_head( &this->entry_queue );
+
+		//We are passing the monitor to someone else, which means recursion level is not 0
+		this->recursion = new_owner ? 1 : 0;
+	}	
 
 	unlock( &this->lock );
 
-	if( this->holder ) ScheduleThread( this->holder );
+	//If we have a new owner, we need to wake-up the thread
+	if( new_owner ) {
+		ScheduleThread( new_owner );
+	}
 }
Index: src/prelude/prelude.cf
===================================================================
--- src/prelude/prelude.cf	(revision d0ffed1543e8d376c606a33965ddc98eef7ec641)
+++ src/prelude/prelude.cf	(revision f37147bb7b7c99554bd122576a0404e84685a68b)
@@ -131,4 +131,7 @@
 		!?( float _Complex ),		!?( double _Complex ),		!?( long double _Complex );
 
+forall ( dtype DT ) int !?(                DT * );
+forall ( dtype DT ) int !?( const          DT * );
+forall ( dtype DT ) int !?(       volatile DT * );
 forall ( dtype DT ) int !?( const volatile DT * );
 forall ( ftype FT ) int !?( FT * );
@@ -235,7 +238,22 @@
 	   ?>?( long double, long double ),				?>=?( long double, long double );
 
+forall( dtype DT ) signed int ?<?(                 DT *,                DT * );
+forall( dtype DT ) signed int ?<?(  const          DT *, const          DT * );
+forall( dtype DT ) signed int ?<?(        volatile DT *,       volatile DT * );
 forall( dtype DT ) signed int ?<?(  const volatile DT *, const volatile DT * );
+
+forall( dtype DT ) signed int ?>?(                 DT *,                DT * );
+forall( dtype DT ) signed int ?>?(  const          DT *, const          DT * );
+forall( dtype DT ) signed int ?>?(        volatile DT *,       volatile DT * );
 forall( dtype DT ) signed int ?>?(  const volatile DT *, const volatile DT * );
+
+forall( dtype DT ) signed int ?<=?(                 DT *,                DT * );
+forall( dtype DT ) signed int ?<=?(  const          DT *, const          DT * );
+forall( dtype DT ) signed int ?<=?(        volatile DT *,       volatile DT * );
 forall( dtype DT ) signed int ?<=?( const volatile DT *, const volatile DT * );
+
+forall( dtype DT ) signed int ?>=?(                 DT *,                DT * );
+forall( dtype DT ) signed int ?>=?(  const          DT *, const          DT * );
+forall( dtype DT ) signed int ?>=?(        volatile DT *,       volatile DT * );
 forall( dtype DT ) signed int ?>=?( const volatile DT *, const volatile DT * );
 
Index: src/tests/avltree/avl_test.c
===================================================================
--- src/tests/avltree/avl_test.c	(revision d0ffed1543e8d376c606a33965ddc98eef7ec641)
+++ src/tests/avltree/avl_test.c	(revision f37147bb7b7c99554bd122576a0404e84685a68b)
@@ -36,15 +36,16 @@
 
   // char* -> char*
-  int ?<?(char *a, char *b) {
-    return strcmp(a,b) < 0;
+  struct c_str { char *str; };  // wraps a C string
+  int ?<?(c_str a, c_str b) {
+    return strcmp(a.str,b.str) < 0;
   }
-  tree(char *, char *) * ssmap = create("queso", "cheese");
-  insert(&ssmap, "foo", "bar");
-  insert(&ssmap, "hello", "world");
+  tree(c_str, char *) * ssmap = create((c_str){"queso"}, "cheese");
+  insert(&ssmap, (c_str){"foo"}, "bar");
+  insert(&ssmap, (c_str){"hello"}, "world");
   assert( height(ssmap) == 2 );
 
-  printf("%s %s %s\n", *find(ssmap, "hello"), *find(ssmap, "foo"), *find(ssmap, "queso"));
+  printf("%s %s %s\n", *find(ssmap, (c_str){"hello"}), *find(ssmap, (c_str){"foo"}), *find(ssmap, (c_str){"queso"}));
 
-  remove(&ssmap, "foo");
+  remove(&ssmap, (c_str){"foo"});
   delete(ssmap);
 }
Index: src/tests/monitor.c
===================================================================
--- src/tests/monitor.c	(revision d0ffed1543e8d376c606a33965ddc98eef7ec641)
+++ src/tests/monitor.c	(revision f37147bb7b7c99554bd122576a0404e84685a68b)
@@ -6,5 +6,5 @@
 struct global_t {
 	int value;
-	monitor m;
+	__monitor_t m;
 };
 
@@ -16,6 +16,12 @@
 
 void increment( /*mutex*/ global_t * this ) {
-	monitor_guard g = { &this->m };
-	this->value += 1;
+	monitor_guard_t g1 = { &this->m };
+	{
+		monitor_guard_t g2 = { &this->m };
+		{
+			monitor_guard_t g3 = { &this->m };
+			this->value += 1;
+		}
+	}
 }
 
