EDK: Replace HandleTable::GetAndRemoveDispatcher() with GetAndRemoveHandle().

(Also temporarily leave in Core::GetAndRemoveDispatcher() for now,
though it should probably be replaced with a GetAndRemoveHandle()
directly.)

R=azani@chromium.org

Review URL: https://codereview.chromium.org/1949283002 .
diff --git a/mojo/edk/system/core.cc b/mojo/edk/system/core.cc
index 0391585..1c89dd2 100644
--- a/mojo/edk/system/core.cc
+++ b/mojo/edk/system/core.cc
@@ -98,26 +98,30 @@
   return handle_table_.AddHandle(std::move(handle));
 }
 
-MojoResult Core::GetDispatcher(MojoHandle handle_value,
+MojoResult Core::GetDispatcher(MojoHandle handle,
                                RefPtr<Dispatcher>* dispatcher) {
-  if (handle_value == MOJO_HANDLE_INVALID)
+  if (handle == MOJO_HANDLE_INVALID)
     return MOJO_RESULT_INVALID_ARGUMENT;
 
   MutexLocker locker(&handle_table_mutex_);
-  Handle handle;
-  MojoResult rv = handle_table_.GetHandle(handle_value, &handle);
+  Handle h;
+  MojoResult rv = handle_table_.GetHandle(handle, &h);
   if (rv == MOJO_RESULT_OK)
-    *dispatcher = std::move(handle.dispatcher);
+    *dispatcher = std::move(h.dispatcher);
   return rv;
 }
 
-MojoResult Core::GetAndRemoveDispatcher(MojoHandle handle_value,
+MojoResult Core::GetAndRemoveDispatcher(MojoHandle handle,
                                         RefPtr<Dispatcher>* dispatcher) {
-  if (handle_value == MOJO_HANDLE_INVALID)
+  if (handle == MOJO_HANDLE_INVALID)
     return MOJO_RESULT_INVALID_ARGUMENT;
 
   MutexLocker locker(&handle_table_mutex_);
-  return handle_table_.GetAndRemoveDispatcher(handle_value, dispatcher);
+  Handle h;
+  MojoResult rv = handle_table_.GetAndRemoveHandle(handle, &h);
+  if (rv == MOJO_RESULT_OK)
+    *dispatcher = std::move(h.dispatcher);
+  return rv;
 }
 
 MojoResult Core::AsyncWait(MojoHandle handle,
@@ -143,11 +147,10 @@
   if (handle == MOJO_HANDLE_INVALID)
     return MOJO_RESULT_INVALID_ARGUMENT;
 
-  RefPtr<Dispatcher> dispatcher;
+  Handle h;
   {
     MutexLocker locker(&handle_table_mutex_);
-    MojoResult result =
-        handle_table_.GetAndRemoveDispatcher(handle, &dispatcher);
+    MojoResult result = handle_table_.GetAndRemoveHandle(handle, &h);
     if (result != MOJO_RESULT_OK)
       return result;
   }
@@ -156,7 +159,7 @@
   // Note: This is done outside of |handle_table_mutex_|. As a result, there's a
   // race condition that the dispatcher must handle; see the comment in
   // |Dispatcher| in dispatcher.h.
-  return dispatcher->Close();
+  return h.dispatcher->Close();
 }
 
 MojoResult Core::Wait(MojoHandle handle,
diff --git a/mojo/edk/system/core.h b/mojo/edk/system/core.h
index d61ec11..18ad059 100644
--- a/mojo/edk/system/core.h
+++ b/mojo/edk/system/core.h
@@ -37,6 +37,9 @@
 
 // |Core| is an object that implements the Mojo system calls. All public methods
 // are thread-safe.
+//
+// Convention: |MojoHandle|s are referred to as |handle| or |foo_handle|,
+// whereas |Handle|s are just |h|.
 class Core {
  public:
   // ---------------------------------------------------------------------------
@@ -50,19 +53,19 @@
   // Adds |handle| (which must have a dispatcher) to the handle table, returning
   // the handle value for it. Returns |MOJO_HANDLE_INVALID| on failure, namely
   // if the handle table is full.
-  MojoHandle AddHandle(Handle&& handle);
+  MojoHandle AddHandle(Handle&& h);
 
   // Looks up the dispatcher for the given handle value. On success, gets the
   // dispatcher for a given handle value. On failure, returns an appropriate
   // result and leaves |dispatcher| alone), namely
   // |MOJO_RESULT_INVALID_ARGUMENT| if the handle value is invalid or
   // |MOJO_RESULT_BUSY| if the handle is marked as busy.
-  MojoResult GetDispatcher(MojoHandle handle_value,
+  MojoResult GetDispatcher(MojoHandle handle,
                            util::RefPtr<Dispatcher>* dispatcher);
 
   // Like |GetDispatcher()|, but on success also removes the handle from the
   // handle table.
-  MojoResult GetAndRemoveDispatcher(MojoHandle handle_value,
+  MojoResult GetAndRemoveDispatcher(MojoHandle handle,
                                     util::RefPtr<Dispatcher>* dispatcher);
 
   // Watches on the given handle for the given signals, calling |callback| when
diff --git a/mojo/edk/system/handle.h b/mojo/edk/system/handle.h
index df7fac2..c02fa1d 100644
--- a/mojo/edk/system/handle.h
+++ b/mojo/edk/system/handle.h
@@ -32,9 +32,20 @@
   Handle& operator=(const Handle&);
   Handle& operator=(Handle&&);
 
+  // Returns a new |Handle| with the same contents as this object. Useful when a
+  // function takes a |Handle&&| argument and the caller wants to retain its
+  // copy (rather than moving it).
+  Handle Clone() const { return *this; }
+
   // A |Handle| tests as true if it actually has a dispatcher.
   explicit operator bool() const { return !!dispatcher; }
 
+  bool operator==(const Handle& rhs) const {
+    return dispatcher == rhs.dispatcher && rights == rhs.rights;
+  }
+
+  bool operator!=(const Handle& rhs) const { return !operator==(rhs); }
+
   void reset() { *this = Handle(); }
 
   // Note: |dispatcher| is guaranteed to be null if default-constructed or
diff --git a/mojo/edk/system/handle_table.cc b/mojo/edk/system/handle_table.cc
index cae7a94..bd20db6 100644
--- a/mojo/edk/system/handle_table.cc
+++ b/mojo/edk/system/handle_table.cc
@@ -49,17 +49,17 @@
   return MOJO_RESULT_OK;
 }
 
-MojoResult HandleTable::GetAndRemoveDispatcher(MojoHandle handle_value,
-                                               RefPtr<Dispatcher>* dispatcher) {
+MojoResult HandleTable::GetAndRemoveHandle(MojoHandle handle_value,
+                                           Handle* handle) {
   DCHECK_NE(handle_value, MOJO_HANDLE_INVALID);
-  DCHECK(dispatcher);
+  DCHECK(handle);
 
   HandleToEntryMap::iterator it = handle_to_entry_map_.find(handle_value);
   if (it == handle_to_entry_map_.end())
     return MOJO_RESULT_INVALID_ARGUMENT;
   if (it->second.busy)
     return MOJO_RESULT_BUSY;
-  *dispatcher = std::move(it->second.handle.dispatcher);
+  *handle = std::move(it->second.handle);
   handle_to_entry_map_.erase(it);
 
   return MOJO_RESULT_OK;
diff --git a/mojo/edk/system/handle_table.h b/mojo/edk/system/handle_table.h
index fb346d6..6376a13 100644
--- a/mojo/edk/system/handle_table.h
+++ b/mojo/edk/system/handle_table.h
@@ -56,10 +56,9 @@
   // marked as busy.
   MojoResult GetHandle(MojoHandle handle_value, Handle* handle);
 
-  // Like |GetDispatcher()|, but on success also removes the handle value from
-  // the handle table.
-  MojoResult GetAndRemoveDispatcher(MojoHandle handle_value,
-                                    util::RefPtr<Dispatcher>* dispatcher);
+  // Like |GetHandle()|, but on success also removes the handle value from the
+  // handle table.
+  MojoResult GetAndRemoveHandle(MojoHandle handle_value, Handle* handle);
 
   // Adds a handle (which must have a dispatcher), returning the handle value
   // for it. Returns |MOJO_HANDLE_INVALID| on failure (if the handle table is
diff --git a/mojo/edk/system/handle_table_unittest.cc b/mojo/edk/system/handle_table_unittest.cc
index 55af970..92bffd7 100644
--- a/mojo/edk/system/handle_table_unittest.cc
+++ b/mojo/edk/system/handle_table_unittest.cc
@@ -21,26 +21,28 @@
 TEST(HandleTableTest, Basic) {
   HandleTable ht(1000u);
 
-  RefPtr<Dispatcher> d = MakeRefCounted<test::MockSimpleDispatcher>();
+  Handle h(MakeRefCounted<test::MockSimpleDispatcher>(),
+           MOJO_HANDLE_RIGHT_TRANSFER | MOJO_HANDLE_RIGHT_READ);
 
-  MojoHandle hv = ht.AddHandle(Handle(d.Clone(), MOJO_HANDLE_RIGHT_NONE));
+  MojoHandle hv = ht.AddHandle(h.Clone());
   ASSERT_NE(hv, MOJO_HANDLE_INVALID);
 
   // Save the pointer value (without taking a ref), so we can check that we get
   // the same object back.
-  Dispatcher* dv = d.get();
+  Dispatcher* dv = h.dispatcher.get();
   // Reset this, to make sure that the handle table takes a ref.
-  d = nullptr;
+  h.reset();
 
-  Handle h;
   EXPECT_EQ(MOJO_RESULT_OK, ht.GetHandle(hv, &h));
   EXPECT_EQ(dv, h.dispatcher.get());
+  EXPECT_EQ(MOJO_HANDLE_RIGHT_TRANSFER | MOJO_HANDLE_RIGHT_READ, h.rights);
 
-  d = nullptr;
-  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(hv, &d));
-  ASSERT_EQ(dv, d.get());
+  h.reset();
+  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv, &h));
+  ASSERT_EQ(dv, h.dispatcher.get());
+  EXPECT_EQ(MOJO_HANDLE_RIGHT_TRANSFER | MOJO_HANDLE_RIGHT_READ, h.rights);
 
-  EXPECT_EQ(MOJO_RESULT_OK, d->Close());
+  EXPECT_EQ(MOJO_RESULT_OK, h.dispatcher->Close());
 
   // We removed |hv|, so it should no longer be valid.
   h.reset();
@@ -50,132 +52,134 @@
 TEST(HandleTableTest, AddHandlePair) {
   HandleTable ht(1000u);
 
-  auto d1 = MakeRefCounted<test::MockSimpleDispatcher>();
-  auto d2 = MakeRefCounted<test::MockSimpleDispatcher>();
+  Handle h1(MakeRefCounted<test::MockSimpleDispatcher>(),
+            MOJO_HANDLE_RIGHT_NONE);
+  Handle h2(MakeRefCounted<test::MockSimpleDispatcher>(),
+            MOJO_HANDLE_RIGHT_DUPLICATE);
 
-  auto hp = ht.AddHandlePair(Handle(d1.Clone(), MOJO_HANDLE_RIGHT_NONE),
-                             Handle(d2.Clone(), MOJO_HANDLE_RIGHT_NONE));
+  auto hp = ht.AddHandlePair(h1.Clone(), h2.Clone());
   ASSERT_NE(hp.first, MOJO_HANDLE_INVALID);
   ASSERT_NE(hp.second, MOJO_HANDLE_INVALID);
   ASSERT_NE(hp.first, hp.second);
 
-  RefPtr<Dispatcher> d;
-  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(hp.first, &d));
-  ASSERT_EQ(d1, d);
+  Handle h;
+  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hp.first, &h));
+  ASSERT_EQ(h1, h);
 
-  d = nullptr;
-  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(hp.second, &d));
-  ASSERT_EQ(d2, d);
+  h.reset();
+  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hp.second, &h));
+  ASSERT_EQ(h2, h);
 
