diff options
| author | 2017-01-06 23:03:37 +0000 | |
|---|---|---|
| committer | 2017-01-06 23:03:38 +0000 | |
| commit | 1b2f6c36c7aea739f048733ca93927e4b3a143c7 (patch) | |
| tree | 6729e3faee09b7ddae446e9706d64abd7e9566f4 | |
| parent | 2c5315bf01a432a8ba31a6f3b0f9894529d3cdbf (diff) | |
| parent | 64013e5b5a57761d9a6767b9b03ff4f15fac51c2 (diff) | |
Merge changes Ia14276d3,I7f063806
* changes:
ART: Add GetClassModifiers
ART: Add GetClassMethods
| -rw-r--r-- | runtime/openjdkjvmti/OpenjdkJvmTi.cc | 4 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_class.cc | 80 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_class.h | 7 | ||||
| -rw-r--r-- | test/912-classes/classes.cc | 37 | ||||
| -rw-r--r-- | test/912-classes/expected.txt | 10 | ||||
| -rw-r--r-- | test/912-classes/src/Main.java | 16 |
6 files changed, 151 insertions, 3 deletions
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc index 98c4c3a511..75c314f017 100644 --- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc +++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc @@ -546,14 +546,14 @@ class JvmtiFunctions { } 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 7b30a9da74..76d070c799 100644 --- a/runtime/openjdkjvmti/ti_class.cc +++ b/runtime/openjdkjvmti/ti_class.cc @@ -52,7 +52,6 @@ jvmtiError ClassUtil::GetClassFields(jvmtiEnv* env, 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 @@ jvmtiError ClassUtil::GetClassFields(jvmtiEnv* env, 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 @@ jvmtiError ClassUtil::IsArrayClass(jvmtiEnv* env ATTRIBUTE_UNUSED, 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 5ee64be77a..619f50e15e 100644 --- a/runtime/openjdkjvmti/ti_class.h +++ b/runtime/openjdkjvmti/ti_class.h @@ -44,6 +44,13 @@ class ClassUtil { 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 28c5931521..3383d04319 100644 --- a/test/912-classes/classes.cc +++ b/test/912-classes/classes.cc @@ -87,6 +87,19 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_isArrayClass( 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 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassFields( 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 44fed795ad..de23b7bc4d 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 @@ java.lang.String interface=false array=false [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 0b41113410..cbcfe71aa6 100644 --- a/test/912-classes/src/Main.java +++ b/test/912-classes/src/Main.java @@ -48,6 +48,10 @@ public class Main { 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 @@ public class Main { 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 @@ public class Main { 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 @@ public class Main { 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); |