hotspot/src/share/vm/interpreter/linkResolver.cpp
changeset 38719 133bf85c3f36
parent 38139 cf6f5c1b7205
child 38939 c1b1d1d0e89b
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp	Thu May 26 20:43:13 2016 -0400
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp	Fri May 27 10:52:39 2016 -0400
@@ -231,6 +231,7 @@
   // Get name, signature, and static klass
   _name          = pool->name_ref_at(index);
   _signature     = pool->signature_ref_at(index);
+  _tag           = pool->tag_ref_at(index);
   _current_klass = KlassHandle(THREAD, pool->pool_holder());
 
   // Coming from the constant pool always checks access
@@ -573,7 +574,7 @@
     Symbol* method_signature = pool->signature_ref_at(index);
     KlassHandle  current_klass(THREAD, pool->pool_holder());
     LinkInfo link_info(resolved_klass, method_name, method_signature, current_klass);
-    return resolve_method(link_info, /*require_methodref*/false, THREAD);
+    return resolve_method(link_info, code, THREAD);
   }
 
   LinkInfo link_info(pool, index, CHECK_NULL);
@@ -591,9 +592,9 @@
   if (code == Bytecodes::_invokeinterface) {
     return resolve_interface_method(link_info, code, THREAD);
   } else if (code == Bytecodes::_invokevirtual) {
-    return resolve_method(link_info, /*require_methodref*/true, THREAD);
+    return resolve_method(link_info, code, THREAD);
   } else if (!resolved_klass->is_interface()) {
-    return resolve_method(link_info, /*require_methodref*/false, THREAD);
+    return resolve_method(link_info, code, THREAD);
   } else {
     return resolve_interface_method(link_info, code, THREAD);
   }
@@ -663,13 +664,13 @@
 }
 
 methodHandle LinkResolver::resolve_method(const LinkInfo& link_info,
-                                          bool require_methodref, TRAPS) {
+                                          Bytecodes::Code code, TRAPS) {
 
   Handle nested_exception;
   KlassHandle resolved_klass = link_info.resolved_klass();
 
-  // 1. check if methodref required, that resolved_klass is not interfacemethodref
-  if (require_methodref && resolved_klass->is_interface()) {
+  // 1. For invokevirtual, cannot call an interface method
+  if (code == Bytecodes::_invokevirtual && resolved_klass->is_interface()) {
     ResourceMark rm(THREAD);
     char buf[200];
     jio_snprintf(buf, sizeof(buf), "Found interface %s, but class was expected",
@@ -677,11 +678,20 @@
     THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
   }
 
-  // 2. lookup method in resolved klass and its super klasses
+  // 2. check constant pool tag for called method - must be JVM_CONSTANT_Methodref
+  if (!link_info.tag().is_invalid() && !link_info.tag().is_method()) {
+    ResourceMark rm(THREAD);
+    char buf[200];
+    jio_snprintf(buf, sizeof(buf), "Method %s must be Methodref constant", link_info.method_string());
+    THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
+  }
+
+
+  // 3. lookup method in resolved klass and its super klasses
   methodHandle resolved_method = lookup_method_in_klasses(link_info, true, false, CHECK_NULL);
 
+  // 4. lookup method in all the interfaces implemented by the resolved klass
   if (resolved_method.is_null() && !resolved_klass->is_array_klass()) { // not found in the class hierarchy
-    // 3. lookup method in all the interfaces implemented by the resolved klass
     resolved_method = lookup_method_in_interfaces(link_info, CHECK_NULL);
 
     if (resolved_method.is_null()) {
@@ -694,8 +704,8 @@
     }
   }
 
+  // 5. method lookup failed
   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(),
@@ -704,7 +714,7 @@
                     nested_exception, NULL);
   }
 
-  // 5. access checks, access checking may be turned off when calling from within the VM.
+  // 6. access checks, access checking may be turned off when calling from within the VM.
   KlassHandle current_klass = link_info.current_klass();
   if (link_info.check_access()) {
     assert(current_klass.not_null() , "current_klass should not be null");
@@ -766,6 +776,14 @@
     THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
   }
 
+  // check constant pool tag for called method - must be JVM_CONSTANT_InterfaceMethodref
+  if (!link_info.tag().is_invalid() && !link_info.tag().is_interface_method()) {
+    ResourceMark rm(THREAD);
+    char buf[200];
+    jio_snprintf(buf, sizeof(buf), "Method %s must be InterfaceMethodref constant", link_info.method_string());
+    THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
+  }
+
   // lookup method in this interface or its super, java.lang.Object
   // JDK8: also look for static methods
   methodHandle resolved_method = lookup_method_in_klasses(link_info, false, true, CHECK_NULL);
@@ -956,7 +974,8 @@
     resolved_klass->initialize(CHECK);
     // Use updated LinkInfo (to reresolve with resolved_klass as method_holder?)
     LinkInfo new_info(resolved_klass, link_info.name(), link_info.signature(),
-                      link_info.current_klass(), link_info.check_access());
+                      link_info.current_klass(),
+                      link_info.check_access() ? LinkInfo::needs_access_check : LinkInfo::skip_access_check);
     resolved_method = linktime_resolve_static_method(new_info, CHECK);
   }
 
@@ -971,7 +990,7 @@
   KlassHandle resolved_klass = link_info.resolved_klass();
   methodHandle resolved_method;
   if (!resolved_klass->is_interface()) {
-    resolved_method = resolve_method(link_info, /*require_methodref*/false, CHECK_NULL);
+    resolved_method = resolve_method(link_info, Bytecodes::_invokestatic, CHECK_NULL);
   } else {
     resolved_method = resolve_interface_method(link_info, Bytecodes::_invokestatic, CHECK_NULL);
   }
@@ -1014,7 +1033,7 @@
   methodHandle resolved_method;
 
   if (!resolved_klass->is_interface()) {
-    resolved_method = resolve_method(link_info, /*require_methodref*/false, CHECK_NULL);
+    resolved_method = resolve_method(link_info, Bytecodes::_invokespecial, CHECK_NULL);
   } else {
     resolved_method = resolve_interface_method(link_info, Bytecodes::_invokespecial, CHECK_NULL);
   }
@@ -1164,7 +1183,7 @@
 methodHandle LinkResolver::linktime_resolve_virtual_method(const LinkInfo& link_info,
                                                            TRAPS) {
   // normal method resolution
-  methodHandle resolved_method = resolve_method(link_info, /*require_methodref*/true, CHECK_NULL);
+  methodHandle resolved_method = resolve_method(link_info, Bytecodes::_invokevirtual, CHECK_NULL);
 
   assert(resolved_method->name() != vmSymbols::object_initializer_name(), "should have been checked in verifier");
   assert(resolved_method->name() != vmSymbols::class_initializer_name (), "should have been checked in verifier");
@@ -1173,6 +1192,7 @@
   KlassHandle resolved_klass = link_info.resolved_klass();
   KlassHandle current_klass = link_info.current_klass();
 
+  // This is impossible, if resolve_klass is an interface, we've thrown icce in resolve_method
   if (resolved_klass->is_interface() && resolved_method->is_private()) {
     ResourceMark rm(THREAD);
     char buf[200];
@@ -1482,7 +1502,7 @@
   KlassHandle defc = attached_method->method_holder();
   Symbol* name = attached_method->name();
   Symbol* type = attached_method->signature();
-  LinkInfo link_info(defc, name, type, KlassHandle(), /*check_access=*/false);
+  LinkInfo link_info(defc, name, type);
   switch(byte) {
     case Bytecodes::_invokevirtual:
       resolve_virtual_call(result, recv, recv->klass(), link_info,