ART: Add Thread TLS support

Add support for GetThreadLocalStorage and SetThreadLocalStorage.
Add test.

Bug: 31684593
Test: m test-art-host-run-test-924-threads
Change-Id: Ia2e567a832716b076a61664809ab29290fffcb70
diff --git a/runtime/openjdkjvmti/ti_thread.cc b/runtime/openjdkjvmti/ti_thread.cc
index f7f63bd..2bcdd8c 100644
--- a/runtime/openjdkjvmti/ti_thread.cc
+++ b/runtime/openjdkjvmti/ti_thread.cc
@@ -35,11 +35,14 @@
 #include "art_jvmti.h"
 #include "base/logging.h"
 #include "base/mutex.h"
+#include "gc/system_weak.h"
+#include "gc_root-inl.h"
 #include "jni_internal.h"
 #include "mirror/class.h"
 #include "mirror/object-inl.h"
 #include "mirror/string.h"
 #include "obj_ptr.h"
+#include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "thread_list.h"
@@ -400,7 +403,43 @@
     *threads_count_ptr = static_cast<jint>(peers.size());
     *threads_ptr = threads;
   }
+  return ERR(NONE);
+}
 
+jvmtiError ThreadUtil::SetThreadLocalStorage(jvmtiEnv* env ATTRIBUTE_UNUSED,
+                                             jthread thread,
+                                             const void* data) {
+  art::ScopedObjectAccess soa(art::Thread::Current());
+  art::Thread* self = GetNativeThread(thread, soa);
+  if (self == nullptr && thread == nullptr) {
+    return ERR(INVALID_THREAD);
+  }
+  if (self == nullptr) {
+    return ERR(THREAD_NOT_ALIVE);
+  }
+
+  self->SetCustomTLS(data);
+
+  return ERR(NONE);
+}
+
+jvmtiError ThreadUtil::GetThreadLocalStorage(jvmtiEnv* env ATTRIBUTE_UNUSED,
+                                             jthread thread,
+                                             void** data_ptr) {
+  if (data_ptr == nullptr) {
+    return ERR(NULL_POINTER);
+  }
+
+  art::ScopedObjectAccess soa(art::Thread::Current());
+  art::Thread* self = GetNativeThread(thread, soa);
+  if (self == nullptr && thread == nullptr) {
+    return ERR(INVALID_THREAD);
+  }
+  if (self == nullptr) {
+    return ERR(THREAD_NOT_ALIVE);
+  }
+
+  *data_ptr = const_cast<void*>(self->GetCustomTLS());
   return ERR(NONE);
 }
 
diff --git a/runtime/openjdkjvmti/ti_thread.h b/runtime/openjdkjvmti/ti_thread.h
index fca42ad..290e9d4 100644
--- a/runtime/openjdkjvmti/ti_thread.h
+++ b/runtime/openjdkjvmti/ti_thread.h
@@ -46,6 +46,9 @@
   static jvmtiError GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr);
 
   static jvmtiError GetThreadState(jvmtiEnv* env, jthread thread, jint* thread_state_ptr);
+
+  static jvmtiError SetThreadLocalStorage(jvmtiEnv* env, jthread thread, const void* data);
+  static jvmtiError GetThreadLocalStorage(jvmtiEnv* env, jthread thread, void** data_ptr);
 };
 
 }  // namespace openjdkjvmti
diff --git a/runtime/thread.h b/runtime/thread.h
index d54a80d..3958c10 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -1140,6 +1140,14 @@
     return debug_disallow_read_barrier_;
   }
 
+  const void* GetCustomTLS() const {
+    return custom_tls_;
+  }
+
+  void SetCustomTLS(const void* data) {
+    custom_tls_ = data;
+  }
+
   // Returns true if the current thread is the jit sensitive thread.
   bool IsJitSensitiveThread() const {
     return this == jit_sensitive_thread_;
@@ -1600,6 +1608,10 @@
   // Pending extra checkpoints if checkpoint_function_ is already used.
   std::list<Closure*> checkpoint_overflow_ GUARDED_BY(Locks::thread_suspend_count_lock_);
 
+  // Custom TLS field that can be used by plugins.
+  // TODO: Generalize once we have more plugins.
+  const void* custom_tls_;
+
   // True if the thread is allowed to call back into java (for e.g. during class resolution).
   // By default this is true.
   bool can_call_into_java_;