diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index d3fd5813a03ab6b04f2df321fbd77e544dccd6c7..dc242757b63cebdff2750afc6fe085666dfb79bc 100644
--- a/indra/newview/llcontrolavatar.cpp
+++ b/indra/newview/llcontrolavatar.cpp
@@ -60,6 +60,8 @@ LLControlAvatar::LLControlAvatar(const LLUUID& id, const LLPCode pcode, LLViewer
 // virtual
 LLControlAvatar::~LLControlAvatar()
 {
+	// Should already have been unlinked before destruction
+	llassert(!mRootVolp);
 }
 
 // virtual
@@ -82,18 +84,12 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_
 {
 
     F32 max_legal_offset = MAX_LEGAL_OFFSET;
-    if (gSavedSettings.getControl("AnimatedObjectsMaxLegalOffset"))
-    {
-        max_legal_offset = gSavedSettings.getF32("AnimatedObjectsMaxLegalOffset");
-    }
-	max_legal_offset = llmax(max_legal_offset,0.f);
+	static LLCachedControl<F32> animated_object_max_legal_offset(gSavedSettings, "AnimatedObjectsMaxLegalOffset");
+	max_legal_offset = llmax(animated_object_max_legal_offset(),0.f);
 
     F32 max_legal_size = MAX_LEGAL_SIZE;
-    if (gSavedSettings.getControl("AnimatedObjectsMaxLegalSize"))
-    {
-        max_legal_size = gSavedSettings.getF32("AnimatedObjectsMaxLegalSize");
-    }
-	max_legal_size = llmax(max_legal_size, 1.f);
+	static LLCachedControl<F32> animated_object_max_legal_size(gSavedSettings, "AnimatedObjectsMaxLegalSize");
+	max_legal_size = llmax(animated_object_max_legal_size(), 1.f);
     
     new_pos_fixup = LLVector3();
     new_scale_fixup = 1.0f;
@@ -124,22 +120,22 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_
 				F32 target_dist = (offset_dist - max_legal_offset);
 				new_pos_fixup = (target_dist/offset_dist)*pos_box_offset;
 			}
-			if (new_pos_fixup != mPositionConstraintFixup)
-			{
-				LL_DEBUGS("ConstraintFix") << getFullname() << " pos fix, offset_dist " << offset_dist << " pos fixup " 
-										   << new_pos_fixup << " was " << mPositionConstraintFixup << LL_ENDL;
-				LL_DEBUGS("ConstraintFix") << "vol_pos " << vol_pos << LL_ENDL;
-				LL_DEBUGS("ConstraintFix") << "extents " << extents[0] << " " << extents[1] << LL_ENDL;
-				LL_DEBUGS("ConstraintFix") << "unshift_extents " << unshift_extents[0] << " " << unshift_extents[1] << LL_ENDL;
-				
-			}
+			//if (new_pos_fixup != mPositionConstraintFixup)
+			//{
+			//	LL_DEBUGS("ConstraintFix") << getFullname() << " pos fix, offset_dist " << offset_dist << " pos fixup " 
+			//							   << new_pos_fixup << " was " << mPositionConstraintFixup << LL_ENDL;
+			//	LL_DEBUGS("ConstraintFix") << "vol_pos " << vol_pos << LL_ENDL;
+			//	LL_DEBUGS("ConstraintFix") << "extents " << extents[0] << " " << extents[1] << LL_ENDL;
+			//	LL_DEBUGS("ConstraintFix") << "unshift_extents " << unshift_extents[0] << " " << unshift_extents[1] << LL_ENDL;
+			//	
+			//}
 		}
         if (box_size/mScaleConstraintFixup > max_legal_size)
         {
             new_scale_fixup = mScaleConstraintFixup*max_legal_size/box_size;
-            LL_DEBUGS("ConstraintFix") << getFullname() << " scale fix, box_size " << box_size << " fixup " 
-									   << mScaleConstraintFixup << " max legal " << max_legal_size 
-									   << " -> new scale " << new_scale_fixup << LL_ENDL;
+            //LL_DEBUGS("ConstraintFix") << getFullname() << " scale fix, box_size " << box_size << " fixup "
+            //						   << mScaleConstraintFixup << " max legal " << max_legal_size
+            //						   << " -> new scale " << new_scale_fixup << LL_ENDL;
         }
     }
 }
