提交 debdc89e 编写于 作者: N never

7050554: JSR 292 - need optimization for selectAlternative

Reviewed-by: kvn, jrose
上级 9afeef74
...@@ -36,6 +36,7 @@ class ciCallProfile : StackObj { ...@@ -36,6 +36,7 @@ class ciCallProfile : StackObj {
private: private:
// Fields are initialized directly by ciMethod::call_profile_at_bci. // Fields are initialized directly by ciMethod::call_profile_at_bci.
friend class ciMethod; friend class ciMethod;
friend class ciMethodHandle;
enum { MorphismLimit = 2 }; // Max call site's morphism we care about enum { MorphismLimit = 2 }; // Max call site's morphism we care about
int _limit; // number of receivers have been determined int _limit; // number of receivers have been determined
...@@ -58,10 +59,10 @@ private: ...@@ -58,10 +59,10 @@ private:
public: public:
// Note: The following predicates return false for invalid profiles: // Note: The following predicates return false for invalid profiles:
bool has_receiver(int i) { return _limit > i; } bool has_receiver(int i) const { return _limit > i; }
int morphism() { return _morphism; } int morphism() const { return _morphism; }
int count() { return _count; } int count() const { return _count; }
int receiver_count(int i) { int receiver_count(int i) {
assert(i < _limit, "out of Call Profile MorphismLimit"); assert(i < _limit, "out of Call Profile MorphismLimit");
return _receiver_count[i]; return _receiver_count[i];
......
...@@ -43,7 +43,7 @@ ciMethod* ciMethodHandle::get_adapter_impl(bool is_invokedynamic) const { ...@@ -43,7 +43,7 @@ ciMethod* ciMethodHandle::get_adapter_impl(bool is_invokedynamic) const {
methodHandle callee(_callee->get_methodOop()); methodHandle callee(_callee->get_methodOop());
// We catch all exceptions here that could happen in the method // We catch all exceptions here that could happen in the method
// handle compiler and stop the VM. // handle compiler and stop the VM.
MethodHandleCompiler mhc(h, callee->name(), callee->signature(), _profile->count(), is_invokedynamic, THREAD); MethodHandleCompiler mhc(h, callee->name(), callee->signature(), _profile.count(), is_invokedynamic, THREAD);
if (!HAS_PENDING_EXCEPTION) { if (!HAS_PENDING_EXCEPTION) {
methodHandle m = mhc.compile(THREAD); methodHandle m = mhc.compile(THREAD);
if (!HAS_PENDING_EXCEPTION) { if (!HAS_PENDING_EXCEPTION) {
......
...@@ -36,7 +36,7 @@ class ciMethodHandle : public ciInstance { ...@@ -36,7 +36,7 @@ class ciMethodHandle : public ciInstance {
private: private:
ciMethod* _callee; ciMethod* _callee;
ciMethod* _caller; ciMethod* _caller;
ciCallProfile* _profile; ciCallProfile _profile;
// Return an adapter for this MethodHandle. // Return an adapter for this MethodHandle.
ciMethod* get_adapter_impl(bool is_invokedynamic) const; ciMethod* get_adapter_impl(bool is_invokedynamic) const;
...@@ -49,8 +49,7 @@ public: ...@@ -49,8 +49,7 @@ public:
ciMethodHandle(instanceHandle h_i) : ciMethodHandle(instanceHandle h_i) :
ciInstance(h_i), ciInstance(h_i),
_callee(NULL), _callee(NULL),
_caller(NULL), _caller(NULL)
_profile(NULL)
{} {}
// What kind of ciObject is this? // What kind of ciObject is this?
...@@ -58,7 +57,7 @@ public: ...@@ -58,7 +57,7 @@ public:
void set_callee(ciMethod* m) { _callee = m; } void set_callee(ciMethod* m) { _callee = m; }
void set_caller(ciMethod* m) { _caller = m; } void set_caller(ciMethod* m) { _caller = m; }
void set_call_profile(ciCallProfile* profile) { _profile = profile; } void set_call_profile(ciCallProfile profile) { _profile = profile; }
// Return an adapter for a MethodHandle call. // Return an adapter for a MethodHandle call.
ciMethod* get_method_handle_adapter() const { return get_adapter(false); } ciMethod* get_method_handle_adapter() const { return get_adapter(false); }
......
...@@ -300,12 +300,23 @@ void CompileTask::print_compilation_impl(outputStream* st, methodOop method, int ...@@ -300,12 +300,23 @@ void CompileTask::print_compilation_impl(outputStream* st, methodOop method, int
st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp
st->print("%4d ", compile_id); // print compilation number st->print("%4d ", compile_id); // print compilation number
// For unloaded methods the transition to zombie occurs after the
// method is cleared so it's impossible to report accurate
// information for that case.
bool is_synchronized = false;
bool has_exception_handler = false;
bool is_native = false;
if (method != NULL) {
is_synchronized = method->is_synchronized();
has_exception_handler = method->has_exception_handler();
is_native = method->is_native();
}
// method attributes // method attributes
const char compile_type = is_osr_method ? '%' : ' '; const char compile_type = is_osr_method ? '%' : ' ';
const char sync_char = method->is_synchronized() ? 's' : ' '; const char sync_char = is_synchronized ? 's' : ' ';
const char exception_char = method->has_exception_handler() ? '!' : ' '; const char exception_char = has_exception_handler ? '!' : ' ';
const char blocking_char = is_blocking ? 'b' : ' '; const char blocking_char = is_blocking ? 'b' : ' ';
const char native_char = method->is_native() ? 'n' : ' '; const char native_char = is_native ? 'n' : ' ';
// print method attributes // print method attributes
st->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, native_char); st->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, native_char);
...@@ -316,11 +327,15 @@ void CompileTask::print_compilation_impl(outputStream* st, methodOop method, int ...@@ -316,11 +327,15 @@ void CompileTask::print_compilation_impl(outputStream* st, methodOop method, int
} }
st->print(" "); // more indent st->print(" "); // more indent
if (method == NULL) {
st->print("(method)");
} else {
method->print_short_name(st); method->print_short_name(st);
if (is_osr_method) { if (is_osr_method) {
st->print(" @ %d", osr_bci); st->print(" @ %d", osr_bci);
} }
st->print(" (%d bytes)", method->code_size()); st->print(" (%d bytes)", method->code_size());
}
if (msg != NULL) { if (msg != NULL) {
st->print(" %s", msg); st->print(" %s", msg);
......
...@@ -698,6 +698,46 @@ CallGenerator* CallGenerator::for_predicted_dynamic_call(ciMethodHandle* predict ...@@ -698,6 +698,46 @@ CallGenerator* CallGenerator::for_predicted_dynamic_call(ciMethodHandle* predict
} }
CallGenerator* CallGenerator::for_method_handle_inline(Node* method_handle, JVMState* jvms,
ciMethod* caller, ciMethod* callee, ciCallProfile profile) {
if (method_handle->Opcode() == Op_ConP) {
const TypeOopPtr* oop_ptr = method_handle->bottom_type()->is_oopptr();
ciObject* const_oop = oop_ptr->const_oop();
ciMethodHandle* method_handle = const_oop->as_method_handle();
// Set the callee to have access to the class and signature in
// the MethodHandleCompiler.
method_handle->set_callee(callee);
method_handle->set_caller(caller);
method_handle->set_call_profile(profile);
// Get an adapter for the MethodHandle.
ciMethod* target_method = method_handle->get_method_handle_adapter();
if (target_method != NULL) {
CallGenerator* hit_cg = Compile::current()->call_generator(target_method, -1, false, jvms, true, 1);
if (hit_cg != NULL && hit_cg->is_inline())
return hit_cg;
}
} else if (method_handle->Opcode() == Op_Phi && method_handle->req() == 3 &&
method_handle->in(1)->Opcode() == Op_ConP && method_handle->in(2)->Opcode() == Op_ConP) {
// selectAlternative idiom merging two constant MethodHandles.
// Generate a guard so that each can be inlined. We might want to
// do more inputs at later point but this gets the most common
// case.
const TypeOopPtr* oop_ptr = method_handle->in(1)->bottom_type()->is_oopptr();
ciObject* const_oop = oop_ptr->const_oop();
ciMethodHandle* mh = const_oop->as_method_handle();
CallGenerator* cg1 = for_method_handle_inline(method_handle->in(1), jvms, caller, callee, profile);
CallGenerator* cg2 = for_method_handle_inline(method_handle->in(2), jvms, caller, callee, profile);
if (cg1 != NULL && cg2 != NULL) {
return new PredictedDynamicCallGenerator(mh, cg2, cg1, PROB_FAIR);
}
}
return NULL;
}
JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) { JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
GraphKit kit(jvms); GraphKit kit(jvms);
PhaseGVN& gvn = kit.gvn(); PhaseGVN& gvn = kit.gvn();
...@@ -707,6 +747,20 @@ JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) { ...@@ -707,6 +747,20 @@ JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
log->elem("predicted_dynamic_call bci='%d'", jvms->bci()); log->elem("predicted_dynamic_call bci='%d'", jvms->bci());
} }
const TypeOopPtr* predicted_mh_ptr = TypeOopPtr::make_from_constant(_predicted_method_handle, true);
Node* predicted_mh = kit.makecon(predicted_mh_ptr);
Node* bol = NULL;
int bc = jvms->method()->java_code_at_bci(jvms->bci());
if (bc == Bytecodes::_invokespecial) {
// This is the selectAlternative idiom for guardWithTest
Node* receiver = kit.argument(0);
// Check if the MethodHandle is the expected one
Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(receiver, predicted_mh));
bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) );
} else {
assert(bc == Bytecodes::_invokedynamic, "must be");
// Get the constant pool cache from the caller class. // Get the constant pool cache from the caller class.
ciMethod* caller_method = jvms->method(); ciMethod* caller_method = jvms->method();
ciBytecodeStream str(caller_method); ciBytecodeStream str(caller_method);
...@@ -729,11 +783,9 @@ JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) { ...@@ -729,11 +783,9 @@ JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
Node* target_mh = kit.make_load(kit.control(), target_adr, TypeInstPtr::BOTTOM, T_OBJECT); Node* target_mh = kit.make_load(kit.control(), target_adr, TypeInstPtr::BOTTOM, T_OBJECT);
// Check if the MethodHandle is still the same. // Check if the MethodHandle is still the same.
const TypeOopPtr* predicted_mh_ptr = TypeOopPtr::make_from_constant(_predicted_method_handle, true);
Node* predicted_mh = kit.makecon(predicted_mh_ptr);
Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(target_mh, predicted_mh)); Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(target_mh, predicted_mh));
Node* bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) ); bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) );
}
IfNode* iff = kit.create_and_xform_if(kit.control(), bol, _hit_prob, COUNT_UNKNOWN); IfNode* iff = kit.create_and_xform_if(kit.control(), bol, _hit_prob, COUNT_UNKNOWN);
kit.set_control( gvn.transform(new(kit.C, 1) IfTrueNode (iff))); kit.set_control( gvn.transform(new(kit.C, 1) IfTrueNode (iff)));
Node* slow_ctl = gvn.transform(new(kit.C, 1) IfFalseNode(iff)); Node* slow_ctl = gvn.transform(new(kit.C, 1) IfFalseNode(iff));
......
...@@ -111,6 +111,8 @@ class CallGenerator : public ResourceObj { ...@@ -111,6 +111,8 @@ class CallGenerator : public ResourceObj {
static CallGenerator* for_dynamic_call(ciMethod* m); // invokedynamic static CallGenerator* for_dynamic_call(ciMethod* m); // invokedynamic
static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index); // virtual, interface static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index); // virtual, interface
static CallGenerator* for_method_handle_inline(Node* method_handle, JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile);
// How to generate a replace a direct call with an inline version // How to generate a replace a direct call with an inline version
static CallGenerator* for_late_inline(ciMethod* m, CallGenerator* inline_cg); static CallGenerator* for_late_inline(ciMethod* m, CallGenerator* inline_cg);
......
...@@ -123,24 +123,9 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index, ...@@ -123,24 +123,9 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
GraphKit kit(jvms); GraphKit kit(jvms);
Node* n = kit.argument(0); Node* n = kit.argument(0);
if (n->Opcode() == Op_ConP) { CallGenerator* cg = CallGenerator::for_method_handle_inline(n, jvms, caller, call_method, profile);
const TypeOopPtr* oop_ptr = n->bottom_type()->is_oopptr(); if (cg != NULL) {
ciObject* const_oop = oop_ptr->const_oop(); return cg;
ciMethodHandle* method_handle = const_oop->as_method_handle();
// Set the callee to have access to the class and signature in
// the MethodHandleCompiler.
method_handle->set_callee(call_method);
method_handle->set_caller(caller);
method_handle->set_call_profile(&profile);
// Get an adapter for the MethodHandle.
ciMethod* target_method = method_handle->get_method_handle_adapter();
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); return CallGenerator::for_direct_call(call_method);
...@@ -157,7 +142,7 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index, ...@@ -157,7 +142,7 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
// the MethodHandleCompiler. // the MethodHandleCompiler.
method_handle->set_callee(call_method); method_handle->set_callee(call_method);
method_handle->set_caller(caller); method_handle->set_caller(caller);
method_handle->set_call_profile(&profile); method_handle->set_call_profile(profile);
// Get an adapter for the MethodHandle. // Get an adapter for the MethodHandle.
ciMethod* target_method = method_handle->get_invokedynamic_adapter(); ciMethod* target_method = method_handle->get_invokedynamic_adapter();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册