-  EXPECT_EQ(MOJO_RESULT_OK, d1->Close());
-  EXPECT_EQ(MOJO_RESULT_OK, d2->Close());
+  EXPECT_EQ(MOJO_RESULT_OK, h1.dispatcher->Close());
+  EXPECT_EQ(MOJO_RESULT_OK, h2.dispatcher->Close());
 }
 
 TEST(HandleTableTest, AddHandleTooMany) {
   HandleTable ht(2u);
 
-  auto d1 = MakeRefCounted<test::MockSimpleDispatcher>();
-  auto d2 = MakeRefCounted<test::MockSimpleDispatcher>();
-  auto d3 = MakeRefCounted<test::MockSimpleDispatcher>();
+  Handle h1(MakeRefCounted<test::MockSimpleDispatcher>(),
+            MOJO_HANDLE_RIGHT_NONE);
+  Handle h2(MakeRefCounted<test::MockSimpleDispatcher>(),
+            MOJO_HANDLE_RIGHT_DUPLICATE);
+  Handle h3(MakeRefCounted<test::MockSimpleDispatcher>(),
+            MOJO_HANDLE_RIGHT_TRANSFER);
 
-  MojoHandle h1 = ht.AddHandle(Handle(d1.Clone(), MOJO_HANDLE_RIGHT_NONE));
-  ASSERT_NE(h1, MOJO_HANDLE_INVALID);
+  MojoHandle hv1 = ht.AddHandle(h1.Clone());
+  ASSERT_NE(hv1, MOJO_HANDLE_INVALID);
 
-  MojoHandle h2 = ht.AddHandle(Handle(d2.Clone(), MOJO_HANDLE_RIGHT_NONE));
-  ASSERT_NE(h2, MOJO_HANDLE_INVALID);
-  EXPECT_NE(h2, h1);
+  MojoHandle hv2 = ht.AddHandle(h2.Clone());
+  ASSERT_NE(hv2, MOJO_HANDLE_INVALID);
+  EXPECT_NE(hv2, hv1);
 
-  // Table should be full; adding |d3| should fail.
-  EXPECT_EQ(MOJO_HANDLE_INVALID,
-            ht.AddHandle(Handle(d3.Clone(), MOJO_HANDLE_RIGHT_NONE)));
+  // Table should be full; adding |h3| should fail.
+  EXPECT_EQ(MOJO_HANDLE_INVALID, ht.AddHandle(h3.Clone()));
 
-  // Remove |h2|/|d2|.
-  RefPtr<Dispatcher> d;
-  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h2, &d));
-  ASSERT_EQ(d2, d);
+  // Remove |hv2|/|h2|.
+  Handle h;
+  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv2, &h));
+  ASSERT_EQ(h2, h);
 