@@ -163,6 +159,8 @@ void LLControlAvatar::matchVolumeTransform()
 		mPositionConstraintFixup = new_pos_fixup;
 		mScaleConstraintFixup = new_scale_fixup;
 
+		static LLCachedControl<F32> global_scale(gSavedSettings, "AnimatedObjectsGlobalScale", 1.f);
+
         if (mRootVolp->isAttachment())
         {
             LLVOAvatar *attached_av = mRootVolp->getAvatarAncestor();
@@ -180,7 +178,6 @@ void LLControlAvatar::matchVolumeTransform()
                 mRoot->setWorldRotation(obj_rot * joint_rot);
                 setRotation(mRoot->getRotation());
 
-				F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale");
 				setGlobalScale(global_scale * mScaleConstraintFixup);
             }
             else
@@ -219,7 +216,7 @@ void LLControlAvatar::matchVolumeTransform()
 	        const LLMeshSkinInfo* skin_info = mRootVolp->getSkinInfo();
 			if (skin_info)
 			{
-                LL_DEBUGS("BindShape") << getFullname() << " bind shape " << skin_info->mBindShapeMatrix << LL_ENDL;
+                //LL_DEBUGS("BindShape") << getFullname() << " bind shape " << skin_info->mBindShapeMatrix << LL_ENDL;
                 bind_rot = LLSkinningUtil::getUnscaledQuaternion(skin_info->mBindShapeMatrix);
 			}
 #endif
@@ -228,7 +225,6 @@ void LLControlAvatar::matchVolumeTransform()
 			setPositionAgent(vol_pos);
 			mRoot->setPosition(vol_pos + mPositionConstraintFixup);
 
-            F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale");
             setGlobalScale(global_scale * mScaleConstraintFixup);
         }
     }
@@ -336,6 +332,7 @@ LLControlAvatar *LLControlAvatar::createControlAvatar(LLVOVolume *obj)
 void LLControlAvatar::markForDeath()
 {
     mMarkedForDeath = true;
+    mRootVolp = NULL;
 }
 
 void LLControlAvatar::idleUpdate(LLAgent &agent, const F64 &time)
