Hold intern table lock for AddImageStringsToTable

Fixes a correctness issue where another thread adding an intern string
after the visitor could cause duplicate strings.

Reduces how often the intern table lock is acquired, probably
improving performance.

Bug: 116059983
Test: test-art-host

Change-Id: I5ba6ca3ba7535de6d4ad5cb46750bd23a6e9aadc
diff --git a/runtime/intern_table-inl.h b/runtime/intern_table-inl.h
index 8c7fb42..84754fa 100644
--- a/runtime/intern_table-inl.h
+++ b/runtime/intern_table-inl.h
@@ -39,11 +39,15 @@
 inline size_t InternTable::AddTableFromMemory(const uint8_t* ptr, const Visitor& visitor) {
   size_t read_count = 0;
   UnorderedSet set(ptr, /*make copy*/false, &read_count);
-  // Visit the unordered set, may remove elements.
-  visitor(set);
-  if (!set.empty()) {
+  {
+    // Hold the lock while calling the visitor to prevent possible race
+    // conditions with another thread adding intern strings.
     MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
-    strong_interns_.AddInternStrings(std::move(set));
+    // Visit the unordered set, may remove elements.
+    visitor(set);
+    if (!set.empty()) {
+      strong_interns_.AddInternStrings(std::move(set));
+    }
   }
   return read_count;
 }