8217760: C2: Missing symbolic info on a call from intrinsics when invoked through MethodHandle
authorvlivanov
Fri, 25 Jan 2019 13:37:08 -0800
changeset 53509 28aa41c4165b
parent 53508 04dcc65c9d58
child 53510 790377fdc328
8217760: C2: Missing symbolic info on a call from intrinsics when invoked through MethodHandle Reviewed-by: thartmann, roland
src/hotspot/share/opto/callGenerator.cpp
src/hotspot/share/opto/callGenerator.hpp
src/hotspot/share/opto/callnode.cpp
src/hotspot/share/opto/callnode.hpp
src/hotspot/share/opto/library_call.cpp
src/hotspot/share/opto/matcher.cpp
test/hotspot/jtreg/compiler/jsr292/NonInlinedCall/InvokeTest.java
--- a/src/hotspot/share/opto/callGenerator.cpp	Fri Jan 25 18:13:25 2019 +0000
+++ b/src/hotspot/share/opto/callGenerator.cpp	Fri Jan 25 13:37:08 2019 -0800
@@ -46,9 +46,17 @@
   return TypeFunc::make(method());
 }
 
-bool CallGenerator::is_inlined_method_handle_intrinsic(JVMState* jvms, ciMethod* callee) {
-  ciMethod* symbolic_info = jvms->method()->get_method_at_bci(jvms->bci());
-  return symbolic_info->is_method_handle_intrinsic() && !callee->is_method_handle_intrinsic();
+bool CallGenerator::is_inlined_method_handle_intrinsic(JVMState* jvms, ciMethod* m) {
+  return is_inlined_method_handle_intrinsic(jvms->method(), jvms->bci(), m);
+}
+
+bool CallGenerator::is_inlined_method_handle_intrinsic(ciMethod* caller, int bci, ciMethod* m) {
+  ciMethod* symbolic_info = caller->get_method_at_bci(bci);
+  return is_inlined_method_handle_intrinsic(symbolic_info, m);
+}
+
+bool CallGenerator::is_inlined_method_handle_intrinsic(ciMethod* symbolic_info, ciMethod* m) {
+  return symbolic_info->is_method_handle_intrinsic() && !m->is_method_handle_intrinsic();
 }
 
 //-----------------------------ParseGenerator---------------------------------
--- a/src/hotspot/share/opto/callGenerator.hpp	Fri Jan 25 18:13:25 2019 +0000
+++ b/src/hotspot/share/opto/callGenerator.hpp	Fri Jan 25 13:37:08 2019 -0800
@@ -176,6 +176,8 @@
   }
 
   static bool is_inlined_method_handle_intrinsic(JVMState* jvms, ciMethod* m);
+  static bool is_inlined_method_handle_intrinsic(ciMethod* caller, int bci, ciMethod* m);
+  static bool is_inlined_method_handle_intrinsic(ciMethod* symbolic_info, ciMethod* m);
 };
 
 
--- a/src/hotspot/share/opto/callnode.cpp	Fri Jan 25 18:13:25 2019 +0000
+++ b/src/hotspot/share/opto/callnode.cpp	Fri Jan 25 13:37:08 2019 -0800
@@ -967,6 +967,21 @@
   return CallNode::cmp(call) && _method == call._method &&
          _override_symbolic_info == call._override_symbolic_info;
 }
+#ifdef ASSERT
+bool CallJavaNode::validate_symbolic_info() const {
+  if (method() == NULL) {
+    return true; // call into runtime or uncommon trap
+  }
+  ciMethod* symbolic_info = jvms()->method()->get_method_at_bci(_bci);
+  ciMethod* callee = method();
+  if (symbolic_info->is_method_handle_intrinsic() && !callee->is_method_handle_intrinsic()) {
+    assert(override_symbolic_info(), "should be set");
+  }
+  assert(ciMethod::is_consistent_info(symbolic_info, callee), "inconsistent info");
+  return true;
+}
+#endif
+
 #ifndef PRODUCT
 void CallJavaNode::dump_spec(outputStream *st) const {
   if( _method ) _method->print_short_name(st);
--- a/src/hotspot/share/opto/callnode.hpp	Fri Jan 25 18:13:25 2019 +0000
+++ b/src/hotspot/share/opto/callnode.hpp	Fri Jan 25 13:37:08 2019 -0800
@@ -683,6 +683,8 @@
   void  set_override_symbolic_info(bool f) { _override_symbolic_info = f; }
   bool  override_symbolic_info() const     { return _override_symbolic_info; }
 
+  DEBUG_ONLY( bool validate_symbolic_info() const; )
+
 #ifndef PRODUCT
   virtual void  dump_spec(outputStream *st) const;
   virtual void  dump_compact_spec(outputStream *st) const;
--- a/src/hotspot/share/opto/library_call.cpp	Fri Jan 25 18:13:25 2019 +0000
+++ b/src/hotspot/share/opto/library_call.cpp	Fri Jan 25 13:37:08 2019 -0800
@@ -3850,6 +3850,13 @@
                                 method, bci());
     slow_call->set_optimized_virtual(true);
   }
