layers: Remove VulkanTypedHandle usage from NotifyInvalidate

Since everything in the NotifyInvalidate() call tree is a valid
state object, use BASE_NODE pointers directly instead of relying
on VulkanTypedHandle.node.

Note that CMD_BUFFER_STATE::broken_bindings includes handles for
objects that have been destroyed, so it must continue to use
VulkanTypedHandle.
diff --git a/layers/base_node.h b/layers/base_node.h
index b895197..5f96f64 100644
--- a/layers/base_node.h
+++ b/layers/base_node.h
@@ -47,7 +47,8 @@
 
 class BASE_NODE {
   public:
-    using BindingsType = layer_data::unordered_set<BASE_NODE*>;
+    using NodeSet = layer_data::unordered_set<BASE_NODE *>;
+    using NodeList = small_vector<BASE_NODE *, 4>;
 
     template <typename Handle>
     BASE_NODE(Handle h, VulkanObjectType t) : handle_(h, t, this), destroyed_(false) {}
@@ -62,6 +63,7 @@
     bool Destroyed() const { return destroyed_; }
 
     const VulkanTypedHandle &Handle() const { return handle_; }
+    VulkanObjectType Type() const { return handle_.type; }
 
     virtual bool InUse() const {
         bool result = false;
@@ -84,23 +86,26 @@
     }
 
     void Invalidate(bool unlink = true) {
-        LogObjectList invalid_handles(handle_);
+        NodeList invalid_nodes;
+        invalid_nodes.emplace_back(this);
         for (auto& node: parent_nodes_) {
-            node->NotifyInvalidate(invalid_handles, unlink);
+            node->NotifyInvalidate(invalid_nodes, unlink);
         }
         if (unlink) {
             parent_nodes_.clear();
         }
     }
   protected:
-    virtual void NotifyInvalidate(const LogObjectList& invalid_handles, bool unlink) {
+    // NOTE: the entries in invalid_nodes will likely be destroyed & deleted
+    // after the NotifyInvalidate() calls finish.
+    virtual void NotifyInvalidate(const NodeList &invalid_nodes, bool unlink) {
         if (parent_nodes_.size() == 0) {
             return;
         }
-        LogObjectList up_handles = invalid_handles;
-        up_handles.object_list.emplace_back(handle_);
+        NodeList up_nodes = invalid_nodes;
+        up_nodes.emplace_back(this);
         for (auto& node: parent_nodes_) {
-            node->NotifyInvalidate(up_handles, unlink);
+            node->NotifyInvalidate(up_nodes, unlink);
         }
         if (unlink) {
             parent_nodes_.clear();
@@ -115,7 +120,7 @@
 
     // Set of immediate parent nodes for this object. For an in-use object, the
     // parent nodes should form a tree with the root being a command buffer.
-    BindingsType parent_nodes_;
+    NodeSet parent_nodes_;
 };
 
 class REFCOUNTED_NODE : public BASE_NODE {
diff --git a/layers/cmd_buffer_state.cpp b/layers/cmd_buffer_state.cpp
index 1279818..1c6b486 100644
--- a/layers/cmd_buffer_state.cpp
+++ b/layers/cmd_buffer_state.cpp
@@ -253,14 +253,16 @@
 }
 
 void CMD_BUFFER_STATE::AddChild(BASE_NODE *child_node) {
+    assert(child_node);
     if (child_node->AddParent(this)) {
-        object_bindings.insert(child_node->Handle());
+        object_bindings.insert(child_node);
     }
 }
 
 void CMD_BUFFER_STATE::RemoveChild(BASE_NODE *child_node) {
+    assert(child_node);
     child_node->RemoveParent(this);
-    object_bindings.erase(child_node->Handle());
+    object_bindings.erase(child_node);
 }
 
 // Reset the command buffer state
@@ -328,9 +330,7 @@
 
     // Remove object bindings
     for (const auto &obj : object_bindings) {
-        if (obj.node) {
-            obj.node->RemoveParent(this);
-        }
+        obj->RemoveParent(this);
     }
     object_bindings.clear();
 
@@ -358,9 +358,8 @@
     transform_feedback_active = false;
 
     // Remove object bindings
-    for (const auto &obj : object_bindings) {
-        BASE_NODE *base_obj = obj.node;
-        if (base_obj) RemoveChild(base_obj);
+    for (auto *base_obj : object_bindings) {
+        RemoveChild(base_obj);
     }
     object_bindings.clear();
 
@@ -451,24 +450,28 @@
     BASE_NODE::Destroy();
 }
 
-void CMD_BUFFER_STATE::NotifyInvalidate(const LogObjectList &invalid_handles, bool unlink) {
+void CMD_BUFFER_STATE::NotifyInvalidate(const BASE_NODE::NodeList &invalid_nodes, bool unlink) {
     if (state == CB_RECORDING) {
         state = CB_INVALID_INCOMPLETE;
     } else if (state == CB_RECORDED) {
         state = CB_INVALID_COMPLETE;
     }
-    assert(!invalid_handles.object_list.empty());
-    broken_bindings.emplace(invalid_handles.object_list[0], invalid_handles);
+    assert(!invalid_nodes.empty());
+    LogObjectList log_list;
+    for (auto *obj : invalid_nodes) {
+        log_list.object_list.emplace_back(obj->Handle());
+    }
+    broken_bindings.emplace(invalid_nodes[0]->Handle(), log_list);
 
     if (unlink) {
-        for (auto &obj : invalid_handles.object_list) {
+        for (auto *obj : invalid_nodes) {
             object_bindings.erase(obj);
-            if (obj.type == kVulkanObjectTypeCommandBuffer) {
-                linkedCommandBuffers.erase(static_cast<CMD_BUFFER_STATE *>(obj.node));
+            if (obj->Type() == kVulkanObjectTypeCommandBuffer) {
+                linkedCommandBuffers.erase(static_cast<CMD_BUFFER_STATE *>(obj));
             }
         }
     }
-    BASE_NODE::NotifyInvalidate(invalid_handles, unlink);
+    BASE_NODE::NotifyInvalidate(invalid_nodes, unlink);
 }
 
 const CommandBufferImageLayoutMap& CMD_BUFFER_STATE::GetImageSubresourceLayoutMap() const { return image_layout_map; }
diff --git a/layers/cmd_buffer_state.h b/layers/cmd_buffer_state.h
index 52b7be1..eebb1b1 100644
--- a/layers/cmd_buffer_state.h
+++ b/layers/cmd_buffer_state.h
@@ -262,7 +262,7 @@
     layer_data::unordered_set<std::shared_ptr<FRAMEBUFFER_STATE>> framebuffers;
     // Unified data structs to track objects bound to this command buffer as well as object
     //  dependencies that have been broken : either destroyed objects, or updated descriptor sets
-    layer_data::unordered_set<VulkanTypedHandle> object_bindings;
+    BASE_NODE::NodeSet object_bindings;
     layer_data::unordered_map<VulkanTypedHandle, LogObjectList> broken_bindings;
 
     QFOTransferBarrierSets<QFOBufferTransferBarrier> qfo_transfer_buffer_barriers;
@@ -447,7 +447,7 @@
     void Retire(uint32_t perf_submit_pass);
 
   protected:
-    void NotifyInvalidate(const LogObjectList &invalid_handles, bool unlink) override;
+    void NotifyInvalidate(const BASE_NODE::NodeList &invalid_nodes, bool unlink) override;
     void UpdateAttachmentsView(const VkRenderPassBeginInfo *pRenderPassBegin);
 };
 
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index be54215..1fc9874 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -3109,21 +3109,28 @@
         }
 
         // Ensure that any bound images or buffers created with SHARING_MODE_CONCURRENT have access to the current queue family
-        for (const auto &object : pCB->object_bindings) {
-            if (object.type == kVulkanObjectTypeImage) {
-                auto image_state = object.node ? (IMAGE_STATE *)object.node : GetImageState(object.Cast<VkImage>());
-                if (image_state && image_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
-                    skip |= ValidImageBufferQueue(pCB, object, queue_state->queueFamilyIndex,
-                                                  image_state->createInfo.queueFamilyIndexCount,
-                                                  image_state->createInfo.pQueueFamilyIndices);
+        for (const auto *base_node : pCB->object_bindings) {
+            switch (base_node->Type()) {
+                case kVulkanObjectTypeImage: {
+                    auto image_state = static_cast<const IMAGE_STATE *>(base_node);
+                    if (image_state && image_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
+                        skip |= ValidImageBufferQueue(pCB, image_state->Handle(), queue_state->queueFamilyIndex,
+                                                      image_state->createInfo.queueFamilyIndexCount,
+                                                      image_state->createInfo.pQueueFamilyIndices);
+                    }
+                    break;
                 }
-            } else if (object.type == kVulkanObjectTypeBuffer) {
-                auto buffer_state = object.node ? (BUFFER_STATE *)object.node : GetBufferState(object.Cast<VkBuffer>());
-                if (buffer_state && buffer_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
-                    skip |= ValidImageBufferQueue(pCB, object, queue_state->queueFamilyIndex,
-                                                  buffer_state->createInfo.queueFamilyIndexCount,
-                                                  buffer_state->createInfo.pQueueFamilyIndices);
+                case kVulkanObjectTypeBuffer: {
+                    auto buffer_state = static_cast<const BUFFER_STATE *>(base_node);
+                    if (buffer_state && buffer_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
+                        skip |= ValidImageBufferQueue(pCB, buffer_state->Handle(), queue_state->queueFamilyIndex,
+                                                      buffer_state->createInfo.queueFamilyIndexCount,
+                                                      buffer_state->createInfo.pQueueFamilyIndices);
+                    }
+                    break;
                 }
+                default:
+                    break;
             }
         }
     }
diff --git a/layers/device_memory_state.h b/layers/device_memory_state.h
index 5f80b3e..d3775c7 100644
--- a/layers/device_memory_state.h
+++ b/layers/device_memory_state.h
@@ -81,7 +81,7 @@
 
     VkDeviceMemory mem() const { return handle_.Cast<VkDeviceMemory>(); }
 
-    const BindingsType &ObjectBindings() const { return parent_nodes_; }
+    const NodeSet &ObjectBindings() const { return parent_nodes_; }
 };
 
 // Generic memory binding struct to track objects bound to objects
diff --git a/layers/image_state.cpp b/layers/image_state.cpp
index a4c049c..132c340 100644
--- a/layers/image_state.cpp
+++ b/layers/image_state.cpp
@@ -265,8 +265,8 @@
     BINDABLE::Destroy();
 }
 
-void IMAGE_STATE::NotifyInvalidate(const LogObjectList &invalid_handles, bool unlink) {
-    BINDABLE::NotifyInvalidate(invalid_handles, unlink);
+void IMAGE_STATE::NotifyInvalidate(const BASE_NODE::NodeList &invalid_nodes, bool unlink) {
+    BINDABLE::NotifyInvalidate(invalid_nodes, unlink);
     if (unlink) {
         Unlink();
     }
@@ -331,7 +331,7 @@
 void IMAGE_STATE::SetMemBinding(std::shared_ptr<DEVICE_MEMORY_STATE> &mem, VkDeviceSize memory_offset) {
     if ((createInfo.flags & VK_IMAGE_CREATE_ALIAS_BIT) != 0) {
         for (auto *base_node : mem->ObjectBindings()) {
-            if (base_node->Handle().type == kVulkanObjectTypeImage) {
+            if (base_node->Type() == kVulkanObjectTypeImage) {
                 auto other_image = static_cast<IMAGE_STATE *>(base_node);
                 AddAliasingImage(other_image);
             }
@@ -346,7 +346,7 @@
     swapchain_image_index = swapchain_index;
     bind_swapchain->AddParent(this);
     for (auto *base_node : swapchain->ObjectBindings()) {
-        if (base_node->Handle().type == kVulkanObjectTypeImage) {
+        if (base_node->Type() == kVulkanObjectTypeImage) {
             auto other_image = static_cast<IMAGE_STATE *>(base_node);
             if (swapchain_image_index == other_image->swapchain_image_index) {
                 AddAliasingImage(other_image);
@@ -551,8 +551,8 @@
     BASE_NODE::Destroy();
 }
 
-void SWAPCHAIN_NODE::NotifyInvalidate(const LogObjectList &invalid_handles, bool unlink) {
-    BASE_NODE::NotifyInvalidate(invalid_handles, unlink);
+void SWAPCHAIN_NODE::NotifyInvalidate(const BASE_NODE::NodeList &invalid_nodes, bool unlink) {
+    BASE_NODE::NotifyInvalidate(invalid_nodes, unlink);
     if (unlink) {
         surface = nullptr;
     }
diff --git a/layers/image_state.h b/layers/image_state.h
index e8d3bfe..a97dc38 100644
--- a/layers/image_state.h
+++ b/layers/image_state.h
@@ -188,7 +188,7 @@
   protected:
     void AddAliasingImage(IMAGE_STATE *bound_image);
     void Unlink();
-    void NotifyInvalidate(const LogObjectList &invalid_handles, bool unlink) override;
+    void NotifyInvalidate(const BASE_NODE::NodeList &invalid_nodes, bool unlink) override;
 };
 
 // State for VkImageView objects.
@@ -268,10 +268,10 @@
 
     void Destroy() override;
 
-    const BindingsType &ObjectBindings() const { return parent_nodes_; }
+    const NodeSet &ObjectBindings() const { return parent_nodes_; }
 
   protected:
-    void NotifyInvalidate(const LogObjectList &invalid_handles, bool unlink) override;
+    void NotifyInvalidate(const BASE_NODE::NodeList &invalid_nodes, bool unlink) override;
 };
 
 struct GpuQueue {