Merge changes Ia14276d3,I7f063806

* changes:
  ART: Add GetClassModifiers
  ART: Add GetClassMethods
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 98c4c3a..75c314f 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -546,14 +546,14 @@
   }
 
   static jvmtiError GetClassModifiers(jvmtiEnv* env, jclass klass, jint* modifiers_ptr) {
-    return ERR(NOT_IMPLEMENTED);
+    return ClassUtil::GetClassModifiers(env, klass, modifiers_ptr);
   }
 
   static jvmtiError GetClassMethods(jvmtiEnv* env,
                                     jclass klass,
                                     jint* method_count_ptr,
                                     jmethodID** methods_ptr) {
-    return ERR(NOT_IMPLEMENTED);
+    return ClassUtil::GetClassMethods(env, klass, method_count_ptr, methods_ptr);
   }
 
   static jvmtiError GetClassFields(jvmtiEnv* env,
diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc
index 7b30a9d..76d070c 100644
--- a/runtime/openjdkjvmti/ti_class.cc
+++ b/runtime/openjdkjvmti/ti_class.cc
@@ -52,7 +52,6 @@
     return ERR(NULL_POINTER);
   }
 
-  art::StackHandleScope<1> hs(soa.Self());
   art::IterationRange<art::StrideIterator<art::ArtField>> ifields = klass->GetIFields();
   art::IterationRange<art::StrideIterator<art::ArtField>> sfields = klass->GetSFields();
   size_t array_size = klass->NumInstanceFields() + klass->NumStaticFields();
@@ -80,6 +79,49 @@
   return ERR(NONE);
 }
 
+jvmtiError ClassUtil::GetClassMethods(jvmtiEnv* env,
+                                      jclass jklass,
+                                      jint* method_count_ptr,
+                                      jmethodID** methods_ptr) {
+  art::ScopedObjectAccess soa(art::Thread::Current());
+  art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
+  if (klass == nullptr) {
+    return ERR(INVALID_CLASS);
+  }
+
+  if (method_count_ptr == nullptr || methods_ptr == nullptr) {
+    return ERR(NULL_POINTER);
+  }
+
+  size_t array_size = klass->NumDeclaredVirtualMethods() + klass->NumDirectMethods();
+  unsigned char* out_ptr;
+  jvmtiError allocError = env->Allocate(array_size * sizeof(jmethodID), &out_ptr);
+  if (allocError != ERR(NONE)) {
+    return allocError;
+  }
+  jmethodID* method_array = reinterpret_cast<jmethodID*>(out_ptr);
+
+  if (art::kIsDebugBuild) {
+    size_t count = 0;
+    for (auto& m ATTRIBUTE_UNUSED : klass->GetDeclaredMethods(art::kRuntimePointerSize)) {
+      count++;
+    }
+    CHECK_EQ(count, klass->NumDirectMethods() + klass->NumDeclaredVirtualMethods());
+  }
+
+  size_t array_idx = 0;
+  for (auto& m : klass->GetDeclaredMethods(art::kRuntimePointerSize)) {
+    method_array[array_idx] = art::jni::EncodeArtMethod(&m);
+    ++array_idx;
+  }
+
+  *method_count_ptr = static_cast<jint>(array_size);
+  *methods_ptr = method_array;
+
+  return ERR(NONE);
+}
+
+
 jvmtiError ClassUtil::GetClassSignature(jvmtiEnv* env,
                                          jclass jklass,
                                          char** signature_ptr,
@@ -182,4 +224,40 @@
   return ClassIsT(jklass, test, is_array_class_ptr);
 }
 
+// Keep this in sync with Class.getModifiers().
+static uint32_t ClassGetModifiers(art::Thread* self, art::ObjPtr<art::mirror::Class> klass)
+    REQUIRES_SHARED(art::Locks::mutator_lock_) {
+  if (klass->IsArrayClass()) {
+    uint32_t component_modifiers = ClassGetModifiers(self, klass->GetComponentType());
+    if ((component_modifiers & art::kAccInterface) != 0) {
+      component_modifiers &= ~(art::kAccInterface | art::kAccStatic);
+    }
+    return art::kAccAbstract | art::kAccFinal | component_modifiers;
+  }
+
+  uint32_t modifiers = klass->GetAccessFlags() & art::kAccJavaFlagsMask;
+
+  art::StackHandleScope<1> hs(self);
+  art::Handle<art::mirror::Class> h_klass(hs.NewHandle(klass));
+  return art::mirror::Class::GetInnerClassFlags(h_klass, modifiers);
+}
+
+jvmtiError ClassUtil::GetClassModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
+                                        jclass jklass,
+                                        jint* modifiers_ptr) {
+  art::ScopedObjectAccess soa(art::Thread::Current());
+  art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
+  if (klass == nullptr) {
+    return ERR(INVALID_CLASS);
+  }
+
+  if (modifiers_ptr == nullptr) {
+    return ERR(NULL_POINTER);
+  }
+
+  *modifiers_ptr = ClassGetModifiers(soa.Self(), klass);
+
+  return ERR(NONE);
+}
+
 }  // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_class.h b/runtime/openjdkjvmti/ti_class.h
