diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 6ca073744511c0052ed43be9993a215017376936..862b6b5ebc27046eca696f825ad116d074c4e9ed 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -31,6 +31,7 @@
 #include "../llmath/llmath.h"
 #include "llformat.h"
 #include "llsdserialize.h"
+#include "stringize.h"
 
 #ifndef LL_RELEASE_FOR_DOWNLOAD
 #define NAME_UNNAMED_NAMESPACE
@@ -50,6 +51,24 @@ namespace
 using namespace LLSDUnnamedNamespace;
 #endif
 
+
+// Normally undefined
+#ifdef LLSD_DEBUG_INFO
+
+// statics
+S32	LLSD::sLLSDAllocationCount = 0;
+S32 LLSD::sLLSDNetObjects = 0;
+
+#define	ALLOC_LLSD_OBJECT			{ sLLSDNetObjects++;	sLLSDAllocationCount++;		}
+#define	FREE_LLSD_OBJECT			{ sLLSDNetObjects--;								}
+
+#else
+
+#define	ALLOC_LLSD_OBJECT
+#define	FREE_LLSD_OBJECT
+
+#endif
+
 class LLSD::Impl
 	/**< This class is the abstract base class of the implementation of LLSD
 		 It provides the reference counting implementation, and the default
@@ -58,13 +77,10 @@ class LLSD::Impl
 		
 	*/
 {
-private:
-	U32 mUseCount;
-	
 protected:
 	Impl();
 
-	enum StaticAllocationMarker { STATIC };
+	enum StaticAllocationMarker { STATIC_USAGE_COUNT = 0xFFFFFFFF };
 	Impl(StaticAllocationMarker);
 		///< This constructor is used for static objects and causes the
 		//   suppresses adjusting the debugging counters when they are
@@ -72,7 +88,9 @@ class LLSD::Impl
 		
 	virtual ~Impl();
 	
-	bool shared() const							{ return mUseCount > 1; }
+	bool shared() const							{ return (mUseCount > 1) && (mUseCount != STATIC_USAGE_COUNT); }
+	
+	U32 mUseCount;
 	
 public:
 	static void reset(Impl*& var, Impl* impl);
@@ -128,6 +146,9 @@ class LLSD::Impl
 	virtual LLSD::array_const_iterator beginArray() const { return endArray(); }
 	virtual LLSD::array_const_iterator endArray() const { static const std::vector<LLSD> empty; return empty.end(); }
 
+	virtual void dumpStats() const;
+	virtual void calcStats(S32 type_counts[], S32 share_counts[]) const;
+
 	static const LLSD& undef();
 	
 	static U32 sAllocationCount;
@@ -360,6 +381,9 @@ namespace
 		LLSD::map_iterator endMap() { return mData.end(); }
 		virtual LLSD::map_const_iterator beginMap() const { return mData.begin(); }
 		virtual LLSD::map_const_iterator endMap() const { return mData.end(); }
+
+		virtual void dumpStats() const;
+		virtual void calcStats(S32 type_counts[], S32 share_counts[]) const;
 	};
 	
 	ImplMap& ImplMap::makeMap(LLSD::Impl*& var)
@@ -414,6 +438,36 @@ namespace
 		return i->second;
 	}
 
