8221542: ~15% performance degradation due to less optimized inline decision
authorjiefu
Mon, 06 May 2019 12:17:54 -0700
changeset 54723 1abca1170080
parent 54722 f0bce2f93e72
child 54724 62f373a53296
8221542: ~15% performance degradation due to less optimized inline decision Reviewed-by: vlivanov, coleenp
src/hotspot/share/interpreter/abstractInterpreter.cpp
src/hotspot/share/interpreter/bytecodeStream.hpp
src/hotspot/share/oops/cpCache.cpp
src/hotspot/share/opto/bytecodeInfo.cpp
src/hotspot/share/opto/parse.hpp
src/hotspot/share/runtime/deoptimization.cpp
--- a/src/hotspot/share/interpreter/abstractInterpreter.cpp	Mon May 06 12:15:55 2019 -0700
+++ b/src/hotspot/share/interpreter/abstractInterpreter.cpp	Mon May 06 12:17:54 2019 -0700
@@ -28,6 +28,7 @@
 #include "compiler/disassembler.hpp"
 #include "interpreter/bytecodeHistogram.hpp"
 #include "interpreter/bytecodeInterpreter.hpp"
+#include "interpreter/bytecodeStream.hpp"
 #include "interpreter/interpreter.hpp"
 #include "interpreter/interpreterRuntime.hpp"
 #include "interpreter/interp_masm.hpp"
@@ -36,6 +37,8 @@
 #include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/arrayOop.hpp"
+#include "oops/constantPool.hpp"
+#include "oops/cpCache.inline.hpp"
 #include "oops/methodData.hpp"
 #include "oops/method.hpp"
 #include "oops/oop.inline.hpp"