-  // Now adding |d3| should succeed.
-  MojoHandle h3 = ht.AddHandle(Handle(d3.Clone(), MOJO_HANDLE_RIGHT_NONE));
-  ASSERT_NE(h3, MOJO_HANDLE_INVALID);
-  EXPECT_NE(h3, h1);
-  // Note: |h3| may be equal to |h2| (handle values may be reused).
+  // Now adding |h3| should succeed.
+  MojoHandle hv3 = ht.AddHandle(h3.Clone());
+  ASSERT_NE(hv3, MOJO_HANDLE_INVALID);
+  EXPECT_NE(hv3, hv1);
+  // Note: |hv3| may be equal to |hv2| (handle values may be reused).
 
-  d = nullptr;
-  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h1, &d));
-  ASSERT_EQ(d1, d);
+  h.reset();
+  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv1, &h));
+  ASSERT_EQ(h1, h);
 
-  d = nullptr;
-  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h3, &d));
-  ASSERT_EQ(d3, d);
+  h.reset();
+  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv3, &h));
+  ASSERT_EQ(h3, h);
 
-  EXPECT_EQ(MOJO_RESULT_OK, d1->Close());
-  EXPECT_EQ(MOJO_RESULT_OK, d2->Close());
-  EXPECT_EQ(MOJO_RESULT_OK, d3->Close());
+  EXPECT_EQ(MOJO_RESULT_OK, h1.dispatcher->Close());
+  EXPECT_EQ(MOJO_RESULT_OK, h2.dispatcher->Close());
+  EXPECT_EQ(MOJO_RESULT_OK, h3.dispatcher->Close());
 }
 
 TEST(HandleTableTest, AddHandlePairTooMany) {
   HandleTable ht(2u);
 
-  auto d1 = MakeRefCounted<test::MockSimpleDispatcher>();
-  auto d2 = MakeRefCounted<test::MockSimpleDispatcher>();
-  auto d3 = MakeRefCounted<test::MockSimpleDispatcher>();
-  auto d4 = MakeRefCounted<test::MockSimpleDispatcher>();
+  Handle h1(MakeRefCounted<test::MockSimpleDispatcher>(),
+            MOJO_HANDLE_RIGHT_NONE);
+  Handle h2(MakeRefCounted<test::MockSimpleDispatcher>(),
+            MOJO_HANDLE_RIGHT_TRANSFER);
+  Handle h3(MakeRefCounted<test::MockSimpleDispatcher>(),
+            MOJO_HANDLE_RIGHT_READ);
+  Handle h4(MakeRefCounted<test::MockSimpleDispatcher>(),
+            MOJO_HANDLE_RIGHT_WRITE);
 
-  auto hp = ht.AddHandlePair(Handle(d1.Clone(), MOJO_HANDLE_RIGHT_NONE),
-                             Handle(d2.Clone(), MOJO_HANDLE_RIGHT_NONE));
-  auto h1 = hp.first;
-  auto h2 = hp.second;
-  ASSERT_NE(h1, MOJO_HANDLE_INVALID);
-  ASSERT_NE(h2, MOJO_HANDLE_INVALID);
-  ASSERT_NE(h1, h2);
+  auto hp = ht.AddHandlePair(h1.Clone(), h2.Clone());
+  auto hv1 = hp.first;
+  auto hv2 = hp.second;
+  ASSERT_NE(hv1, MOJO_HANDLE_INVALID);
+  ASSERT_NE(hv2, MOJO_HANDLE_INVALID);
+  ASSERT_NE(hv1, hv2);
 
-  // Table should be full; adding |d3| should fail.
-  EXPECT_EQ(MOJO_HANDLE_INVALID,
-            ht.AddHandle(Handle(d3.Clone(), MOJO_HANDLE_RIGHT_NONE)));
+  // Table should be full; adding |h3| should fail.
+  EXPECT_EQ(MOJO_HANDLE_INVALID, ht.AddHandle(h3.Clone()));
 
-  // Adding |d3| and |d4| as a pair should also fail.
-  auto hp2 = ht.AddHandlePair(Handle(d3.Clone(), MOJO_HANDLE_RIGHT_NONE),
-                              Handle(d4.Clone(), MOJO_HANDLE_RIGHT_NONE));
+  // Adding |h3| and |h4| as a pair should also fail.
+  auto hp2 = ht.AddHandlePair(h3.Clone(), h4.Clone());
   EXPECT_EQ(MOJO_HANDLE_INVALID, hp2.first);
   EXPECT_EQ(MOJO_HANDLE_INVALID, hp2.second);
 
-  // Remove |h2|/|d2|.
-  RefPtr<Dispatcher> d;
-  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h2, &d));
-  ASSERT_EQ(d2, d);
+  // Remove |hv2|/|h2|.
+  Handle h;
+  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv2, &h));
+  ASSERT_EQ(h2, h);
 