+	void ImplMap::dumpStats() const
+	{
+		std::cout << "Map size: " << mData.size() << std::endl;
+
+		#ifdef LLSD_DEBUG_INFO
+		std::cout << "LLSD Net Objects: " << LLSD::sLLSDNetObjects << std::endl;
+		std::cout << "LLSD allocations: " << LLSD::sLLSDAllocationCount << std::endl;
+		#endif
+
+		std::cout << "LLSD::Impl Net Objects: " << sOutstandingCount << std::endl;
+		std::cout << "LLSD::Impl allocations: " << sAllocationCount << std::endl;
+
+		Impl::dumpStats();
+	}
+
+	void ImplMap::calcStats(S32 type_counts[], S32 share_counts[]) const
+	{
+		LLSD::map_const_iterator iter = beginMap();
+		while (iter != endMap())
+		{
+			//std::cout << "  " << (*iter).first << ": " << (*iter).second << std::endl;
+			(*iter).second.calcStats(type_counts, share_counts);
+			iter++;
+		}
+
+		// Add in the values for this map
+		Impl::calcStats(type_counts, share_counts);
+	}
+
+
 	class ImplArray : public LLSD::Impl
 	{
 	private:
@@ -449,6 +503,8 @@ namespace
 		LLSD::array_iterator endArray() { return mData.end(); }
 		virtual LLSD::array_const_iterator beginArray() const { return mData.begin(); }
 		virtual LLSD::array_const_iterator endArray() const { return mData.end(); }
+
+		virtual void calcStats(S32 type_counts[], S32 share_counts[]) const;
 	};
 
 	ImplArray& ImplArray::makeArray(Impl*& var)
@@ -490,12 +546,13 @@ namespace
 	
 	void ImplArray::insert(LLSD::Integer i, const LLSD& v)
 	{
-		if (i < 0) {
+		if (i < 0) 
+		{
 			return;
 		}
 		DataVector::size_type index = i;
 		
-		if (index >= mData.size())
+		if (index >= mData.size())	// tbd - sanity check limit for index ?
 		{
 			mData.resize(index + 1);
 		}
@@ -543,6 +600,19 @@ namespace
 		
 		return mData[index];
 	}
+
+	void ImplArray::calcStats(S32 type_counts[], S32 share_counts[]) const
+	{
+		LLSD::array_const_iterator iter = beginArray();
+		while (iter != endArray())
+		{	// Add values for all items held in the array
+			(*iter).calcStats(type_counts, share_counts);
+			iter++;
+		}
+
+		// Add in the values for this array
+		Impl::calcStats(type_counts, share_counts);
+	}
 }
 
 LLSD::Impl::Impl()
@@ -564,8 +634,11 @@ LLSD::Impl::~Impl()
 
 void LLSD::Impl::reset(Impl*& var, Impl* impl)
 {
-	if (impl) ++impl->mUseCount;
-	if (var  &&  --var->mUseCount == 0)
+	if (impl && impl->mUseCount != STATIC_USAGE_COUNT) 
+	{
+		++impl->mUseCount;
+	}
+	if (var  &&  var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0)
 	{
 		delete var;
 	}
@@ -574,13 +647,13 @@ void LLSD::Impl::reset(Impl*& var, Impl* impl)
 
 LLSD::Impl& LLSD::Impl::safe(Impl* impl)
 {
-	static Impl theUndefined(STATIC);
+	static Impl theUndefined(STATIC_USAGE_COUNT);
 	return impl ? *impl : theUndefined;
 }
 
 const LLSD::Impl& LLSD::Impl::safe(const Impl* impl)
 {
-	static Impl theUndefined(STATIC);
+	static Impl theUndefined(STATIC_USAGE_COUNT);
 	return impl ? *impl : theUndefined;
 }
 
@@ -656,6 +729,39 @@ const LLSD& LLSD::Impl::undef()
 	return immutableUndefined;
 }
 
+void LLSD::Impl::dumpStats() const
+{
+	S32 type_counts[LLSD::TypeLLSDNumTypes + 1];
+	memset(&type_counts, 0, LLSD::TypeLLSDNumTypes * sizeof(S32));
+
+	S32 share_counts[LLSD::TypeLLSDNumTypes + 1];
+	memset(&share_counts, 0, LLSD::TypeLLSDNumTypes * sizeof(S32));
+
+	// Add info from all the values this object has
+	calcStats(type_counts, share_counts);
+
+	S32 type_index = LLSD::TypeLLSDTypeBegin;
+	while (type_index != LLSD::TypeLLSDTypeEnd)
+	{
+		std::cout << LLSD::typeString((LLSD::Type)type_index) << " type "
+			<< type_counts[type_index] << " objects, "
+			<< share_counts[type_index] << " shared"
+			<< std::endl;
+		type_index++;
+	}
+}
+
+
+void LLSD::Impl::calcStats(S32 type_counts[], S32 share_counts[]) const
+{ 
+	type_counts[(S32) type()]++;	
+	if (shared())
+	{
+		share_counts[(S32) type()]++;
+	}
+}
+
+
 U32 LLSD::Impl::sAllocationCount = 0;
 U32 LLSD::Impl::sOutstandingCount = 0;
 
