8036805: Correct linker method lookup.
Summary: Correct handling of array of primitive type qualifiers during field and method resolution.
Reviewed-by: acorn, hseigel, ahgross
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Fri Oct 10 02:24:35 2014 -0700
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Wed May 07 19:38:22 2014 +0400
@@ -246,6 +246,12 @@
// Ignore overpasses so statics can be found during resolution
Method* result_oop = klass->uncached_lookup_method(name, signature, Klass::skip_overpass);
+ if (klass->oop_is_array()) {
+ // Only consider klass and super klass for arrays
+ result = methodHandle(THREAD, result_oop);
+ return;
+ }
+
// JDK 8, JVMS 5.4.3.4: Interface method resolution should
// ignore static and non-public methods of java.lang.Object,
// like clone, finalize, registerNatives.
@@ -290,6 +296,11 @@
result = methodHandle(THREAD, super_klass->uncached_lookup_method(name, signature, Klass::normal));
}
+ if (klass->oop_is_array()) {
+ // Only consider klass and super klass for arrays
+ return;
+ }
+
if (result.is_null()) {
Array<Method*>* default_methods = InstanceKlass::cast(klass())->default_methods();
if (default_methods != NULL) {
@@ -545,7 +556,7 @@
// 2. lookup method in resolved klass and its super klasses
lookup_method_in_klasses(resolved_method, resolved_klass, method_name, method_signature, true, false, CHECK);
- if (resolved_method.is_null()) { // not found in the class hierarchy
+ if (resolved_method.is_null() && !resolved_klass->oop_is_array()) { // not found in the class hierarchy
// 3. lookup method in all the interfaces implemented by the resolved klass
lookup_method_in_interfaces(resolved_method, resolved_klass, method_name, method_signature, CHECK);
@@ -558,16 +569,16 @@
CLEAR_PENDING_EXCEPTION;
}
}
+ }
- if (resolved_method.is_null()) {
- // 4. method lookup failed
- ResourceMark rm(THREAD);
- THROW_MSG_CAUSE(vmSymbols::java_lang_NoSuchMethodError(),
- Method::name_and_sig_as_C_string(resolved_klass(),
- method_name,
- method_signature),
- nested_exception);
- }
+ if (resolved_method.is_null()) {
+ // 4. method lookup failed
+ ResourceMark rm(THREAD);
+ THROW_MSG_CAUSE(vmSymbols::java_lang_NoSuchMethodError(),
+ Method::name_and_sig_as_C_string(resolved_klass(),
+ method_name,
+ method_signature),
+ nested_exception);
}
// 5. access checks, access checking may be turned off when calling from within the VM.
@@ -633,17 +644,18 @@
// JDK8: also look for static methods
lookup_method_in_klasses(resolved_method, resolved_klass, method_name, method_signature, false, true, CHECK);
- if (resolved_method.is_null()) {
+ if (resolved_method.is_null() && !resolved_klass->oop_is_array()) {
// lookup method in all the super-interfaces
lookup_method_in_interfaces(resolved_method, resolved_klass, method_name, method_signature, CHECK);
- if (resolved_method.is_null()) {
- // no method found
- ResourceMark rm(THREAD);
- THROW_MSG(vmSymbols::java_lang_NoSuchMethodError(),
- Method::name_and_sig_as_C_string(resolved_klass(),
- method_name,
- method_signature));
- }
+ }
+
+ if (resolved_method.is_null()) {
+ // no method found
+ ResourceMark rm(THREAD);
+ THROW_MSG(vmSymbols::java_lang_NoSuchMethodError(),
+ Method::name_and_sig_as_C_string(resolved_klass(),
+ method_name,
+ method_signature));
}
if (check_access) {
@@ -775,7 +787,7 @@
}
// Resolve instance field
- KlassHandle sel_klass(THREAD, InstanceKlass::cast(resolved_klass())->find_field(field, sig, &fd));
+ KlassHandle sel_klass(THREAD, resolved_klass->find_field(field, sig, &fd));
// check if field exists; i.e., if a klass containing the field def has been selected
if (sel_klass.is_null()) {
ResourceMark rm(THREAD);
--- a/hotspot/src/share/vm/oops/arrayKlass.cpp Fri Oct 10 02:24:35 2014 -0700
+++ b/hotspot/src/share/vm/oops/arrayKlass.cpp Wed May 07 19:38:22 2014 +0400
@@ -64,6 +64,13 @@
return NULL;
}
+// find field according to JVM spec 5.4.3.2, returns the klass in which the field is defined
+Klass* ArrayKlass::find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const {
+ // There are no fields in an array klass but look to the super class (Object)
+ assert(super(), "super klass must be present");
+ return super()->find_field(name, sig, fd);
+}
+
Method* ArrayKlass::uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const {
// There are no methods in an array klass but the super class (Object) has some
assert(super(), "super klass must be present");
--- a/hotspot/src/share/vm/oops/arrayKlass.hpp Fri Oct 10 02:24:35 2014 -0700
+++ b/hotspot/src/share/vm/oops/arrayKlass.hpp Wed May 07 19:38:22 2014 +0400
@@ -28,6 +28,7 @@
#include "memory/universe.hpp"
#include "oops/klass.hpp"
+class fieldDescriptor;
class klassVtable;
// ArrayKlass is the abstract baseclass for all array classes
@@ -77,6 +78,9 @@
virtual oop multi_allocate(int rank, jint* sizes, TRAPS);
objArrayOop allocate_arrayArray(int n, int length, TRAPS);
+ // find field according to JVM spec 5.4.3.2, returns the klass in which the field is defined
+ Klass* find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const;
+
// Lookup operations
Method* uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const;
--- a/hotspot/src/share/vm/oops/klass.cpp Fri Oct 10 02:24:35 2014 -0700
+++ b/hotspot/src/share/vm/oops/klass.cpp Wed May 07 19:38:22 2014 +0400
@@ -130,6 +130,15 @@
return is_subclass_of(k);
}
+Klass* Klass::find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const {
+#ifdef ASSERT
+ tty->print_cr("Error: find_field called on a klass oop."
+ " Likely error: reflection method does not correctly"
+ " wrap return value in a mirror object.");
+#endif
+ ShouldNotReachHere();
+ return NULL;
+}
Method* Klass::uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const {
#ifdef ASSERT
--- a/hotspot/src/share/vm/oops/klass.hpp Fri Oct 10 02:24:35 2014 -0700
+++ b/hotspot/src/share/vm/oops/klass.hpp Wed May 07 19:38:22 2014 +0400
@@ -62,6 +62,7 @@
class klassVtable;
class ParCompactionManager;
class KlassSizeStats;
+class fieldDescriptor;
class Klass : public Metadata {
friend class VMStructs;
@@ -411,6 +412,7 @@
virtual void initialize(TRAPS);
// lookup operation for MethodLookupCache
friend class MethodLookupCache;
+ virtual Klass* find_field(Symbol* name, Symbol* signature, fieldDescriptor* fd) const;
virtual Method* uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const;
public:
Method* lookup_method(Symbol* name, Symbol* signature) const {