hotspot/src/share/vm/interpreter/linkResolver.cpp
changeset 46458 3c12af929e7d
parent 46408 70aab0c2ea8b
parent 44738 11431bbc9549
child 46505 fd4bc78630b1
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp	Fri May 12 11:41:05 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp	Fri May 12 13:14:25 2017 -0700
@@ -1053,12 +1053,14 @@
 
 
 void LinkResolver::resolve_special_call(CallInfo& result,
+                                        Handle recv,
                                         const LinkInfo& link_info,
                                         TRAPS) {
   methodHandle resolved_method = linktime_resolve_special_method(link_info, CHECK);
   runtime_resolve_special_method(result, resolved_method,
                                  link_info.resolved_klass(),
                                  link_info.current_klass(),
+                                 recv,
                                  link_info.check_access(), CHECK);
 }
 
@@ -1146,6 +1148,7 @@
                                                   const methodHandle& resolved_method,
                                                   Klass* resolved_klass,
                                                   Klass* current_klass,
+                                                  Handle recv,
                                                   bool check_access, TRAPS) {
 
   // resolved method is selected method unless we have an old-style lookup
@@ -1154,30 +1157,53 @@
   // no checks for shadowing
   methodHandle sel_method(THREAD, resolved_method());
 
-  // check if this is an old-style super call and do a new lookup if so
   if (check_access &&
-      // a) check if ACC_SUPER flag is set for the current class
-      (current_klass->is_super() || !AllowNonVirtualCalls) &&
-      // b) check if the class of the resolved_klass is a superclass
-      // (not supertype in order to exclude interface classes) of the current class.
-      // This check is not performed for super.invoke for interface methods
-      // in super interfaces.
-      current_klass->is_subclass_of(resolved_klass) &&
-      current_klass != resolved_klass &&
-      // c) check if the method is not <init>
+      // check if the method is not <init>
       resolved_method->name() != vmSymbols::object_initializer_name()) {
-    // Lookup super method
-    Klass* super_klass = current_klass->super();
-    sel_method = lookup_instance_method_in_klasses(super_klass,
-                         resolved_method->name(),
-                         resolved_method->signature(), CHECK);
-    // check if found
-    if (sel_method.is_null()) {
-      ResourceMark rm(THREAD);
-      THROW_MSG(vmSymbols::java_lang_AbstractMethodError(),
-                Method::name_and_sig_as_C_string(resolved_klass,
-                                          resolved_method->name(),
-                                          resolved_method->signature()));
+
+  // check if this is an old-style super call and do a new lookup if so
+        // a) check if ACC_SUPER flag is set for the current class
+    if ((current_klass->is_super() || !AllowNonVirtualCalls) &&
+        // b) check if the class of the resolved_klass is a superclass
+        // (not supertype in order to exclude interface classes) of the current class.
+        // This check is not performed for super.invoke for interface methods
+        // in super interfaces.
+        current_klass->is_subclass_of(resolved_klass) &&
+        current_klass != resolved_klass) {
+      // Lookup super method
+      Klass* super_klass = current_klass->super();
+      sel_method = lookup_instance_method_in_klasses(super_klass,
+                           resolved_method->name(),
+                           resolved_method->signature(), CHECK);
+      // check if found
+      if (sel_method.is_null()) {
+        ResourceMark rm(THREAD);
+        THROW_MSG(vmSymbols::java_lang_AbstractMethodError(),
+                  Method::name_and_sig_as_C_string(resolved_klass,
+                                            resolved_method->name(),
+                                            resolved_method->signature()));
+      }
+    }
+
+    // Check that the class of objectref (the receiver) is the current class or interface,
+    // or a subtype of the current class or interface (the sender), otherwise invokespecial
+    // throws IllegalAccessError.
+    // The verifier checks that the sender is a subtype of the class in the I/MR operand.
+    // The verifier also checks that the receiver is a subtype of the sender, if the sender is
+    // a class.  If the sender is an interface, the check has to be performed at runtime.
+    InstanceKlass* sender = InstanceKlass::cast(current_klass);
+    sender = sender->is_anonymous() ? sender->host_klass() : sender;
+    if (sender->is_interface() && recv.not_null()) {
+      Klass* receiver_klass = recv->klass();
+      if (!receiver_klass->is_subtype_of(sender)) {
+        ResourceMark rm(THREAD);
+        char buf[500];
+        jio_snprintf(buf, sizeof(buf),
+                     "Receiver class %s must be the current class or a subtype of interface %s",
+                     receiver_klass->name()->as_C_string(),
+                     sender->name()->as_C_string());
+        THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), buf);
+      }
     }
   }
 
@@ -1511,7 +1537,7 @@
 methodHandle LinkResolver::resolve_special_call_or_null(const LinkInfo& link_info) {
   EXCEPTION_MARK;
   CallInfo info;
-  resolve_special_call(info, link_info, THREAD);
+  resolve_special_call(info, Handle(), link_info, THREAD);
   if (HAS_PENDING_EXCEPTION) {
     CLEAR_PENDING_EXCEPTION;
     return methodHandle();
@@ -1527,7 +1553,7 @@
 void LinkResolver::resolve_invoke(CallInfo& result, Handle recv, const constantPoolHandle& pool, int index, Bytecodes::Code byte, TRAPS) {
   switch (byte) {
     case Bytecodes::_invokestatic   : resolve_invokestatic   (result,       pool, index, CHECK); break;
-    case Bytecodes::_invokespecial  : resolve_invokespecial  (result,       pool, index, CHECK); break;
+    case Bytecodes::_invokespecial  : resolve_invokespecial  (result, recv, pool, index, CHECK); break;
     case Bytecodes::_invokevirtual  : resolve_invokevirtual  (result, recv, pool, index, CHECK); break;
     case Bytecodes::_invokehandle   : resolve_invokehandle   (result,       pool, index, CHECK); break;
     case Bytecodes::_invokedynamic  : resolve_invokedynamic  (result,       pool, index, CHECK); break;
@@ -1556,7 +1582,7 @@
       resolve_static_call(result, link_info, /*initialize_class=*/false, CHECK);
       break;
     case Bytecodes::_invokespecial:
-      resolve_special_call(result, link_info, CHECK);
+      resolve_special_call(result, recv, link_info, CHECK);
       break;
     default:
       fatal("bad call: %s", Bytecodes::name(byte));
@@ -1569,9 +1595,10 @@
 }
 
 
-void LinkResolver::resolve_invokespecial(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) {
+void LinkResolver::resolve_invokespecial(CallInfo& result, Handle recv,
+                                         const constantPoolHandle& pool, int index, TRAPS) {
   LinkInfo link_info(pool, index, CHECK);
-  resolve_special_call(result, link_info, CHECK);
+  resolve_special_call(result, recv, link_info, CHECK);
 }