@@ -681,10 +787,10 @@ namespace
 }
 
 
-LLSD::LLSD()							: impl(0)	{ }
-LLSD::~LLSD()							{ Impl::reset(impl, 0); }
+LLSD::LLSD() : impl(0)					{ ALLOC_LLSD_OBJECT; }
+LLSD::~LLSD()							{ FREE_LLSD_OBJECT; Impl::reset(impl, 0); }
 
-LLSD::LLSD(const LLSD& other)			: impl(0) { assign(other); }
+LLSD::LLSD(const LLSD& other) : impl(0) { ALLOC_LLSD_OBJECT;  assign(other); }
 void LLSD::assign(const LLSD& other)	{ Impl::assign(impl, other.impl); }
 
 
@@ -693,17 +799,17 @@ void LLSD::clear()						{ Impl::assignUndefined(impl); }
 LLSD::Type LLSD::type() const			{ return safe(impl).type(); }
 
 // Scaler Constructors
-LLSD::LLSD(Boolean v)					: impl(0) { assign(v); }
-LLSD::LLSD(Integer v)					: impl(0) { assign(v); }
-LLSD::LLSD(Real v)						: impl(0) { assign(v); }
-LLSD::LLSD(const UUID& v)				: impl(0) { assign(v); }
-LLSD::LLSD(const String& v)				: impl(0) { assign(v); }
-LLSD::LLSD(const Date& v)				: impl(0) { assign(v); }
-LLSD::LLSD(const URI& v)				: impl(0) { assign(v); }
-LLSD::LLSD(const Binary& v)				: impl(0) { assign(v); }
+LLSD::LLSD(Boolean v) : impl(0)			{ ALLOC_LLSD_OBJECT;	assign(v); }
+LLSD::LLSD(Integer v) : impl(0)			{ ALLOC_LLSD_OBJECT;	assign(v); }
+LLSD::LLSD(Real v) : impl(0)			{ ALLOC_LLSD_OBJECT;	assign(v); }
+LLSD::LLSD(const UUID& v) : impl(0)		{ ALLOC_LLSD_OBJECT;	assign(v); }
+LLSD::LLSD(const String& v) : impl(0)	{ ALLOC_LLSD_OBJECT;	assign(v); }
+LLSD::LLSD(const Date& v) : impl(0)		{ ALLOC_LLSD_OBJECT;	assign(v); }
+LLSD::LLSD(const URI& v) : impl(0)		{ ALLOC_LLSD_OBJECT;	assign(v); }
+LLSD::LLSD(const Binary& v) : impl(0)	{ ALLOC_LLSD_OBJECT;	assign(v); }
 
 // Convenience Constructors
-LLSD::LLSD(F32 v)						: impl(0) { assign((Real)v); }
+LLSD::LLSD(F32 v) : impl(0)				{ ALLOC_LLSD_OBJECT;	assign((Real)v); }
 
 // Scalar Assignment
 void LLSD::assign(Boolean v)			{ safe(impl).assign(impl, v); }
@@ -726,7 +832,7 @@ LLSD::URI		LLSD::asURI() const		{ return safe(impl).asURI(); }
 LLSD::Binary	LLSD::asBinary() const	{ return safe(impl).asBinary(); }
 
 // const char * helpers
