8203188: Add JEP-181 support to the Zero interpreter
authorsgehwolf
Tue, 05 Jun 2018 11:55:39 +0200
changeset 50736 f703d45c5687
parent 50735 2f2af62dfac7
child 50737 ada9735476b2
8203188: Add JEP-181 support to the Zero interpreter Reviewed-by: dholmes, chrisphi
src/hotspot/cpu/zero/methodHandles_zero.cpp
src/hotspot/cpu/zero/methodHandles_zero.hpp
src/hotspot/share/interpreter/bytecodeInterpreter.cpp
--- a/src/hotspot/cpu/zero/methodHandles_zero.cpp	Sat Jun 23 01:32:41 2018 -0400
+++ b/src/hotspot/cpu/zero/methodHandles_zero.cpp	Tue Jun 05 11:55:39 2018 +0200
@@ -26,6 +26,7 @@
 #include "precompiled.hpp"
 #include "interpreter/cppInterpreterGenerator.hpp"
 #include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterRuntime.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/method.inline.hpp"
@@ -65,6 +66,37 @@
 
 }
 
+void MethodHandles::throw_AME(Klass* rcvr, Method* interface_method, TRAPS) {
+
+  JavaThread *thread = (JavaThread *) THREAD;
+  // Set up the frame anchor if it isn't already
+  bool has_last_Java_frame = thread->has_last_Java_frame();
+  if (!has_last_Java_frame) {
+    intptr_t *sp = thread->zero_stack()->sp();
+    ZeroFrame *frame = thread->top_zero_frame();
+    while (frame) {
+      if (frame->is_interpreter_frame()) {
+        interpreterState istate =
+          frame->as_interpreter_frame()->interpreter_state();
+        if (istate->self_link() == istate)
+          break;
+      }
+
+      sp = ((intptr_t *) frame) + 1;
+      frame = frame->next();
+    }
+
+    assert(frame != NULL, "must be");
+    thread->set_last_Java_frame(frame, sp);
+  }
+  InterpreterRuntime::throw_AbstractMethodErrorVerbose(thread, rcvr, interface_method);
+  // Reset the frame anchor if necessary
+  if (!has_last_Java_frame) {
+    thread->reset_last_Java_frame();
+  }
+
+}
+
 int MethodHandles::method_handle_entry_invokeBasic(Method* method, intptr_t UNUSED, TRAPS) {
 
   JavaThread *thread = (JavaThread *) THREAD;
@@ -124,8 +156,15 @@
 
   itableMethodEntry* im = ki->first_method_entry(recv->klass());
   Method* vmtarget = im[vmindex].method();
-
-  invoke_target(vmtarget, THREAD);
+  // Check that the vmtarget entry is non-null.  A null entry means
+  // that the method no longer exists (got deleted) or is private.
+  // Private class methods can never be an implementation of an
+  // interface method. In those cases, throw AME.
+  if (vmtarget != NULL) {
+    invoke_target(vmtarget, THREAD);
+  } else {
+    throw_AME(recv->klass(), target, THREAD);
+  }
 
   return 0;
 }
--- a/src/hotspot/cpu/zero/methodHandles_zero.hpp	Sat Jun 23 01:32:41 2018 -0400
+++ b/src/hotspot/cpu/zero/methodHandles_zero.hpp	Tue Jun 05 11:55:39 2018 +0200
@@ -32,6 +32,7 @@
 private:
   static oop popFromStack(TRAPS);
   static void invoke_target(Method* method, TRAPS);
+  static void throw_AME(Klass* rcvr, Method* interface_method, TRAPS);
   static int method_handle_entry_invokeBasic(Method* method, intptr_t UNUSED, TRAPS);
   static int method_handle_entry_linkToStaticOrSpecial(Method* method, intptr_t UNUSED, TRAPS);
   static int method_handle_entry_linkToVirtual(Method* method, intptr_t UNUSED, TRAPS);
--- a/src/hotspot/share/interpreter/bytecodeInterpreter.cpp	Sat Jun 23 01:32:41 2018 -0400
+++ b/src/hotspot/share/interpreter/bytecodeInterpreter.cpp	Tue Jun 05 11:55:39 2018 +0200
@@ -2524,11 +2524,9 @@
         istate->set_msg(call_method);
 
         // Special case of invokeinterface called for virtual method of
-        // java.lang.Object.  See cpCacheOop.cpp for details.
-        // This code isn't produced by javac, but could be produced by
-        // another compliant java compiler.
+        // java.lang.Object.  See cpCache.cpp for details.
+        Method* callee = NULL;
         if (cache->is_forced_virtual()) {
-          Method* callee;
           CHECK_NULL(STACK_OBJECT(-(cache->parameter_size())));
           if (cache->is_vfinal()) {
             callee = cache->f2_as_vfinal_method();
@@ -2545,6 +2543,29 @@
             // Profile 'special case of invokeinterface' virtual call.
             BI_PROFILE_UPDATE_VIRTUALCALL(rcvrKlass);
           }
+        } else if (cache->is_vfinal()) {
+          // private interface method invocations
+          //
+          // Ensure receiver class actually implements
+          // the resolved interface class. The link resolver
+          // does this, but only for the first time this
+          // interface is being called.
+          int parms = cache->parameter_size();
+          oop rcvr = STACK_OBJECT(-parms);
+          CHECK_NULL(rcvr);
+          Klass* recv_klass = rcvr->klass();
+          Klass* resolved_klass = cache->f1_as_klass();
+          if (!recv_klass->is_subtype_of(resolved_klass)) {
+            ResourceMark rm(THREAD);
+            char buf[200];
+            jio_snprintf(buf, sizeof(buf), "Class %s does not implement the requested interface %s",
+              recv_klass->external_name(),
+              resolved_klass->external_name());
+            VM_JAVA_ERROR(vmSymbols::java_lang_IncompatibleClassChangeError(), buf, note_no_trap);
+          }
+          callee = cache->f2_as_vfinal_method();
+        }
+        if (callee != NULL) {
           istate->set_callee(callee);
           istate->set_callee_entry_point(callee->from_interpreted_entry());
 #ifdef VM_JVMTI
@@ -2557,7 +2578,6 @@
         }
 
         // this could definitely be cleaned up QQQ
-        Method* callee;
         Method *interface_method = cache->f2_as_interface_method();
         InstanceKlass* iclass = interface_method->method_holder();