-  // Trying to add |d3| and |d4| as a pair should still fail.
-  hp2 = ht.AddHandlePair(Handle(d3.Clone(), MOJO_HANDLE_RIGHT_NONE),
-                         Handle(d4.Clone(), MOJO_HANDLE_RIGHT_NONE));
+  // Trying to add |h3| and |h4| as a pair should still fail.
+  hp2 = ht.AddHandlePair(h3.Clone(), h4.Clone());
   EXPECT_EQ(MOJO_HANDLE_INVALID, hp2.first);
   EXPECT_EQ(MOJO_HANDLE_INVALID, hp2.second);
 
-  // Remove |h1|/|d1|.
-  d = nullptr;
-  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h1, &d));
-  ASSERT_EQ(d1, d);
+  // Remove |hv1|/|h1|.
+  h.reset();
+  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv1, &h));
+  ASSERT_EQ(h1, h);
 
-  // Add |d3| and |d4| as a pair should now succeed fail.
-  hp2 = ht.AddHandlePair(Handle(d3.Clone(), MOJO_HANDLE_RIGHT_NONE),
-                         Handle(d4.Clone(), MOJO_HANDLE_RIGHT_NONE));
-  auto h3 = hp2.first;
-  auto h4 = hp2.second;
-  ASSERT_NE(h3, MOJO_HANDLE_INVALID);
-  ASSERT_NE(h4, MOJO_HANDLE_INVALID);
-  ASSERT_NE(h3, h4);
+  // Add |h3| and |h4| as a pair should now succeed fail.
+  hp2 = ht.AddHandlePair(h3.Clone(), h4.Clone());
+  auto hv3 = hp2.first;
+  auto hv4 = hp2.second;
+  ASSERT_NE(hv3, MOJO_HANDLE_INVALID);
+  ASSERT_NE(hv4, MOJO_HANDLE_INVALID);
+  ASSERT_NE(hv3, hv4);
 
