ART: Add heap iteration callback

Add callback support for heap iteration. Visiting of fields will
be done in a follow-up.

Add a test.

Bug: 31385354
Test: m test-art-host-run-test-906-iterate-heap
Test: m ART_TEST_GC_STRESS=true ART_TEST_GC_VERIFY=true test-art-host-run-test-906-iterate-heap
Change-Id: I7bcf6751e6df4ef58756ba97701050b2ff5eb07b
diff --git a/runtime/openjdkjvmti/object_tagging.cc b/runtime/openjdkjvmti/object_tagging.cc
index bb17cac..29d4830 100644
--- a/runtime/openjdkjvmti/object_tagging.cc
+++ b/runtime/openjdkjvmti/object_tagging.cc
@@ -87,6 +87,33 @@
   return false;
 }
 
+bool ObjectTagTable::Set(art::mirror::Object* obj, jlong new_tag) {
+  art::Thread* self = art::Thread::Current();
+  art::MutexLock mu(self, allow_disallow_lock_);
+  Wait(self);
+
+  for (auto& pair : tagged_objects_) {
+    if (pair.first.Read(nullptr) == obj) {
+      pair.second = new_tag;
+      return true;
+    }
+  }
+
+  // TODO refactor with Add.
+  if (first_free_ == tagged_objects_.size()) {
+    tagged_objects_.push_back(Entry(art::GcRoot<art::mirror::Object>(obj), new_tag));
+    first_free_++;
+  } else {
+    DCHECK_LT(first_free_, tagged_objects_.size());
+    DCHECK(tagged_objects_[first_free_].first.IsNull());
+    tagged_objects_[first_free_] = Entry(art::GcRoot<art::mirror::Object>(obj), new_tag);
+    // TODO: scan for free elements.
+    first_free_ = tagged_objects_.size();
+  }
+
+  return false;
+}
+
 void ObjectTagTable::Sweep(art::IsMarkedVisitor* visitor) {
   if (event_handler_->IsEventEnabledAnywhere(JVMTI_EVENT_OBJECT_FREE)) {
     SweepImpl<true>(visitor);