mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8221542: ~15% performance degradation due to less optimized inline decision
Reviewed-by: vlivanov, coleenp
This commit is contained in:
parent
2e0c5db11d
commit
0ff8db34ca
6 changed files with 72 additions and 6 deletions
|
@ -28,6 +28,7 @@
|
||||||
#include "compiler/disassembler.hpp"
|
#include "compiler/disassembler.hpp"
|
||||||
#include "interpreter/bytecodeHistogram.hpp"
|
#include "interpreter/bytecodeHistogram.hpp"
|
||||||
#include "interpreter/bytecodeInterpreter.hpp"
|
#include "interpreter/bytecodeInterpreter.hpp"
|
||||||
|
#include "interpreter/bytecodeStream.hpp"
|
||||||
#include "interpreter/interpreter.hpp"
|
#include "interpreter/interpreter.hpp"
|
||||||
#include "interpreter/interpreterRuntime.hpp"
|
#include "interpreter/interpreterRuntime.hpp"
|
||||||
#include "interpreter/interp_masm.hpp"
|
#include "interpreter/interp_masm.hpp"
|
||||||
|
@ -36,6 +37,8 @@
|
||||||
#include "memory/metaspaceShared.hpp"
|
#include "memory/metaspaceShared.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
#include "oops/arrayOop.hpp"
|
#include "oops/arrayOop.hpp"
|
||||||
|
#include "oops/constantPool.hpp"
|
||||||
|
#include "oops/cpCache.inline.hpp"
|
||||||
#include "oops/methodData.hpp"
|
#include "oops/methodData.hpp"
|
||||||
#include "oops/method.hpp"
|
#include "oops/method.hpp"
|
||||||
#include "oops/oop.inline.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
|
// Return true if the interpreter can prove that the given bytecode has
|
||||||
// not yet been executed (in Java semantics, not in actual operation).
|
// not yet been executed (in Java semantics, not in actual operation).
|
||||||
bool AbstractInterpreter::is_not_reached(const methodHandle& method, int bci) {
|
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
|
// might have been reached
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,6 +170,10 @@ class BytecodeStream: public BaseBytecodeStream {
|
||||||
// Construction
|
// Construction
|
||||||
BytecodeStream(const methodHandle& method) : BaseBytecodeStream(method) { }
|
BytecodeStream(const methodHandle& method) : BaseBytecodeStream(method) { }
|
||||||
|
|
||||||
|
BytecodeStream(const methodHandle& method, int bci) : BaseBytecodeStream(method) {
|
||||||
|
set_start(bci);
|
||||||
|
}
|
||||||
|
|
||||||
// Iteration
|
// Iteration
|
||||||
Bytecodes::Code next() {
|
Bytecodes::Code next() {
|
||||||
Bytecodes::Code raw_code, code;
|
Bytecodes::Code raw_code, code;
|
||||||
|
|
|
@ -506,7 +506,7 @@ Method* ConstantPoolCacheEntry::method_if_resolved(const constantPoolHandle& cpo
|
||||||
switch (invoke_code) {
|
switch (invoke_code) {
|
||||||
case Bytecodes::_invokeinterface:
|
case Bytecodes::_invokeinterface:
|
||||||
assert(f1->is_klass(), "");
|
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::_invokestatic:
|
||||||
case Bytecodes::_invokespecial:
|
case Bytecodes::_invokespecial:
|
||||||
assert(!has_appendix(), "");
|
assert(!has_appendix(), "");
|
||||||
|
|
|
@ -321,6 +321,35 @@ bool InlineTree::should_not_inline(ciMethod *callee_method,
|
||||||
return false;
|
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-----------------------------------
|
//-----------------------------try_to_inline-----------------------------------
|
||||||
// return true if ok
|
// return true if ok
|
||||||
// Relocated from "InliningClosure::try_to_inline"
|
// 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.
|
// inline constructors even if they are not reached.
|
||||||
} else if (forced_inline()) {
|
} else if (forced_inline()) {
|
||||||
// Inlining was forced by CompilerOracle, ciReplay or annotation
|
// 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
|
// don't inline unreached call sites
|
||||||
set_msg("call site not reached");
|
set_msg("call site not reached");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -88,6 +88,10 @@ protected:
|
||||||
ciMethod* caller_method,
|
ciMethod* caller_method,
|
||||||
JVMState* jvms,
|
JVMState* jvms,
|
||||||
WarmCallInfo* wci_result);
|
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,
|
void print_inlining(ciMethod* callee_method, int caller_bci,
|
||||||
ciMethod* caller_method, bool success) const;
|
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;
|
int top_frame_expression_stack_adjustment = 0;
|
||||||
methodHandle mh(thread, iframe->interpreter_frame_method());
|
methodHandle mh(thread, iframe->interpreter_frame_method());
|
||||||
OopMapCache::compute_one_oop_map(mh, iframe->interpreter_frame_bci(), &mask);
|
OopMapCache::compute_one_oop_map(mh, iframe->interpreter_frame_bci(), &mask);
|
||||||
BytecodeStream str(mh);
|
BytecodeStream str(mh, iframe->interpreter_frame_bci());
|
||||||
str.set_start(iframe->interpreter_frame_bci());
|
|
||||||
int max_bci = mh->code_size();
|
int max_bci = mh->code_size();
|
||||||
// Get to the next bytecode if possible
|
// Get to the next bytecode if possible
|
||||||
assert(str.bci() < max_bci, "bci in interpreter frame out of bounds");
|
assert(str.bci() < max_bci, "bci in interpreter frame out of bounds");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue