InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(ofMirror));
// 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 = newGrowableArray<int>(methods_length); int num_methods = 0;
// Select methods matching the criteria. for (int i = 0; i < methods_length; i++) { Method* method = methods->at(i); if (want_constructor && !method->is_object_initializer()) { continue; } if (!want_constructor && (method->is_object_initializer() || method->is_static_initializer() || method->is_overpass())) { continue; } if (publicOnly && !method->is_public()) { continue; } 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, nullptr); } else { oop m; if (want_constructor) { m = Reflection::new_constructor(method, CHECK_NULL); } else { m = Reflection::new_method(method, false, CHECK_NULL); } result->obj_at_put(i, m); } }
// https://github.com/openjdk/jdk/blob/master/src/hotspot/share/oops/instanceKlass.cpp Method* InstanceKlass::method_with_idnum(int idnum)const{ Method* m = nullptr; if (idnum < methods()->length()) { m = methods()->at(idnum); } if (m == nullptr || 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. returnnullptr; } return m; }
// https://github.com/openjdk/jdk/blob/master/src/hotspot/share/classfile/classFileParser.cpp staticconst intArray* sort_methods(Array<Method*>* methods){ constint 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() || CDSConfig::is_dumping_archive()) { for (int index = 0; index < length; index++) { Method* const 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 = nullptr; // If JVMTI original method ordering or sharing is enabled construct int // array remembering the original ordering if (JvmtiExport::can_maintain_original_method_order() || CDSConfig::is_dumping_archive()) { method_ordering = newintArray(length, length, -1); for (int index = 0; index < length; index++) { Method* const m = methods->at(index); constint 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; }
//https://github.com/openjdk/jdk/blob/master/src/hotspot/share/oops/method.cpp // 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 voidMethod::sort_methods(Array<Method*>* methods, bool set_idnums, method_comparator_func func){ int length = methods->length(); if (length > 1) { if (func == nullptr) { func = method_comparator; } { NoSafepointVerifier nsv; QuickSort::sort(methods->data(), length, func); } // Reset method ordering if (set_idnums) { for (u2 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. staticintmethod_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 intSymbol::fast_compare(const Symbol* other)const{ return (((uintptr_t)this < (uintptr_t)other) ? -1 : ((uintptr_t)this == (uintptr_t) other) ? 0 : 1); }
// sun.reflect.NativeMethodAccessorImpl public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException { // We can't inflate methods belonging to vm-anonymous classes because // that kind of class can't be referred to by name, hence can't be // found from the generated bytecode. if (++numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) { MethodAccessorImplacc= (MethodAccessorImpl) newMethodAccessorGenerator(). generateMethod(method.getDeclaringClass(), method.getName(), method.getParameterTypes(), method.getReturnType(), method.getExceptionTypes(), method.getModifiers()); parent.setDelegate(acc); }