@@ -240,9 +243,36 @@
 // Return true if the interpreter can prove that the given bytecode has
 // not yet been executed (in Java semantics, not in actual operation).
 bool AbstractInterpreter::is_not_reached(const methodHandle& method, int bci) {
-  Bytecodes::Code code = method()->code_at(bci);
+  BytecodeStream s(method, bci);
+  Bytecodes::Code code = s.next();
+
+  if (Bytecodes::is_invoke(code)) {
+    assert(!Bytecodes::must_rewrite(code), "invokes aren't rewritten");
+    ConstantPool* cpool = method()->constants();
+
+    Bytecode invoke_bc(s.bytecode());
 
-  if (!Bytecodes::must_rewrite(code)) {
+    switch (code) {
+      case Bytecodes::_invokedynamic: {
+        assert(invoke_bc.has_index_u4(code), "sanity");
+        int method_index = invoke_bc.get_index_u4(code);
+        return cpool->invokedynamic_cp_cache_entry_at(method_index)->is_f1_null();
+      }
+      case Bytecodes::_invokevirtual:   // fall-through
+      case Bytecodes::_invokeinterface: // fall-through
+      case Bytecodes::_invokespecial:   // fall-through
+      case Bytecodes::_invokestatic: {
+        if (cpool->has_preresolution()) {
+          return false; // might have been reached
+        }
+        assert(!invoke_bc.has_index_u4(code), "sanity");
+        int method_index = invoke_bc.get_index_u2_cpcache(code);
+        Method* resolved_method = ConstantPool::method_at_if_loaded(cpool, method_index);
+        return (resolved_method == NULL);
+      }
+      default: ShouldNotReachHere();
+    }
+  } else if (!Bytecodes::must_rewrite(code)) {
     // might have been reached
     return false;
   }
--- a/src/hotspot/share/interpreter/bytecodeStream.hpp	Mon May 06 12:15:55 2019 -0700
+++ b/src/hotspot/share/interpreter/bytecodeStream.hpp	Mon May 06 12:17:54 2019 -0700
@@ -170,6 +170,10 @@
   // Construction
   BytecodeStream(const methodHandle& method) : BaseBytecodeStream(method) { }
 
+  BytecodeStream(const methodHandle& method, int bci) : BaseBytecodeStream(method) {
+    set_start(bci);
+  }
+
   // Iteration
   Bytecodes::Code next() {
     Bytecodes::Code raw_code, code;
--- a/src/hotspot/share/oops/cpCache.cpp	Mon May 06 12:15:55 2019 -0700
+++ b/src/hotspot/share/oops/cpCache.cpp	Mon May 06 12:17:54 2019 -0700
@@ -506,7 +506,7 @@
       switch (invoke_code) {
       case Bytecodes::_invokeinterface:
         assert(f1->is_klass(), "");
-        return klassItable::method_for_itable_index((InstanceKlass*)f1, f2_as_index());
+        return f2_as_interface_method();
       case Bytecodes::_invokestatic:
       case Bytecodes::_invokespecial:
         assert(!has_appendix(), "");
--- a/src/hotspot/share/opto/bytecodeInfo.cpp	Mon May 06 12:15:55 2019 -0700
+++ b/src/hotspot/share/opto/bytecodeInfo.cpp	Mon May 06 12:17:54 2019 -0700
@@ -321,6 +321,35 @@
   return false;
 }
 
+bool InlineTree::is_not_reached(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile) {
+  if (!UseInterpreter) {
+    return false; // -Xcomp
+  }
+  if (profile.count() > 0) {
+    return false; // reachable according to profile
+  }
+  if (!callee_method->was_executed_more_than(0)) {
+    return true; // callee was never executed
+  }
+  if (caller_method->is_not_reached(caller_bci)) {
+    return true; // call site not resolved
+  }
+  if (profile.count() == -1) {
+    return false; // immature profile; optimistically treat as reached
+  }
+  assert(profile.count() == 0, "sanity");
+
+  // Profile info is scarce.
+  // Try to guess: check if the call site belongs to a start block.
+  // Call sites in a start block should be reachable if no exception is thrown earlier.
+  ciMethodBlocks* caller_blocks = caller_method->get_method_blocks();
+  bool is_start_block = caller_blocks->block_containing(caller_bci)->start_bci() == 0;
+  if (is_start_block) {
+    return false; // treat the call reached as part of start block
+  }
+  return true; // give up and treat the call site as not reached
+}
+
 //-----------------------------try_to_inline-----------------------------------
 // return true if ok
 // Relocated from "InliningClosure::try_to_inline"
@@ -372,7 +401,7 @@
       // inline constructors even if they are not reached.
     } else if (forced_inline()) {
       // Inlining was forced by CompilerOracle, ciReplay or annotation
-    } else if (profile.count() == 0) {
+    } else if (is_not_reached(callee_method, caller_method, caller_bci, profile)) {
       // don't inline unreached call sites
        set_msg("call site not reached");
        return false;
--- a/src/hotspot/share/opto/parse.hpp	Mon May 06 12:15:55 2019 -0700
+++ b/src/hotspot/share/opto/parse.hpp	Mon May 06 12:17:54 2019 -0700
@@ -88,6 +88,10 @@
                                 ciMethod* caller_method,
                                 JVMState* jvms,
                                 WarmCallInfo* wci_result);
+  bool        is_not_reached(ciMethod* callee_method,
+                             ciMethod* caller_method,
+                             int caller_bci,
+                             ciCallProfile& profile);
   void        print_inlining(ciMethod* callee_method, int caller_bci,
                              ciMethod* caller_method, bool success) const;
 
--- a/src/hotspot/share/runtime/deoptimization.cpp	Mon May 06 12:15:55 2019 -0700
+++ b/src/hotspot/share/runtime/deoptimization.cpp	Mon May 06 12:17:54 2019 -0700
@@ -674,8 +674,7 @@
       int top_frame_expression_stack_adjustment = 0;
       methodHandle mh(thread, iframe->interpreter_frame_method());
       OopMapCache::compute_one_oop_map(mh, iframe->interpreter_frame_bci(), &mask);
-      BytecodeStream str(mh);
-      str.set_start(iframe->interpreter_frame_bci());
+      BytecodeStream str(mh, iframe->interpreter_frame_bci());
       int max_bci = mh->code_size();
       // Get to the next bytecode if possible
       assert(str.bci() < max_bci, "bci in interpreter frame out of bounds");