+  if (CallGenerator::is_inlined_method_handle_intrinsic(this->method(), bci(), callee())) {
+    // To be able to issue a direct call (optimized virtual or virtual)
+    // and skip a call to MH.linkTo*/invokeBasic adapter, additional information
+    // about the method being invoked should be attached to the call site to
+    // make resolution logic work (see SharedRuntime::resolve_{virtual,opt_virtual}_call_C).
+    slow_call->set_override_symbolic_info(true);
+  }
   set_arguments_for_java_call(slow_call);
   set_edges_for_java_call(slow_call);
   return slow_call;
--- a/src/hotspot/share/opto/matcher.cpp	Fri Jan 25 18:13:25 2019 +0000
+++ b/src/hotspot/share/opto/matcher.cpp	Fri Jan 25 13:37:08 2019 -0800
@@ -1170,6 +1170,7 @@
     if( mcall->is_MachCallJava() ) {
       MachCallJavaNode *mcall_java  = mcall->as_MachCallJava();
       const CallJavaNode *call_java =  call->as_CallJava();
+      assert(call_java->validate_symbolic_info(), "inconsistent info");
       method = call_java->method();
       mcall_java->_method = method;
       mcall_java->_bci = call_java->_bci;
--- a/test/hotspot/jtreg/compiler/jsr292/NonInlinedCall/InvokeTest.java	Fri Jan 25 18:13:25 2019 +0000
+++ b/test/hotspot/jtreg/compiler/jsr292/NonInlinedCall/InvokeTest.java	Fri Jan 25 13:37:08 2019 -0800
@@ -60,6 +60,8 @@
     static final MethodHandle privateMH; // invokespecial   I.f4 T
     static final MethodHandle basicMH;
 
+    static final MethodHandle intrinsicMH; // invokevirtual Object.hashCode
+
     static final WhiteBox WB = WhiteBox.getWhiteBox();
 
     static volatile boolean doDeopt = false;
@@ -75,6 +77,7 @@
             specialMH  = LOOKUP.findSpecial(T.class, "f4", mtype, T.class);
             privateMH  = LOOKUP.findSpecial(I.class, "f4", mtype, I.class);
             basicMH    = NonInlinedReinvoker.make(staticMH);
+            intrinsicMH = LOOKUP.findVirtual(Object.class, "hashCode", MethodType.methodType(int.class));
         } catch (Exception e) {
             throw new Error(e);
         }
@@ -117,6 +120,10 @@
     static class Q2 extends T implements J2 {}
     static class Q3 extends T implements J3 {}
 
+    static class H {
+        public int hashCode() { return 0; }
+    }
+
     @DontInline
     static void linkToVirtual(T recv, Class<?> expected) {
         try {
@@ -138,6 +145,16 @@
     }
 
     @DontInline
+    static void linkToVirtualIntrinsic(Object recv, int expected) {
+        try {
+            int v = (int)intrinsicMH.invokeExact(recv);
+            assertEquals(v, expected);
+        } catch (Throwable e) {
+            throw new Error(e);
+        }
+    }
+
+    @DontInline
     static void linkToInterface(I recv, Class<?> expected) {
         try {
             Class<?> cls = (Class<?>)intfMH.invokeExact(recv);
@@ -177,7 +194,6 @@
         }
     }
 
-
     @DontInline
     static void invokeBasic() {
         try {
@@ -215,6 +231,8 @@
         run(() -> linkToVirtual(new T(), T.class));
         run(() -> linkToVirtualDefault(new T(), I.class));
 
+        run(() -> linkToVirtualIntrinsic(new H(), 0));
+
         // Megamorphic case (optimized virtual call)
         run(() -> {
             linkToVirtual(new T() {}, T.class);