Add GetSourceFile and GetSourceDebugExt JVMTI functions

Also add associated capabilities.

Test: ./test.py --host -j40
Bug: 62821960

Change-Id: Icc534b2789287fc9f0daddb747c0c0fa81a7728b
diff --git a/test/ti-stress/stress.cc b/test/ti-stress/stress.cc
index 8d4cc89..40fcc4f 100644
--- a/test/ti-stress/stress.cc
+++ b/test/ti-stress/stress.cc
@@ -128,12 +128,16 @@
       : jvmtienv_(jvmtienv),
         class_(c),
         name_(nullptr),
-        generic_(nullptr) {}
+        generic_(nullptr),
+        file_(nullptr),
+        debug_ext_(nullptr) {}
 
   ~ScopedClassInfo() {
     if (class_ != nullptr) {
       jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
       jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
+      jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(file_));
+      jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(debug_ext_));
     }
   }
 
@@ -143,7 +147,13 @@
       generic_ = const_cast<char*>("<NONE>");
       return true;
     } else {
-      return jvmtienv_->GetClassSignature(class_, &name_, &generic_) == JVMTI_ERROR_NONE;
+      jvmtiError ret1 = jvmtienv_->GetSourceFileName(class_, &file_);
+      jvmtiError ret2 = jvmtienv_->GetSourceDebugExtension(class_, &debug_ext_);
+      return jvmtienv_->GetClassSignature(class_, &name_, &generic_) == JVMTI_ERROR_NONE &&
+          ret1 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
+          ret1 != JVMTI_ERROR_INVALID_CLASS &&
+          ret2 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
+          ret2 != JVMTI_ERROR_INVALID_CLASS;
     }
   }
 
@@ -156,12 +166,28 @@
   const char* GetGeneric() const {
     return generic_;
   }
+  const char* GetSourceDebugExtension() const {
+    if (debug_ext_ == nullptr) {
+      return "<UNKNOWN_SOURCE_DEBUG_EXTENSION>";
+    } else {
+      return debug_ext_;
+    }
+  }
+  const char* GetSourceFileName() const {
+    if (file_ == nullptr) {
+      return "<UNKNOWN_FILE>";
+    } else {
+      return file_;
+    }
+  }
 
  private:
   jvmtiEnv* jvmtienv_;
   jclass class_;
   char* name_;
   char* generic_;
+  char* file_;
+  char* debug_ext_;
 };
 
 class ScopedMethodInfo {
@@ -174,7 +200,8 @@
         class_info_(nullptr),
         name_(nullptr),
         signature_(nullptr),
-        generic_(nullptr) {}
+        generic_(nullptr),
+        first_line_(-1) {}
 
   ~ScopedMethodInfo() {
     env_->DeleteLocalRef(declaring_class_);
@@ -188,6 +215,18 @@
       return false;
     }
     class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
+    jint nlines;
+    jvmtiLineNumberEntry* lines;
+    jvmtiError err = jvmtienv_->GetLineNumberTable(method_, &nlines, &lines);
+    if (err == JVMTI_ERROR_NONE) {
+      if (nlines > 0) {
+        first_line_ = lines[0].line_number;
+      }
+      jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(lines));
+    } else if (err != JVMTI_ERROR_ABSENT_INFORMATION &&
+               err != JVMTI_ERROR_NATIVE_METHOD) {
+      return false;
+    }
     return class_info_->Init() &&
         (jvmtienv_->GetMethodName(method_, &name_, &signature_, &generic_) == JVMTI_ERROR_NONE);
   }
@@ -212,6 +251,10 @@
     return generic_;
   }
 
+  jint GetFirstLine() const {
+    return first_line_;
+  }
+
  private:
   jvmtiEnv* jvmtienv_;
   JNIEnv* env_;
@@ -221,6 +264,7 @@
   char* name_;
   char* signature_;
   char* generic_;
+  jint first_line_;
 
   friend std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m);
 };
@@ -295,7 +339,9 @@
 }
 
 std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m) {
-  return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature();
+  return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature()
+            << " (source: " << m.GetDeclaringClassInfo().GetSourceFileName() << ":"
+            << m.GetFirstLine() << ")";
 }
 
 static void doJvmtiMethodBind(jvmtiEnv* jvmtienv,