8221542: ~15% performance degradation due to less optimized inline decision

Reviewed-by: vlivanov, coleenp
This commit is contained in:
Jie Fu 2019-05-06 12:17:54 -07:00
parent 2e0c5db11d
commit 0ff8db34ca
6 changed files with 72 additions and 6 deletions

@ -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 @@ void AbstractInterpreter::set_entry_for_kind(AbstractInterpreter::MethodKind kin
// 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::must_rewrite(code)) {
if (Bytecodes::is_invoke(code)) {
assert(!Bytecodes::must_rewrite(code), "invokes aren't rewritten");
ConstantPool* cpool = method()->constants();
Bytecode invoke_bc(s.bytecode());
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;
}

@ -170,6 +170,10 @@ class BytecodeStream: public BaseBytecodeStream {
// 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;

@ -506,7 +506,7 @@ Method* ConstantPoolCacheEntry::method_if_resolved(const constantPoolHandle& cpo
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(), "");

@ -321,6 +321,35 @@ bool InlineTree::should_not_inline(ciMethod *callee_method,
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 @@ bool InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_method,
// 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;

@ -88,6 +88,10 @@ protected:
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;

@ -674,8 +674,7 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m
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");