-  d = nullptr;
-  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h3, &d));
-  ASSERT_EQ(d3, d);
+  h.reset();
+  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv3, &h));
+  ASSERT_EQ(h3, h);
 
-  d = nullptr;
-  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h4, &d));
-  ASSERT_EQ(d4, d);
+  h.reset();
+  ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv4, &h));
+  ASSERT_EQ(h4, h);
 
-  EXPECT_EQ(MOJO_RESULT_OK, d1->Close());
-  EXPECT_EQ(MOJO_RESULT_OK, d2->Close());
-  EXPECT_EQ(MOJO_RESULT_OK, d3->Close());
-  EXPECT_EQ(MOJO_RESULT_OK, d4->Close());
+  EXPECT_EQ(MOJO_RESULT_OK, h1.dispatcher->Close());
+  EXPECT_EQ(MOJO_RESULT_OK, h2.dispatcher->Close());
+  EXPECT_EQ(MOJO_RESULT_OK, h3.dispatcher->Close());
+  EXPECT_EQ(MOJO_RESULT_OK, h4.dispatcher->Close());
 }
 
 TEST(HandleTableTest, AddHandleVector) {
@@ -184,27 +188,26 @@
   HandleTable ht(1000u);
 
   HandleVector handles;
-  std::vector<RefPtr<Dispatcher>> dispatchers;
   for (size_t i = 0u; i < kNumHandles; i++) {
-    dispatchers.push_back(MakeRefCounted<test::MockSimpleDispatcher>());
-    handles.push_back(
-        Handle(dispatchers.back().Clone(), MOJO_HANDLE_RIGHT_NONE));
+    handles.push_back(Handle(MakeRefCounted<test::MockSimpleDispatcher>(),
+                             static_cast<MojoHandleRights>(i)));
     ASSERT_TRUE(handles[i]) << i;
   }
 
   std::vector<MojoHandle> handle_values(kNumHandles, MOJO_HANDLE_INVALID);
 
-  ASSERT_TRUE(ht.AddHandleVector(&handles, handle_values.data()));
+  HandleVector handles_copy = handles;
+  ASSERT_TRUE(ht.AddHandleVector(&handles_copy, handle_values.data()));
 
   for (size_t i = 0u; i < kNumHandles; i++) {
     ASSERT_NE(handle_values[i], MOJO_HANDLE_INVALID) << i;
+    EXPECT_FALSE(handles_copy[i]) << i;
 
-    RefPtr<Dispatcher> d;
-    ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(handle_values[i], &d))
-        << i;
-    ASSERT_EQ(dispatchers[i], d) << i;
+    Handle h;
+    ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(handle_values[i], &h)) << i;
+    ASSERT_EQ(handles[i], h) << i;
 
