8221542: ~15% performance degradation due to less optimized inline decision
Reviewed-by: vlivanov, coleenp
--- 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");