-LLSD::LLSD(const char* v)				: impl(0) { assign(v); }
+LLSD::LLSD(const char* v) : impl(0)		{ ALLOC_LLSD_OBJECT;	assign(v); }
 void LLSD::assign(const char* v)
 {
 	if(v) assign(std::string(v));
@@ -801,15 +907,9 @@ static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat)
 	{
 		std::ostringstream out;
 		if (useXMLFormat)
-		{
-			LLSDXMLStreamer xml_streamer(llsd);
-			out << xml_streamer;
-		}
+			out << LLSDXMLStreamer(llsd);
 		else
-		{
-			LLSDNotationStreamer notation_streamer(llsd);
-			out << notation_streamer;
-		}
+			out << LLSDNotationStreamer(llsd);
 		out_string = out.str();
 	}
 	int len = out_string.length();
@@ -840,3 +940,33 @@ LLSD::array_iterator		LLSD::beginArray()		{ return makeArray(impl).beginArray();
 LLSD::array_iterator		LLSD::endArray()		{ return makeArray(impl).endArray(); }
 LLSD::array_const_iterator	LLSD::beginArray() const{ return safe(impl).beginArray(); }
 LLSD::array_const_iterator	LLSD::endArray() const	{ return safe(impl).endArray(); }
+
+
+// Diagnostic dump of contents in an LLSD object
+void LLSD::dumpStats()	const						{ safe(impl).dumpStats();	}
+void LLSD::calcStats(S32 type_counts[], S32 share_counts[]) const
+													{ safe(impl).calcStats(type_counts, share_counts);	}
+
+// static
+std::string		LLSD::typeString(Type type)
+{
+	static const char * sTypeNameArray[] = {
+		"Undefined",
+		"Boolean",
+		"Integer",
+		"Real",
+		"String",
+		"UUID",
+		"Date",
+		"URI",
+		"Binary",
+		"Map",
+		"Array"
+	};
+
+	if (0 <= type < (sizeof(sTypeNameArray)/sizeof(sTypeNameArray[0])))
+	{
+		return sTypeNameArray[type];
+	}
+	return STRINGIZE("** invalid type value " << type);
+}
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index 90d0f978730d61f165f2e3d429f972e71211a7b4..1ffa1d279b6baa5a75e26ff3fb5b1274fb56a7b3 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -80,9 +80,73 @@
 	
 	An array is a sequence of zero or more LLSD values.
 	
+	Thread Safety
+
+	In general, these LLSD classes offer *less* safety than STL container
+	classes.  Implementations prior to this one were unsafe even when
+	completely unrelated LLSD trees were in two threads due to reference
+	sharing of special 'undefined' values that participated in the reference
+	counting mechanism.
+
+	The dereference-before-refcount and aggressive tree sharing also make
+	it impractical to share an LLSD across threads.  A strategy of passing
+	ownership or a copy to another thread is still difficult due to a lack
+	of a cloning interface but it can be done with some care.
+
+	One way of transferring ownership is as follows:
+
+		void method(const LLSD input) {
+		...
+		LLSD * xfer_tree = new LLSD();
+		{
+			// Top-level values
+			(* xfer_tree)['label'] = "Some text";
+			(* xfer_tree)['mode'] = APP_MODE_CONSTANT;
+
+			// There will be a second-level
+			LLSD subtree(LLSD::emptyMap());
+			(* xfer_tree)['subtree'] = subtree;
+
+			// Do *not* copy from LLSD objects via LLSD
+			// intermediaries.  Only use plain-old-data
+			// types as intermediaries to prevent reference
+			// sharing.
+			subtree['value1'] = input['value1'].asInteger();
+			subtree['value2'] = input['value2'].asString();
+
+			// Close scope and drop 'subtree's reference.
+			// Only xfer_tree has a reference to the second
+			// level data.
+		}
+		...
+		// Transfer the LLSD pointer to another thread.  Ownership
+		// transfers, this thread no longer has a reference to any
+		// part of the xfer_tree and there's nothing to free or
+		// release here.  Receiving thread does need to delete the
+		// pointer when it is done with the LLSD.  Transfer
+		// mechanism must perform correct data ordering operations
+		// as dictated by architecture.
+		other_thread.sendMessageAndPointer("Take This", xfer_tree);
+		xfer_tree = NULL;
+
+
+	Avoid this pattern which provides half of a race condition:
+	
+		void method(const LLSD input) {
+		...
+		LLSD xfer_tree(LLSD::emptyMap());
+		xfer_tree['label'] = "Some text";
+		xfer_tree['mode'] = APP_MODE_CONSTANT;
+		...
+		other_thread.sendMessageAndPointer("Take This", xfer_tree);
+
+	
 	@nosubgrouping
 */
 
+// Normally undefined, used for diagnostics
+//#define LLSD_DEBUG_INFO	1
+
 class LL_COMMON_API LLSD
 {
 public:
@@ -266,7 +330,7 @@ class LL_COMMON_API LLSD
 	/** @name Type Testing */
 	//@{
 		enum Type {
-			TypeUndefined,
+			TypeUndefined = 0,
 			TypeBoolean,
 			TypeInteger,
 			TypeReal,
@@ -276,7 +340,10 @@ class LL_COMMON_API LLSD
 			TypeURI,
 			TypeBinary,
 			TypeMap,
-			TypeArray
+			TypeArray,
+			TypeLLSDTypeEnd,
+			TypeLLSDTypeBegin = TypeUndefined,
+			TypeLLSDNumTypes = (TypeLLSDTypeEnd - TypeLLSDTypeBegin)
 		};
 		
 		Type type() const;
@@ -338,6 +405,17 @@ class LL_COMMON_API LLSD
 		/// Returns Notation version of llsd -- only to be called from debugger
 		static const char *dump(const LLSD &llsd);
 	//@}
+
+public:
+	void			dumpStats() const;					// Output information on object and usage
+	void			calcStats(S32 type_counts[], S32 share_counts[]) const;		// Calculate the number of LLSD objects used by this value
+
+	static std::string		typeString(Type type);		// Return human-readable type as a string
+
+#ifdef LLSD_DEBUG_INFO
+	static S32		sLLSDAllocationCount;		// Number of LLSD objects ever created
+	static S32		sLLSDNetObjects;			// Number of LLSD objects that exist
+#endif
 };
 
 struct llsd_select_bool : public std::unary_function<LLSD, LLSD::Boolean>
diff --git a/indra/llmessage/llsdmessagereader.cpp b/indra/llmessage/llsdmessagereader.cpp
index 304a692cdfeaea700fe2a9cbf855c3c31ca1d2d8..3ab62a8c5796f972493ddd89247cd43a8b6ea7c7 100644
--- a/indra/llmessage/llsdmessagereader.cpp
+++ b/indra/llmessage/llsdmessagereader.cpp
@@ -291,6 +291,7 @@ S32 getElementSize(const LLSD& llsd)
 	case LLSD::TypeMap:
 	case LLSD::TypeArray:
 	case LLSD::TypeUndefined:
+	default:                        // TypeLLSDTypeEnd, TypeLLSDNumTypes, etc.
 		return 0;
 	}
 	return 0;
diff --git a/indra/test/lltut.cpp b/indra/test/lltut.cpp
index da7031b52a828e2bd2932ab5e14b4d4a38dae977..c43a8f0c7d7dba03e7ebc58cafc652b82ea6cc5c 100644
--- a/indra/test/lltut.cpp
+++ b/indra/test/lltut.cpp
@@ -34,6 +34,7 @@
 #include "llformat.h"
 #include "llsd.h"
 #include "lluri.h"
+#include "stringize.h"
 
 namespace tut
 {
@@ -144,6 +145,10 @@ namespace tut
 				}
 				return;
 			}
+			default:
+				// should never get here, but compiler produces warning if we
+				// don't cover this case, and at Linden warnings are fatal.
+				throw failure(STRINGIZE("invalid type field " << actual.type()));
 		}
 	}