index 5ee64be..619f50e 100644
--- a/runtime/openjdkjvmti/ti_class.h
+++ b/runtime/openjdkjvmti/ti_class.h
@@ -44,6 +44,13 @@
                                    jint* field_count_ptr,
                                    jfieldID** fields_ptr);
 
+  static jvmtiError GetClassMethods(jvmtiEnv* env,
+                                    jclass klass,
+                                    jint* method_count_ptr,
+                                    jmethodID** methods_ptr);
+
+  static jvmtiError GetClassModifiers(jvmtiEnv* env, jclass klass, jint* modifiers_ptr);
+
   static jvmtiError GetClassSignature(jvmtiEnv* env,
                                       jclass klass,
                                       char** signature_ptr,
diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc
index 28c5931..3383d04 100644
--- a/test/912-classes/classes.cc
+++ b/test/912-classes/classes.cc
@@ -87,6 +87,19 @@
   return is_array_class;
 }
 
+extern "C" JNIEXPORT jint JNICALL Java_Main_getClassModifiers(
+    JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+  jint mod;
+  jvmtiError result = jvmti_env->GetClassModifiers(klass, &mod);
+  if (result != JVMTI_ERROR_NONE) {
+    char* err;
+    jvmti_env->GetErrorName(result, &err);
+    printf("Failure running GetClassModifiers: %s\n", err);
+    return JNI_FALSE;
+  }
+  return mod;
+}
+
 extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassFields(
     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
   jint count = 0;
@@ -111,6 +124,30 @@
   return CreateObjectArray(env, count, "java/lang/Object", callback);
 }
 
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassMethods(
+    JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+  jint count = 0;
+  jmethodID* methods = nullptr;
+  jvmtiError result = jvmti_env->GetClassMethods(klass, &count, &methods);
+  if (result != JVMTI_ERROR_NONE) {
+    char* err;
+    jvmti_env->GetErrorName(result, &err);
+    printf("Failure running GetClassMethods: %s\n", err);
+    return nullptr;
+  }
+
+  auto callback = [&](jint i) {
+    jint modifiers;
+    // Ignore any errors for simplicity.
+    jvmti_env->GetMethodModifiers(methods[i], &modifiers);
+    constexpr jint kStatic = 0x8;
+    return env->ToReflectedMethod(klass,
+                                  methods[i],
+                                  (modifiers & kStatic) != 0 ? JNI_TRUE : JNI_FALSE);
+  };
+  return CreateObjectArray(env, count, "java/lang/Object", callback);
+}
+
 extern "C" JNIEXPORT jint JNICALL Java_Main_getClassStatus(
     JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
   jint status;
diff --git a/test/912-classes/expected.txt b/test/912-classes/expected.txt
index 44fed79..de23b7b 100644
--- a/test/912-classes/expected.txt
+++ b/test/912-classes/expected.txt
@@ -1,10 +1,17 @@
 [Ljava/lang/Object;, null]
+1
 [Ljava/lang/String;, null]
+11
 [Ljava/lang/Math;, null]
+11
 [Ljava/util/List;, null]
+601
 [L$Proxy0;, null]
+11
 [I, null]
+411
 [[D, null]
+411
 int interface=false array=false
 $Proxy0 interface=false array=false
 java.lang.Runnable interface=true array=false
@@ -15,6 +22,9 @@
 [public static final int java.lang.Integer.BYTES, static final char[] java.lang.Integer.DigitOnes, static final char[] java.lang.Integer.DigitTens, public static final int java.lang.Integer.MAX_VALUE, public static final int java.lang.Integer.MIN_VALUE, public static final int java.lang.Integer.SIZE, private static final java.lang.String[] java.lang.Integer.SMALL_NEG_VALUES, private static final java.lang.String[] java.lang.Integer.SMALL_NONNEG_VALUES, public static final java.lang.Class java.lang.Integer.TYPE, static final char[] java.lang.Integer.digits, private static final long java.lang.Integer.serialVersionUID, static final int[] java.lang.Integer.sizeTable, private final int java.lang.Integer.value]
 []
 []
+[java.lang.Integer(), public java.lang.Integer(int), public java.lang.Integer(java.lang.String) throws java.lang.NumberFormatException, public static int java.lang.Integer.bitCount(int), public static int java.lang.Integer.compare(int,int), public static int java.lang.Integer.compareUnsigned(int,int), public static java.lang.Integer java.lang.Integer.decode(java.lang.String) throws java.lang.NumberFormatException, public static int java.lang.Integer.divideUnsigned(int,int), static int java.lang.Integer.formatUnsignedInt(int,int,char[],int,int), static void java.lang.Integer.getChars(int,int,char[]), public static java.lang.Integer java.lang.Integer.getInteger(java.lang.String), public static java.lang.Integer java.lang.Integer.getInteger(java.lang.String,int), public static java.lang.Integer java.lang.Integer.getInteger(java.lang.String,java.lang.Integer), public static int java.lang.Integer.hashCode(int), public static int java.lang.Integer.highestOneBit(int), public static int java.lang.Integer.lowestOneBit(int), public static int java.lang.Integer.max(int,int), public static int java.lang.Integer.min(int,int), public static int java.lang.Integer.numberOfLeadingZeros(int), public static int java.lang.Integer.numberOfTrailingZeros(int), public static int java.lang.Integer.parseInt(java.lang.String) throws java.lang.NumberFormatException, public static int java.lang.Integer.parseInt(java.lang.String,int) throws java.lang.NumberFormatException, public static int java.lang.Integer.parseUnsignedInt(java.lang.String) throws java.lang.NumberFormatException, public static int java.lang.Integer.parseUnsignedInt(java.lang.String,int) throws java.lang.NumberFormatException, public static int java.lang.Integer.remainderUnsigned(int,int), public static int java.lang.Integer.reverse(int), public static int java.lang.Integer.reverseBytes(int), public static int java.lang.Integer.rotateLeft(int,int), public static int java.lang.Integer.rotateRight(int,int), public static int java.lang.Integer.signum(int), static int java.lang.Integer.stringSize(int), public static int java.lang.Integer.sum(int,int), public static java.lang.String java.lang.Integer.toBinaryString(int), public static java.lang.String java.lang.Integer.toHexString(int), public static java.lang.String java.lang.Integer.toOctalString(int), public static java.lang.String java.lang.Integer.toString(int), public static java.lang.String java.lang.Integer.toString(int,int), public static long java.lang.Integer.toUnsignedLong(int), public static java.lang.String java.lang.Integer.toUnsignedString(int), public static java.lang.String java.lang.Integer.toUnsignedString(int,int), private static java.lang.String java.lang.Integer.toUnsignedString0(int,int), public static java.lang.Integer java.lang.Integer.valueOf(int), public static java.lang.Integer java.lang.Integer.valueOf(java.lang.String) throws java.lang.NumberFormatException, public static java.lang.Integer java.lang.Integer.valueOf(java.lang.String,int) throws java.lang.NumberFormatException, public byte java.lang.Integer.byteValue(), public int java.lang.Integer.compareTo(java.lang.Integer), public int java.lang.Integer.compareTo(java.lang.Object), public double java.lang.Integer.doubleValue(), public boolean java.lang.Integer.equals(java.lang.Object), public float java.lang.Integer.floatValue(), public int java.lang.Integer.hashCode(), public int java.lang.Integer.intValue(), public long java.lang.Integer.longValue(), public short java.lang.Integer.shortValue(), public java.lang.String java.lang.Integer.toString()]
+[]
+[]
 int 100000
 class [Ljava.lang.String; 10000
 class java.lang.Object 111
diff --git a/test/912-classes/src/Main.java b/test/912-classes/src/Main.java
index 0b41113..cbcfe71 100644
--- a/test/912-classes/src/Main.java
+++ b/test/912-classes/src/Main.java
@@ -48,6 +48,10 @@
     testClassFields(int.class);
     testClassFields(String[].class);
 
+    testClassMethods(Integer.class);
+    testClassMethods(int.class);
+    testClassMethods(String[].class);
+
     testClassStatus(int.class);
     testClassStatus(String[].class);
     testClassStatus(Object.class);
@@ -78,6 +82,11 @@
   private static void testClass(Class<?> base) throws Exception {
     String[] result = getClassSignature(base);
     System.out.println(Arrays.toString(result));
+    int mod = getClassModifiers(base);
+    if (mod != base.getModifiers()) {
+      throw new RuntimeException("Unexpected modifiers: " + base.getModifiers() + " vs " + mod);
+    }
+    System.out.println(Integer.toHexString(mod));
   }
 
   private static void testClassType(Class<?> c) throws Exception {
@@ -90,6 +99,10 @@
     System.out.println(Arrays.toString(getClassFields(c)));
   }
 
+  private static void testClassMethods(Class<?> c) throws Exception {
+    System.out.println(Arrays.toString(getClassMethods(c)));
+  }
+
   private static void testClassStatus(Class<?> c) {
     System.out.println(c + " " + Integer.toBinaryString(getClassStatus(c)));
   }
@@ -99,7 +112,10 @@
   private static native boolean isInterface(Class<?> c);
   private static native boolean isArrayClass(Class<?> c);
 
+  private static native int getClassModifiers(Class<?> c);
+
   private static native Object[] getClassFields(Class<?> c);
+  private static native Object[] getClassMethods(Class<?> c);
 
   private static native int getClassStatus(Class<?> c);