Merge "Ensure GetThreadState works with Thread subtypes"
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index d437e52..da1c1bc 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -484,13 +484,18 @@
   }
 
   art::ScopedObjectAccess soa(self);
+  art::StackHandleScope<1> hs(self);
 
   // Need to read the Java "started" field to know whether this is starting or terminated.
-  art::ObjPtr<art::mirror::Object> peer = soa.Decode<art::mirror::Object>(thread);
-  art::ObjPtr<art::mirror::Class> klass = peer->GetClass();
-  art::ArtField* started_field = klass->FindDeclaredInstanceField("started", "Z");
+  art::Handle<art::mirror::Object> peer(hs.NewHandle(soa.Decode<art::mirror::Object>(thread)));
+  art::ObjPtr<art::mirror::Class> thread_klass =
+      soa.Decode<art::mirror::Class>(art::WellKnownClasses::java_lang_Thread);
+  if (!thread_klass->IsAssignableFrom(peer->GetClass())) {
+    return ERR(INVALID_THREAD);
+  }
+  art::ArtField* started_field = thread_klass->FindDeclaredInstanceField("started", "Z");
   CHECK(started_field != nullptr);
-  bool started = started_field->GetBoolean(peer) != 0;
+  bool started = started_field->GetBoolean(peer.Get()) != 0;
   constexpr jint kStartedState = JVMTI_JAVA_LANG_THREAD_STATE_NEW;
   constexpr jint kTerminatedState = JVMTI_THREAD_STATE_TERMINATED |
                                     JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED;
diff --git a/test/924-threads/expected.txt b/test/924-threads/expected.txt
index 1eb2e1b..e529559 100644
--- a/test/924-threads/expected.txt
+++ b/test/924-threads/expected.txt
@@ -26,6 +26,15 @@
 class dalvik.system.PathClassLoader
 5
 5
+Thread type is class java.lang.Thread
+0 = NEW
+191 = ALIVE|WAITING_INDEFINITELY|WAITING|IN_OBJECT_WAIT
+1a1 = ALIVE|WAITING_WITH_TIMEOUT|WAITING|IN_OBJECT_WAIT
+401 = ALIVE|BLOCKED_ON_MONITOR_ENTER
+e1 = ALIVE|WAITING_WITH_TIMEOUT|SLEEPING|WAITING
+5 = ALIVE|RUNNABLE
+2 = TERMINATED
+Thread type is class art.Test924$ExtThread
 0 = NEW
 191 = ALIVE|WAITING_INDEFINITELY|WAITING|IN_OBJECT_WAIT
 1a1 = ALIVE|WAITING_WITH_TIMEOUT|WAITING|IN_OBJECT_WAIT
diff --git a/test/924-threads/src/art/Test924.java b/test/924-threads/src/art/Test924.java
index b73eb30..1ff2c3f 100644
--- a/test/924-threads/src/art/Test924.java
+++ b/test/924-threads/src/art/Test924.java
@@ -21,6 +21,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.concurrent.CountDownLatch;
+import java.util.function.Function;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -76,7 +77,9 @@
     };
     printThreadInfo(t4);
 
-    doStateTests();
+    doCurrentThreadStateTests();
+    doStateTests(Thread::new);
+    doStateTests(ExtThread::new);
 
     doAllThreadsTests();
 
@@ -85,14 +88,20 @@
     doTestEvents();
   }
 
+  private static final class ExtThread extends Thread {
+    public ExtThread(Runnable r) { super(r); }
+  }
+
   private static class Holder {
     volatile boolean flag = false;
   }
 
-  private static void doStateTests() throws Exception {
+  private static void doCurrentThreadStateTests() throws Exception {
     System.out.println(Integer.toHexString(getThreadState(null)));
     System.out.println(Integer.toHexString(getThreadState(Thread.currentThread())));
+  }
 
+  private static void doStateTests(Function<Runnable, Thread> mkThread) throws Exception {
     final CountDownLatch cdl1 = new CountDownLatch(1);
     final CountDownLatch cdl2 = new CountDownLatch(1);
     final CountDownLatch cdl3_1 = new CountDownLatch(1);
@@ -133,7 +142,8 @@
       }
     };
 
-    Thread t = new Thread(r);
+    Thread t = mkThread.apply(r);
+    System.out.println("Thread type is " + t.getClass());
     printThreadState(t);
     t.start();