-    EXPECT_EQ(MOJO_RESULT_OK, dispatchers[i]->Close()) << i;
+    EXPECT_EQ(MOJO_RESULT_OK, handles[i].dispatcher->Close()) << i;
   }
 }
 
@@ -215,34 +218,33 @@
   HandleTable ht(kHandleTableSize);
 
   HandleVector handles;
-  std::vector<RefPtr<Dispatcher>> dispatchers;
   for (size_t i = 0u; i < kNumHandles; i++) {
-    dispatchers.push_back(MakeRefCounted<test::MockSimpleDispatcher>());
-    handles.push_back(
-        Handle(dispatchers.back().Clone(), MOJO_HANDLE_RIGHT_NONE));
+    handles.push_back(Handle(MakeRefCounted<test::MockSimpleDispatcher>(),
+                             static_cast<MojoHandleRights>(i)));
     ASSERT_TRUE(handles[i]) << i;
   }
 
   std::vector<MojoHandle> handle_values(kNumHandles, MOJO_HANDLE_INVALID);
 
-  EXPECT_FALSE(ht.AddHandleVector(&handles, handle_values.data()));
+  HandleVector handles_copy = handles;
+  EXPECT_FALSE(ht.AddHandleVector(&handles_copy, handle_values.data()));
 
-  handles.pop_back();
+  handles_copy.pop_back();
   handle_values.pop_back();
 
-  ASSERT_TRUE(ht.AddHandleVector(&handles, handle_values.data()));
+  ASSERT_TRUE(ht.AddHandleVector(&handles_copy, handle_values.data()));
 
   for (size_t i = 0u; i < kNumHandles - 1u; i++) {
     ASSERT_NE(handle_values[i], MOJO_HANDLE_INVALID) << i;
+    EXPECT_FALSE(handles_copy[i]) << i;
 
-    RefPtr<Dispatcher> d;
-    ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(handle_values[i], &d))
-        << i;
-    ASSERT_EQ(dispatchers[i], d) << i;
+    Handle h;
+    ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(handle_values[i], &h)) << i;
+    ASSERT_EQ(handles[i], h) << i;
   }
 
   for (size_t i = 0u; i < kNumHandles; i++)
-    EXPECT_EQ(MOJO_RESULT_OK, dispatchers[i]->Close()) << i;
+    EXPECT_EQ(MOJO_RESULT_OK, handles[i].dispatcher->Close()) << i;
 }
 
 }  // namespace