8221542: ~15% performance degradation due to less optimized inline decision
Reviewed-by: vlivanov, coleenp
This commit is contained in:
parent
2e0c5db11d
commit
0ff8db34ca
src/hotspot/share
interpreter
oops
opto
runtime
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user