@@ -359,7 +356,8 @@ BOOL LLControlAvatar::updateCharacter(LLAgent &agent)
 //virtual
 void LLControlAvatar::updateDebugText()
 {
-	if (gSavedSettings.getBOOL("DebugAnimatedObjects"))
+	static LLCachedControl<bool> debug_animated_objects(gSavedSettings, "DebugAnimatedObjects");
+	if (debug_animated_objects)
     {
         S32 total_linkset_count = 0;
         if (mRootVolp)
@@ -492,7 +490,7 @@ void LLControlAvatar::getAnimatedVolumes(std::vector<LLVOVolume*>& volumes)
 		 iter != child_list.end(); ++iter)
 	{
 		LLViewerObject* childp = *iter;
-        LLVOVolume *child_volp = dynamic_cast<LLVOVolume*>(childp);
+        LLVOVolume *child_volp = childp ? childp->asVolume() : nullptr;
         if (child_volp && child_volp->isAnimatedObject())
         {
             volumes.push_back(child_volp);
@@ -635,8 +633,11 @@ void LLControlAvatar::onRegionChanged()
 	std::vector<LLCharacter*>::iterator it = LLCharacter::sInstances.begin();
 	for ( ; it != LLCharacter::sInstances.end(); ++it)
 	{
-		LLControlAvatar* cav = dynamic_cast<LLControlAvatar*>(*it);
-		if (!cav) continue;
-		cav->mRegionChanged = true;
+		auto avatar = static_cast<LLVOAvatar*>(*it);
+		if (!avatar->isDead() && avatar->isControlAvatar())
+		{
+			LLControlAvatar* cav = static_cast<LLControlAvatar*>(avatar);
+			cav->mRegionChanged = true;
+		}
 	}
 }
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index c53b14de883bcb663c2f5c9d6c66ae75b76aa69a..f81b2446492adaacdefc15bf5cec9ae1b73b19e5 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -3034,7 +3034,7 @@ void LLViewerObject::linkControlAvatar()
 {
     if (!getControlAvatar() && isRootEdit())
     {
-        LLVOVolume *volp = dynamic_cast<LLVOVolume*>(this);
+        LLVOVolume *volp = asVolume();
         if (!volp)
         {
             LL_WARNS() << "called with null or non-volume object" << LL_ENDL;
@@ -3824,7 +3824,7 @@ F32 LLViewerObject::recursiveGetScaledSurfaceArea() const
                  ++child_iter)
             {
                 LLViewerObject* child_obj = *child_iter;
-                LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
+                LLVOVolume *child = child_obj ? child_obj->asVolume() : nullptr;
                 if (child && child->getVolume())
                 {
                     const LLVector3& scale = child->getScale();
@@ -5466,6 +5466,12 @@ LLVOAvatar* LLViewerObject::asAvatar()
 	return NULL;
 }
 
+// virtual 
+LLVOVolume* LLViewerObject::asVolume()
+{
+	return nullptr;
+}
+
 // If this object is directly or indirectly parented by an avatar,
 // return it.  Normally getAvatar() is the correct function to call;
 // it will give the avatar used for skinning.  The exception is with
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 3df2207e2bc076c01526c88a09b86a2fd77ccc67..390a03f01b42721cfe3cc775faed90ebfb5bbbaa 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -59,6 +59,7 @@ class LLPipeline;
 class LLTextureEntry;
 class LLVOAvatar;
 class LLVOInventoryListener;
+class LLVOVolume;
 class LLViewerInventoryItem;
 class LLViewerObject;
 class LLViewerObjectMedia;
@@ -137,6 +138,7 @@ public:
 	BOOL isParticleSource() const;
 
 	virtual LLVOAvatar* asAvatar();
+	virtual LLVOVolume* asVolume();
 
 	LLVOAvatar* getAvatarAncestor();
 
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 2c6244897b861e78e7d311f5a4252dd8c2b01587..714cc9d195d0993822f1b58034f230c1bce5480f 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -1409,7 +1409,7 @@ void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
                     // Don't we need to look at children of attached_object as well?
                     if (attached_object && !attached_object->isHUDAttachment())
                     {
-                        const LLVOVolume *vol = dynamic_cast<const LLVOVolume*>(attached_object);
+                        LLVOVolume *vol = attached_object->asVolume();
                         if (vol && vol->isAnimatedObject())
                         {
                             // Animated objects already have a bounding box in their control av, use that. 
@@ -1995,7 +1995,7 @@ void LLVOAvatar::resetVisualParams()
 			 ++iter)
 		{
 			LLPolySkeletalDistortionInfo *info = (LLPolySkeletalDistortionInfo*)*iter;
-			LLPolySkeletalDistortion *param = dynamic_cast<LLPolySkeletalDistortion*>(getVisualParam(info->getID()));
+			LLPolySkeletalDistortion *param = static_cast<LLPolySkeletalDistortion*>(getVisualParam(info->getID()));
             *param = LLPolySkeletalDistortion(this);
             llassert(param);
 			if (!param->setInfo(info))
@@ -2011,7 +2011,7 @@ void LLVOAvatar::resetVisualParams()
 		 ++iter)
 	{
 		LLDriverParamInfo *info = *iter;
-        LLDriverParam *param = dynamic_cast<LLDriverParam*>(getVisualParam(info->getID()));
+        LLDriverParam *param = static_cast<LLDriverParam*>(getVisualParam(info->getID()));
         LLDriverParam::entry_list_t driven_list = param->getDrivenList();
         *param = LLDriverParam(this);
         llassert(param);
@@ -3406,8 +3406,7 @@ void LLVOAvatar::invalidateNameTags()
 	std::vector<LLCharacter*>::iterator it = LLCharacter::sInstances.begin();
 	for ( ; it != LLCharacter::sInstances.end(); ++it)
 	{
-		LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*it);
-		if (!avatar) continue;
+        LLVOAvatar* avatar = static_cast<LLVOAvatar*>(*it);
 		if (avatar->isDead()) continue;
 
 		avatar->clearNameTag();
@@ -3694,7 +3693,7 @@ void LLVOAvatar::updateAnimationDebugText()
             {
                 if (isControlAvatar())
                 {
-                    LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
+                    LLControlAvatar *control_av = static_cast<LLControlAvatar*>(this);
                     // Try to get name from inventory of associated object
                     LLVOVolume *volp = control_av->mRootVolp;
                     LLViewerInventoryItem *item = recursiveGetObjectInventoryItem(volp,motionp->getID());
@@ -6071,10 +6070,9 @@ void LLVOAvatar::rebuildAttachmentOverrides()
     clearAttachmentOverrides();
 
     // Handle the case that we're resetting the skeleton of an animated object.
-    LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
-    if (control_av)
+    if (isControlAvatar())
     {
-        LLVOVolume *volp = control_av->mRootVolp;
+        LLVOVolume *volp = static_cast<LLControlAvatar*>(this)->mRootVolp;
         if (volp)
         {
             LL_DEBUGS("Avatar") << volp->getID() << " adding attachment overrides for root vol, prim count " 
@@ -6093,7 +6091,7 @@ void LLVOAvatar::rebuildAttachmentOverrides()
             {
                 // Attached animated objects affect joints in their control
                 // avs, not the avs to which they are attached.
-                if (!vo->isAnimatedObject())
+                if (vo && !vo->isAnimatedObject())
                 {
 					addAttachmentOverridesForObject(vo);
                 }
@@ -6118,9 +6116,9 @@ void LLVOAvatar::updateAttachmentOverrides()
     std::set<LLUUID> meshes_seen;
     
     // Handle the case that we're updating the skeleton of an animated object.
-    LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
-    if (control_av)
+    if (isControlAvatar())
     {
+        LLControlAvatar *control_av = static_cast<LLControlAvatar*>(this);
         LLVOVolume *volp = control_av->mRootVolp;
         if (volp)
         {
@@ -6144,7 +6142,7 @@ void LLVOAvatar::updateAttachmentOverrides()
                 LLViewerObject *vo = *at_it;
                 // Attached animated objects affect joints in their control
                 // avs, not the avs to which they are attached.
-                if (!vo->isAnimatedObject())
+                if (vo && !vo->isAnimatedObject())
                 {
                     addAttachmentOverridesForObject(vo, &meshes_seen);
                 }
@@ -6249,7 +6247,7 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LL
         }
     }
 
-	LLVOVolume *vobj = dynamic_cast<LLVOVolume*>(vo);
+	LLVOVolume *vobj = vo->asVolume();
 	bool pelvisGotSet = false;
 
 	if (!vobj)
@@ -9738,16 +9736,14 @@ void showRigInfoTabExtents(LLVOAvatar *avatar, LLJointRiggingInfoTab& tab, S32&
 
 void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
 {
-	for ( LLVOAvatar::attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter )
+	for ( const auto& pair : mAttachmentPoints)
 	{
-		LLViewerJointAttachment* attachment = iter->second;
-		LLViewerJointAttachment::attachedobjs_vec_t::iterator attach_end = attachment->mAttachedObjects.end();
-		
-		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attach_iter = attachment->mAttachedObjects.begin();
-			 attach_iter != attach_end; ++attach_iter)
+		for(LLViewerObject* attached_object : pair.second->mAttachedObjects)
 		{
-			LLViewerObject* attached_object =  *attach_iter;
-            LLVOVolume *volume = dynamic_cast<LLVOVolume*>(attached_object);
+			if (!attached_object)
+				continue;
+
+            LLVOVolume *volume = attached_object->asVolume();
             if (volume)
             {
                 volumes.push_back(volume);
@@ -9760,11 +9756,12 @@ void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
                 }
             }
             LLViewerObject::const_child_list_t& children = attached_object->getChildren();
-            for (LLViewerObject::const_child_list_t::const_iterator it = children.begin();
-                 it != children.end(); ++it)
+			for (LLViewerObject* childp : children)
             {
-                LLViewerObject *childp = *it;
-                LLVOVolume *volume = dynamic_cast<LLVOVolume*>(childp);
+				if (!childp) 
+					continue;
+
+                LLVOVolume *volume = childp->asVolume();
                 if (volume)
                 {
                     volumes.push_back(volume);
@@ -9773,10 +9770,10 @@ void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
         }
     }
 
-    LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
-    if (control_av)
+    if (isControlAvatar())
     {
-        LLVOVolume *volp = control_av->mRootVolp;
+		LLControlAvatar *control_av = static_cast<LLControlAvatar*>(this);
+		LLVOVolume *volp = control_av->mRootVolp;
         if (volp)
         {
             volumes.push_back(volp);
@@ -9785,7 +9782,7 @@ void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
                  it != children.end(); ++it)
             {
                 LLViewerObject *childp = *it;
-                LLVOVolume *volume = dynamic_cast<LLVOVolume*>(childp);
+                LLVOVolume *volume = childp ? childp->asVolume() : nullptr;
                 if (volume)
                 {
                     volumes.push_back(volume);
@@ -9969,8 +9966,8 @@ void LLVOAvatar::idleUpdateRenderComplexity()
 {
     if (isControlAvatar())
     {
-        LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this);
-        bool is_attachment = cav && cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects
+        LLControlAvatar *cav = static_cast<LLControlAvatar*>(this);
+        bool is_attachment = cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects
         if (is_attachment)
         {
             // ARC for animated object attachments is accounted with the avatar they're attached to.
@@ -10108,7 +10105,7 @@ void LLVOAvatar::accountRenderComplexityForObject(
                      ++child_iter)
                 {
                     LLViewerObject* child_obj = *child_iter;
-                    LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
+                    LLVOVolume *child = child_obj ? child_obj->asVolume() : nullptr;
                     if (child)
                     {
                         attachment_children_cost += child->getRenderCost(textures);
@@ -10163,7 +10160,7 @@ void LLVOAvatar::accountRenderComplexityForObject(
                  iter != child_list.end(); ++iter)
             {
                 LLViewerObject* childp = *iter;
-                const LLVOVolume* chld_volume = dynamic_cast<LLVOVolume*>(childp);
+                const LLVOVolume* chld_volume = childp ? childp->asVolume() : nullptr;
                 if (chld_volume)
                 {
                     // get cost and individual textures
@@ -10242,10 +10239,10 @@ void LLVOAvatar::calculateUpdateRenderComplexity()
         // A standalone animated object needs to be accounted for
         // using its associated volume. Attached animated objects
         // will be covered by the subsequent loop over attachments.
-        LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
-        if (control_av)
+        if (isControlAvatar())
         {
-            LLVOVolume *volp = control_av->mRootVolp;
+			LLControlAvatar *control_av = static_cast<LLControlAvatar*>(this);
+			LLVOVolume *volp = control_av->mRootVolp;
             if (volp && !volp->isAttachment())
             {
                 accountRenderComplexityForObject(volp, max_attachment_complexity,
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 378c6cbc178a4a9f3be4e6efc4e035b522039683..4c7b07bab8b7e8a3fc60d11ed6434358dbaa6e8b 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -266,6 +266,11 @@ LLVOVolume::~LLVOVolume()
 	}
 }
 
+LLVOVolume* LLVOVolume::asVolume()
+{
+	return this;
+}
+
 void LLVOVolume::markDead()
 {
 	if (!mDead)
@@ -1327,7 +1332,7 @@ std::string get_debug_object_lod_text(LLVOVolume *rootp)
          iter != child_list.end(); ++iter)
     {
         LLViewerObject *childp = *iter;
-        LLVOVolume *volp = dynamic_cast<LLVOVolume*>(childp);
+        LLVOVolume *volp = childp ? childp->asVolume() : nullptr;
         if (volp)
         {
             lod_string += llformat("%d",volp->getLOD());
@@ -3658,8 +3663,6 @@ bool LLVOVolume::isAnimatedObject() const
 // virtual
 void LLVOVolume::onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent)
 {
-    LLVOVolume *old_volp = dynamic_cast<LLVOVolume*>(old_parent);
-
     if (new_parent && !new_parent->isAvatar())
     {
         if (mControlAvatar.notNull())
@@ -3671,7 +3674,8 @@ void LLVOVolume::onReparent(LLViewerObject *old_parent, LLViewerObject *new_pare
             av->markForDeath();
         }
     }
-    if (old_volp && old_volp->isAnimatedObject())
+	LLVOVolume *old_volp = old_parent ? old_parent->asVolume() : nullptr;
+	if (old_volp && old_volp->isAnimatedObject())
     {
         if (old_volp->getControlAvatar())
         {
@@ -5415,7 +5419,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	if (bridge)
 	{
         vobj = bridge->mDrawable->getVObj();
-        vol_obj = dynamic_cast<LLVOVolume*>(vobj);
+        vol_obj = vobj ? vobj->asVolume() : nullptr;
 	}
     if (vol_obj)
     {
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 89e3e7fd74fe474abfef63ade5cbf48657f910db..dddd37e2e19c2ef8c760f39a1380dab09c46a644 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -113,6 +113,8 @@ public:
 
 public:
 						LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
+
+				LLVOVolume* asVolume() final;
 	/*virtual*/ void markDead() override;		// Override (and call through to parent) to clean up media references
 
 	/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline) override;