提交 a0dc8908 编写于 作者: T twisti

7042122: JSR 292: adjust various inline thresholds for JSR 292 API methods and...

7042122: JSR 292: adjust various inline thresholds for JSR 292 API methods and method handle adapters
Reviewed-by: jrose, never, kvn
上级 653ef337
......@@ -42,7 +42,7 @@ ciMethod* ciMethodHandle::get_adapter(bool is_invokedynamic) const {
methodHandle callee(_callee->get_methodOop());
// We catch all exceptions here that could happen in the method
// handle compiler and stop the VM.
MethodHandleCompiler mhc(h, callee, is_invokedynamic, THREAD);
MethodHandleCompiler mhc(h, callee, call_profile()->count(), is_invokedynamic, THREAD);
if (!HAS_PENDING_EXCEPTION) {
methodHandle m = mhc.compile(THREAD);
if (!HAS_PENDING_EXCEPTION) {
......
......@@ -25,6 +25,7 @@
#ifndef SHARE_VM_CI_CIMETHODHANDLE_HPP
#define SHARE_VM_CI_CIMETHODHANDLE_HPP
#include "ci/ciCallProfile.hpp"
#include "ci/ciInstance.hpp"
#include "prims/methodHandles.hpp"
......@@ -33,7 +34,8 @@
// The class represents a java.lang.invoke.MethodHandle object.
class ciMethodHandle : public ciInstance {
private:
ciMethod* _callee;
ciMethod* _callee;
ciCallProfile* _profile;
// Return an adapter for this MethodHandle.
ciMethod* get_adapter(bool is_invokedynamic) const;
......@@ -50,6 +52,9 @@ public:
ciMethod* callee() const { return _callee; }
void set_callee(ciMethod* m) { _callee = m; }
ciCallProfile* call_profile() const { return _profile; }
void set_call_profile(ciCallProfile* profile) { _profile = profile; }
// Return an adapter for a MethodHandle call.
ciMethod* get_method_handle_adapter() const {
return get_adapter(false);
......
......@@ -89,7 +89,7 @@ static bool is_init_with_ea(ciMethod* callee_method,
}
// positive filter: should send be inlined? returns NULL, if yes, or rejection msg
const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const {
const char* InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const {
// Allows targeted inlining
if(callee_method->should_inline()) {
*wci_result = *(WarmCallInfo::always_hot());
......@@ -102,8 +102,7 @@ const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_m
// positive filter: should send be inlined? returns NULL (--> yes)
// or rejection msg
int max_size = C->max_inline_size();
int size = callee_method->code_size();
int size = callee_method->code_size();
// Check for too many throws (and not too huge)
if(callee_method->interpreter_throwout_count() > InlineThrowCount &&
......@@ -120,18 +119,36 @@ const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_m
return NULL; // size and frequency are represented in a new way
}
int default_max_inline_size = C->max_inline_size();
int inline_small_code_size = InlineSmallCode / 4;
int max_inline_size = default_max_inline_size;
int call_site_count = method()->scale_count(profile.count());
int invoke_count = method()->interpreter_invocation_count();
assert( invoke_count != 0, "Require invokation count greater than zero");
int freq = call_site_count/invoke_count;
// Bytecoded method handle adapters do not have interpreter
// profiling data but only made up MDO data. Get the counter from
// there.
if (caller_method->is_method_handle_adapter()) {
assert(method()->method_data_or_null(), "must have an MDO");
ciMethodData* mdo = method()->method_data();
ciProfileData* mha_profile = mdo->bci_to_data(caller_bci);
assert(mha_profile, "must exist");
CounterData* cd = mha_profile->as_CounterData();
invoke_count = cd->count();
call_site_count = invoke_count; // use the same value
}
assert(invoke_count != 0, "require invocation count greater than zero");
int freq = call_site_count / invoke_count;
// bump the max size if the call is frequent
if ((freq >= InlineFrequencyRatio) ||
(call_site_count >= InlineFrequencyCount) ||
is_init_with_ea(callee_method, caller_method, C)) {
max_size = C->freq_inline_size();
if (size <= max_size && TraceFrequencyInlining) {
max_inline_size = C->freq_inline_size();
if (size <= max_inline_size && TraceFrequencyInlining) {
CompileTask::print_inline_indent(inline_depth());
tty->print_cr("Inlined frequent method (freq=%d count=%d):", freq, call_site_count);
CompileTask::print_inline_indent(inline_depth());
......@@ -141,11 +158,11 @@ const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_m
} else {
// Not hot. Check for medium-sized pre-existing nmethod at cold sites.
if (callee_method->has_compiled_code() &&
callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode/4)
callee_method->instructions_size(CompLevel_full_optimization) > inline_small_code_size)
return "already compiled into a medium method";
}
if (size > max_size) {
if (max_size > C->max_inline_size())
if (size > max_inline_size) {
if (max_inline_size > default_max_inline_size)
return "hot method too big";
return "too big";
}
......@@ -154,7 +171,7 @@ const char* InlineTree::shouldInline(ciMethod* callee_method, ciMethod* caller_m
// negative filter: should send NOT be inlined? returns NULL, ok to inline, or rejection msg
const char* InlineTree::shouldNotInline(ciMethod *callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const {
const char* InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const {
// negative filter: should send NOT be inlined? returns NULL (--> inline) or rejection msg
if (!UseOldInlining) {
const char* fail = NULL;
......@@ -269,14 +286,13 @@ const char* InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_
}
const char *msg = NULL;
if ((msg = shouldInline(callee_method, caller_method, caller_bci,
profile, wci_result)) != NULL) {
msg = should_inline(callee_method, caller_method, caller_bci, profile, wci_result);
if (msg != NULL)
return msg;
}
if ((msg = shouldNotInline(callee_method, caller_method,
wci_result)) != NULL) {
msg = should_not_inline(callee_method, caller_method, wci_result);
if (msg != NULL)
return msg;
}
if (InlineAccessors && callee_method->is_accessor()) {
// accessor methods are not subject to any of the following limits.
......@@ -492,9 +508,8 @@ InlineTree *InlineTree::build_inline_tree_for_callee( ciMethod* callee_method, J
new_depth_adjust -= 1; // don't count method handle calls from java.lang.invoke implem
}
if (new_depth_adjust != 0 && PrintInlining) {
stringStream nm1; caller_jvms->method()->print_name(&nm1);
stringStream nm2; callee_method->print_name(&nm2);
tty->print_cr("discounting inlining depth from %s to %s", nm1.base(), nm2.base());
CompileTask::print_inline_indent(inline_depth());
tty->print_cr(" \\-> discounting inline depth");
}
if (new_depth_adjust != 0 && C->log()) {
int id1 = C->log()->identify(caller_jvms->method());
......
......@@ -73,7 +73,8 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
// Note: When we get profiling during stage-1 compiles, we want to pull
// from more specific profile data which pertains to this inlining.
// Right now, ignore the information in jvms->caller(), and do method[bci].
ciCallProfile profile = jvms->method()->call_profile_at_bci(jvms->bci());
ciCallProfile profile = jvms->method()->call_profile_at_bci(jvms->bci());
Bytecodes::Code bytecode = jvms->method()->java_code_at_bci(jvms->bci());
// See how many times this site has been invoked.
int site_count = profile.count();
......@@ -116,7 +117,7 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
// MethodHandle.invoke* are native methods which obviously don't
// have bytecodes and so normal inlining fails.
if (call_method->is_method_handle_invoke()) {
if (jvms->method()->java_code_at_bci(jvms->bci()) != Bytecodes::_invokedynamic) {
if (bytecode != Bytecodes::_invokedynamic) {
GraphKit kit(jvms);
Node* n = kit.argument(0);
......@@ -128,14 +129,15 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
// Set the actually called method to have access to the class
// and signature in the MethodHandleCompiler.
method_handle->set_callee(call_method);
method_handle->set_call_profile(&profile);
// Get an adapter for the MethodHandle.
ciMethod* target_method = method_handle->get_method_handle_adapter();
CallGenerator* hit_cg = NULL;
if (target_method != NULL)
hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
if (hit_cg != NULL && hit_cg->is_inline())
return hit_cg;
if (target_method != NULL) {
CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
if (hit_cg != NULL && hit_cg->is_inline())
return hit_cg;
}
}
return CallGenerator::for_direct_call(call_method);
......@@ -151,15 +153,16 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
// Set the actually called method to have access to the class
// and signature in the MethodHandleCompiler.
method_handle->set_callee(call_method);
method_handle->set_call_profile(&profile);
// Get an adapter for the MethodHandle.
ciMethod* target_method = method_handle->get_invokedynamic_adapter();
CallGenerator* hit_cg = NULL;
if (target_method != NULL)
hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
if (hit_cg != NULL && hit_cg->is_inline()) {
CallGenerator* miss_cg = CallGenerator::for_dynamic_call(call_method);
return CallGenerator::for_predicted_dynamic_call(method_handle, miss_cg, hit_cg, prof_factor);
if (target_method != NULL) {
CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
if (hit_cg != NULL && hit_cg->is_inline()) {
CallGenerator* miss_cg = CallGenerator::for_dynamic_call(call_method);
return CallGenerator::for_predicted_dynamic_call(method_handle, miss_cg, hit_cg, prof_factor);
}
}
// If something failed, generate a normal dynamic call.
......
......@@ -68,8 +68,8 @@ protected:
JVMState* caller_jvms,
int caller_bci);
const char* try_to_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result);
const char* shouldInline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const;
const char* shouldNotInline(ciMethod* callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const;
const char* should_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const;
const char* should_not_inline(ciMethod* callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const;
void print_inlining(ciMethod *callee_method, int caller_bci, const char *failure_msg) const;
InlineTree *caller_tree() const { return _caller_tree; }
......
......@@ -616,9 +616,10 @@ int MethodHandleWalker::argument_count_slow() {
// -----------------------------------------------------------------------------
// MethodHandleCompiler
MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, bool is_invokedynamic, TRAPS)
MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool is_invokedynamic, TRAPS)
: MethodHandleWalker(root, is_invokedynamic, THREAD),
_callee(callee),
_invoke_count(invoke_count),
_thread(THREAD),
_bytecode(THREAD, 50),
_constants(THREAD, 10),
......@@ -1182,7 +1183,7 @@ constantPoolHandle MethodHandleCompiler::get_constant_pool(TRAPS) const {
methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const {
methodHandle nullHandle;
methodHandle empty;
// Create a method that holds the generated bytecode. invokedynamic
// has no receiver, normal MH calls do.
int flags_bits;
......@@ -1191,13 +1192,16 @@ methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const {
else
flags_bits = (/*JVM_MH_INVOKE_BITS |*/ JVM_ACC_PUBLIC | JVM_ACC_FINAL | JVM_ACC_SYNTHETIC);
methodOop m_oop = oopFactory::new_method(bytecode_length(),
accessFlags_from(flags_bits),
0, 0, 0, oopDesc::IsSafeConc, CHECK_(nullHandle));
methodHandle m(THREAD, m_oop);
m_oop = NULL; // oop not GC safe
// Create a new method
methodHandle m;
{
methodOop m_oop = oopFactory::new_method(bytecode_length(),
accessFlags_from(flags_bits),
0, 0, 0, oopDesc::IsSafeConc, CHECK_(empty));
m = methodHandle(THREAD, m_oop);
}
constantPoolHandle cpool = get_constant_pool(CHECK_(nullHandle));
constantPoolHandle cpool = get_constant_pool(CHECK_(empty));
m->set_constants(cpool());
m->set_name_index(_name_index);
......@@ -1212,16 +1216,32 @@ methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const {
typeArrayHandle exception_handlers(THREAD, Universe::the_empty_int_array());
m->set_exception_table(exception_handlers());
// Set the carry bit of the invocation counter to force inlining of
// the adapter.
// Set the invocation counter's count to the invoke count of the
// original call site.
InvocationCounter* ic = m->invocation_counter();
ic->set_carry_flag();
ic->set(InvocationCounter::wait_for_compile, _invoke_count);
// Rewrite the method and set up the constant pool cache.
objArrayOop m_array = oopFactory::new_system_objArray(1, CHECK_(nullHandle));
objArrayOop m_array = oopFactory::new_system_objArray(1, CHECK_(empty));
objArrayHandle methods(THREAD, m_array);
methods->obj_at_put(0, m());
Rewriter::rewrite(_target_klass(), cpool, methods, CHECK_(nullHandle)); // Use fake class.
Rewriter::rewrite(_target_klass(), cpool, methods, CHECK_(empty)); // Use fake class.
// Create a new MDO
{
methodDataOop mdo = oopFactory::new_methodData(m, CHECK_(empty));
assert(m->method_data() == NULL, "there should not be an MDO yet");
m->set_method_data(mdo);
// Iterate over all profile data and set the count of the counter
// data entries to the original call site counter.
for (ProfileData* pd = mdo->first_data(); mdo->is_valid(pd); pd = mdo->next_data(pd)) {
if (pd->is_CounterData()) {
CounterData* cd = pd->as_CounterData();
cd->set_count(_invoke_count);
}
}
}
#ifndef PRODUCT
if (TraceMethodHandles) {
......
......@@ -247,6 +247,7 @@ public:
class MethodHandleCompiler : public MethodHandleWalker {
private:
methodHandle _callee;
int _invoke_count; // count the original call site has been executed
KlassHandle _rklass; // Return type for casting.
BasicType _rtype;
KlassHandle _target_klass;
......@@ -416,7 +417,7 @@ private:
methodHandle get_method_oop(TRAPS) const;
public:
MethodHandleCompiler(Handle root, methodHandle call_method, bool for_invokedynamic, TRAPS);
MethodHandleCompiler(Handle root, methodHandle call_method, int invoke_count, bool for_invokedynamic, TRAPS);
// Compile the given MH chain into bytecode.
methodHandle compile(TRAPS);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册