static jobjectArray get_class_declared_methods_helper(
JNIEnv *env,
jclass ofClass, jboolean publicOnly,
bool want_constructor,
Klass* klass, TRAPS) {
JvmtiVMObjectAllocEventCollector oam;
// Exclude primitive types and array types
if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass))
|| java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->oop_is_array()) {
// Return empty array
oop res = oopFactory::new_objArray(klass, 0, CHECK_NULL);
return (jobjectArray) JNIHandles::make_local(env, res);
}
instanceKlassHandle k(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass)));
// Ensure class is linked
k->link_class(CHECK_NULL);
Array<Method*>* methods = k->methods();
int methods_length = methods->length();
// Save original method_idnum in case of redefinition, which can change
// the idnum of obsolete methods. The new method will have the same idnum
// but if we refresh the methods array, the counts will be wrong.
ResourceMark rm(THREAD);
GrowableArray<int>* idnums = new GrowableArray<int>(methods_length);
int num_methods = 0;
for (int i = 0; i < methods_length; i++) {
methodHandle method(THREAD, methods->at(i));
if (select_method(method, want_constructor)) {
if (!publicOnly || method->is_public()) {
idnums->push(method->method_idnum());
++num_methods;
}
}
}
// Allocate result
objArrayOop r = oopFactory::new_objArray(klass, num_methods, CHECK_NULL);
objArrayHandle result (THREAD, r);
// Now just put the methods that we selected above, but go by their idnum
// in case of redefinition. The methods can be redefined at any safepoint,
// so above when allocating the oop array and below when creating reflect
// objects.
for (int i = 0; i < num_methods; i++) {
methodHandle method(THREAD, k->method_with_idnum(idnums->at(i)));
if (method.is_null()) {
// Method may have been deleted and seems this API can handle null
// Otherwise should probably put a method that throws NSME
result->obj_at_put(i, NULL);
} else {
oop m;
if (want_constructor) {
m = Reflection::new_constructor(method, CHECK_NULL);
} else {
m = Reflection::new_method(method, UseNewReflection, false, CHECK_NULL);
}
result->obj_at_put(i, m);
}
}
return (jobjectArray) JNIHandles::make_local(env, result());
}
Method* InstanceKlass::method_with_idnum(int idnum) {
Method* m = NULL;
if (idnum < methods()->length()) {
m = methods()->at(idnum);
}
if (m == NULL || m->method_idnum() != idnum) {
for (int index = 0; index < methods()->length(); ++index) {
m = methods()->at(index);
if (m->method_idnum() == idnum) {
return m;
}
}
// None found, return null for the caller to handle.
return NULL;
}
return m;
}
intArray* ClassFileParser::sort_methods(Array<Method*>* methods) {
int length = methods->length();
// If JVMTI original method ordering or sharing is enabled we have to
// remember the original class file ordering.
// We temporarily use the vtable_index field in the Method* to store the
// class file index, so we can read in after calling qsort.
// Put the method ordering in the shared archive.
if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) {
for (int index = 0; index < length; index++) {
Method* m = methods->at(index);
assert(!m->valid_vtable_index(), "vtable index should not be set");
m->set_vtable_index(index);
}
}
// Sort method array by ascending method name (for faster lookups & vtable construction)
// Note that the ordering is not alphabetical, see Symbol::fast_compare
Method::sort_methods(methods);
intArray* method_ordering = NULL;
// If JVMTI original method ordering or sharing is enabled construct int
// array remembering the original ordering
if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) {
method_ordering = new intArray(length);
for (int index = 0; index < length; index++) {
Method* m = methods->at(index);
int old_index = m->vtable_index();
assert(old_index >= 0 && old_index < length, "invalid method index");
method_ordering->at_put(index, old_index);
m->set_vtable_index(Method::invalid_vtable_index);
}
}
return method_ordering;
}
// This is only done during class loading, so it is OK to assume method_idnum matches the methods() array
// default_methods also uses this without the ordering for fast find_method
void Method::sort_methods(Array<Method*>* methods, bool idempotent, bool set_idnums) {
int length = methods->length();
if (length > 1) {
{
No_Safepoint_Verifier nsv;
QuickSort::sort<Method*>(methods->data(), length, method_comparator, idempotent);
}
// Reset method ordering
if (set_idnums) {
for (int i = 0; i < length; i++) {
Method* m = methods->at(i);
m->set_method_idnum(i);
m->set_orig_method_idnum(i);
}
}
}
}
// Comparer for sorting an object array containing
// Method*s.
static int method_comparator(Method* a, Method* b) {
return a->name()->fast_compare(b->name());
}
// Note: this comparison is used for vtable sorting only; it doesn't matter
// what order it defines, as long as it is a total, time-invariant order
// Since Symbol*s are in C_HEAP, their relative order in memory never changes,
// so use address comparison for speed
int Symbol::fast_compare(Symbol* other) const {
return (((uintptr_t)this < (uintptr_t)other) ? -1
: ((uintptr_t)this == (uintptr_t) other) ? 0 : 1);
}