diff options
author | roland <none@none> | 2013-10-22 09:51:47 +0200 |
---|---|---|
committer | roland <none@none> | 2013-10-22 09:51:47 +0200 |
commit | e1b04a791dcebf4477bb6830ffd11efcce4785f6 (patch) | |
tree | 5bb1c34522801d9bf57b1400ed7e357cf2ff42ec /src/share/vm/c1 | |
parent | 6ec3e5836a130e96037f53c662f1b5c34a32ef9d (diff) |
8026251: New type profiling points: parameters to methods
Summary: x86 interpreter and c1 type profiling for parameters on method entries
Reviewed-by: kvn, twisti
Diffstat (limited to 'src/share/vm/c1')
-rw-r--r-- | src/share/vm/c1/c1_Compilation.hpp | 13 | ||||
-rw-r--r-- | src/share/vm/c1/c1_GraphBuilder.cpp | 34 | ||||
-rw-r--r-- | src/share/vm/c1/c1_GraphBuilder.hpp | 7 | ||||
-rw-r--r-- | src/share/vm/c1/c1_LIRGenerator.cpp | 109 | ||||
-rw-r--r-- | src/share/vm/c1/c1_LIRGenerator.hpp | 2 |
5 files changed, 147 insertions, 18 deletions
diff --git a/src/share/vm/c1/c1_Compilation.hpp b/src/share/vm/c1/c1_Compilation.hpp index 7386dc414..679ff609a 100644 --- a/src/share/vm/c1/c1_Compilation.hpp +++ b/src/share/vm/c1/c1_Compilation.hpp @@ -238,7 +238,18 @@ class Compilation: public StackObj { return env()->comp_level() == CompLevel_full_profile && C1UpdateMethodData && C1ProfileCheckcasts; } - + bool profile_parameters() { + return env()->comp_level() == CompLevel_full_profile && + C1UpdateMethodData && MethodData::profile_parameters(); + } + bool profile_arguments() { + return env()->comp_level() == CompLevel_full_profile && + C1UpdateMethodData && MethodData::profile_arguments(); + } + bool profile_return() { + return env()->comp_level() == CompLevel_full_profile && + C1UpdateMethodData && MethodData::profile_return(); + } // will compilation make optimistic assumptions that might lead to // deoptimization and that the runtime will account for? bool is_optimistic() const { diff --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp index 23d800528..2ac2cceed 100644 --- a/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/src/share/vm/c1/c1_GraphBuilder.cpp @@ -1470,7 +1470,7 @@ void GraphBuilder::method_return(Value x) { set_state(state()->caller_state()->copy_for_parsing()); if (x != NULL) { state()->push(x->type(), x); - if (profile_calls() && MethodData::profile_return() && x->type()->is_object_kind()) { + if (profile_return() && x->type()->is_object_kind()) { ciMethod* caller = state()->scope()->method(); ciMethodData* md = caller->method_data_or_null(); ciProfileData* data = md->bci_to_data(invoke_bci); @@ -1672,15 +1672,23 @@ Dependencies* GraphBuilder::dependency_recorder() const { } // How many arguments do we want to profile? -Values* GraphBuilder::args_list_for_profiling(int& start, bool may_have_receiver) { +Values* GraphBuilder::args_list_for_profiling(ciMethod* target, int& start, bool may_have_receiver) { int n = 0; - assert(start == 0, "should be initialized"); - if (MethodData::profile_arguments()) { + bool has_receiver = may_have_receiver && Bytecodes::has_receiver(method()->java_code_at_bci(bci())); + start = has_receiver ? 1 : 0; + if (profile_arguments()) { ciProfileData* data = method()->method_data()->bci_to_data(bci()); if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) { n = data->is_CallTypeData() ? data->as_CallTypeData()->number_of_arguments() : data->as_VirtualCallTypeData()->number_of_arguments(); - bool has_receiver = may_have_receiver && Bytecodes::has_receiver(method()->java_code_at_bci(bci())); - start = has_receiver ? 1 : 0; + } + } + // If we are inlining then we need to collect arguments to profile parameters for the target + if (profile_parameters() && target != NULL) { + if (target->method_data() != NULL && target->method_data()->parameters_type_data() != NULL) { + // The receiver is profiled on method entry so it's included in + // the number of parameters but here we're only interested in + // actual arguments. + n = MAX2(n, target->method_data()->parameters_type_data()->number_of_parameters() - start); } } if (n > 0) { @@ -1690,9 +1698,9 @@ Values* GraphBuilder::args_list_for_profiling(int& start, bool may_have_receiver } // Collect arguments that we want to profile in a list -Values* GraphBuilder::collect_args_for_profiling(Values* args, bool may_have_receiver) { +Values* GraphBuilder::collect_args_for_profiling(Values* args, ciMethod* target, bool may_have_receiver) { int start = 0; - Values* obj_args = args_list_for_profiling(start, may_have_receiver); + Values* obj_args = args_list_for_profiling(target, start, may_have_receiver); if (obj_args == NULL) { return NULL; } @@ -2006,7 +2014,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) { } else if (exact_target != NULL) { target_klass = exact_target->holder(); } - profile_call(target, recv, target_klass, collect_args_for_profiling(args, false), false); + profile_call(target, recv, target_klass, collect_args_for_profiling(args, NULL, false), false); } } @@ -2021,7 +2029,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) { push(result_type, result); } } - if (profile_calls() && MethodData::profile_return() && result_type->is_object_kind()) { + if (profile_return() && result_type->is_object_kind()) { profile_return_type(result, target); } } @@ -3561,7 +3569,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) { recv = args->at(0); null_check(recv); } - profile_call(callee, recv, NULL, collect_args_for_profiling(args, true), true); + profile_call(callee, recv, NULL, collect_args_for_profiling(args, callee, true), true); } } } @@ -3572,7 +3580,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) { Value value = append_split(result); if (result_type != voidType) push(result_type, value); - if (callee != method() && profile_calls() && MethodData::profile_return() && result_type->is_object_kind()) { + if (callee != method() && profile_return() && result_type->is_object_kind()) { profile_return_type(result, callee); } @@ -3820,7 +3828,7 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode if (profile_calls()) { int start = 0; - Values* obj_args = args_list_for_profiling(start, has_receiver); + Values* obj_args = args_list_for_profiling(callee, start, has_receiver); if (obj_args != NULL) { int s = obj_args->size(); // if called through method handle invoke, some arguments may have been popped diff --git a/src/share/vm/c1/c1_GraphBuilder.hpp b/src/share/vm/c1/c1_GraphBuilder.hpp index 7945674fc..ce83cb73f 100644 --- a/src/share/vm/c1/c1_GraphBuilder.hpp +++ b/src/share/vm/c1/c1_GraphBuilder.hpp @@ -386,9 +386,12 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC { bool profile_calls() { return _compilation->profile_calls(); } bool profile_inlined_calls() { return _compilation->profile_inlined_calls(); } bool profile_checkcasts() { return _compilation->profile_checkcasts(); } + bool profile_parameters() { return _compilation->profile_parameters(); } + bool profile_arguments() { return _compilation->profile_arguments(); } + bool profile_return() { return _compilation->profile_return(); } - Values* args_list_for_profiling(int& start, bool may_have_receiver); - Values* collect_args_for_profiling(Values* args, bool may_have_receiver); + Values* args_list_for_profiling(ciMethod* target, int& start, bool may_have_receiver); + Values* collect_args_for_profiling(Values* args, ciMethod* target, bool may_have_receiver); public: NOT_PRODUCT(void print_stats();) diff --git a/src/share/vm/c1/c1_LIRGenerator.cpp b/src/share/vm/c1/c1_LIRGenerator.cpp index 7b773b7a1..44ad61f64 100644 --- a/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/src/share/vm/c1/c1_LIRGenerator.cpp @@ -2647,6 +2647,39 @@ ciKlass* LIRGenerator::profile_arg_type(ciMethodData* md, int md_base_offset, in return result; } +// profile parameters on entry to the root of the compilation +void LIRGenerator::profile_parameters(Base* x) { + if (compilation()->profile_parameters()) { + CallingConvention* args = compilation()->frame_map()->incoming_arguments(); + ciMethodData* md = scope()->method()->method_data_or_null(); + assert(md != NULL, "Sanity"); + + if (md->parameters_type_data() != NULL) { + ciParametersTypeData* parameters_type_data = md->parameters_type_data(); + ciTypeStackSlotEntries* parameters = parameters_type_data->parameters(); + LIR_Opr mdp = LIR_OprFact::illegalOpr; + for (int java_index = 0, i = 0, j = 0; j < parameters_type_data->number_of_parameters(); i++) { + LIR_Opr src = args->at(i); + assert(!src->is_illegal(), "check"); + BasicType t = src->type(); + if (t == T_OBJECT || t == T_ARRAY) { + intptr_t profiled_k = parameters->type(j); + Local* local = x->state()->local_at(java_index)->as_Local(); + ciKlass* exact = profile_arg_type(md, md->byte_offset_of_slot(parameters_type_data, ParametersTypeData::type_offset(0)), + in_bytes(ParametersTypeData::type_offset(j)) - in_bytes(ParametersTypeData::type_offset(0)), + profiled_k, local, mdp, false, local->declared_type()->as_klass()); + // If the profile is known statically set it once for all and do not emit any code + if (exact != NULL) { + md->set_parameter_type(j, exact); + } + j++; + } + java_index += type2size[t]; + } + } + } +} + void LIRGenerator::do_Base(Base* x) { __ std_entry(LIR_OprFact::illegalOpr); // Emit moves from physical registers / stack slots to virtual registers @@ -2722,6 +2755,7 @@ void LIRGenerator::do_Base(Base* x) { // increment invocation counters if needed if (!method()->is_accessor()) { // Accessors do not have MDOs, so no counting. + profile_parameters(x); CodeEmitInfo* info = new CodeEmitInfo(scope()->start()->state()->copy(ValueStack::StateBefore, SynchronizationEntryBCI), NULL, false); increment_invocation_counter(info); } @@ -3081,11 +3115,12 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) { } void LIRGenerator::profile_arguments(ProfileCall* x) { - if (MethodData::profile_arguments()) { + if (compilation()->profile_arguments()) { int bci = x->bci_of_invoke(); ciMethodData* md = x->method()->method_data_or_null(); ciProfileData* data = md->bci_to_data(bci); - if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) { + if ((data->is_CallTypeData() && data->as_CallTypeData()->has_arguments()) || + (data->is_VirtualCallTypeData() && data->as_VirtualCallTypeData()->has_arguments())) { ByteSize extra = data->is_CallTypeData() ? CallTypeData::args_data_offset() : VirtualCallTypeData::args_data_offset(); int base_offset = md->byte_offset_of_slot(data, extra); LIR_Opr mdp = LIR_OprFact::illegalOpr; @@ -3111,6 +3146,71 @@ void LIRGenerator::profile_arguments(ProfileCall* x) { md->set_argument_type(bci, i, exact); } } + } else { +#ifdef ASSERT + Bytecodes::Code code = x->method()->raw_code_at_bci(x->bci_of_invoke()); + int n = x->nb_profiled_args(); + assert(MethodData::profile_parameters() && x->inlined() && + ((code == Bytecodes::_invokedynamic && n <= 1) || (code == Bytecodes::_invokehandle && n <= 2)), + "only at JSR292 bytecodes"); +#endif + } + } +} + +// profile parameters on entry to an inlined method +void LIRGenerator::profile_parameters_at_call(ProfileCall* x) { + if (compilation()->profile_parameters() && x->inlined()) { + ciMethodData* md = x->callee()->method_data_or_null(); + if (md != NULL) { + ciParametersTypeData* parameters_type_data = md->parameters_type_data(); + if (parameters_type_data != NULL) { + ciTypeStackSlotEntries* parameters = parameters_type_data->parameters(); + LIR_Opr mdp = LIR_OprFact::illegalOpr; + bool has_receiver = !x->callee()->is_static(); + ciSignature* sig = x->callee()->signature(); + ciSignatureStream sig_stream(sig, has_receiver ? x->callee()->holder() : NULL); + int i = 0; // to iterate on the Instructions + Value arg = x->recv(); + bool not_null = false; + int bci = x->bci_of_invoke(); + Bytecodes::Code bc = x->method()->java_code_at_bci(bci); + // The first parameter is the receiver so that's what we start + // with if it exists. On exception if method handle call to + // virtual method has receiver in the args list + if (arg == NULL || !Bytecodes::has_receiver(bc)) { + i = 1; + arg = x->profiled_arg_at(0); + not_null = !x->arg_needs_null_check(0); + } + int k = 0; // to iterate on the profile data + for (;;) { + intptr_t profiled_k = parameters->type(k); + ciKlass* exact = profile_arg_type(md, md->byte_offset_of_slot(parameters_type_data, ParametersTypeData::type_offset(0)), + in_bytes(ParametersTypeData::type_offset(k)) - in_bytes(ParametersTypeData::type_offset(0)), + profiled_k, arg, mdp, not_null, sig_stream.next_klass()); + // If the profile is known statically set it once for all and do not emit any code + if (exact != NULL) { + md->set_parameter_type(k, exact); + } + k++; + if (k >= parameters_type_data->number_of_parameters()) { +#ifdef ASSERT + int extra = 0; + if (MethodData::profile_arguments() && TypeProfileParmsLimit != -1 && + x->nb_profiled_args() >= TypeProfileParmsLimit && + x->recv() != NULL && Bytecodes::has_receiver(bc)) { + extra += 1; + } + assert(i == x->nb_profiled_args() - extra || (TypeProfileParmsLimit != -1 && TypeProfileArgsLimit > TypeProfileParmsLimit), "unused parameters?"); +#endif + break; + } + arg = x->profiled_arg_at(i); + not_null = !x->arg_needs_null_check(i); + i++; + } + } } } } @@ -3126,6 +3226,11 @@ void LIRGenerator::do_ProfileCall(ProfileCall* x) { profile_arguments(x); } + // profile parameters on inlined method entry including receiver + if (x->recv() != NULL || x->nb_profiled_args() > 0) { + profile_parameters_at_call(x); + } + if (x->recv() != NULL) { LIRItem value(x->recv(), this); value.load_item(); diff --git a/src/share/vm/c1/c1_LIRGenerator.hpp b/src/share/vm/c1/c1_LIRGenerator.hpp index 05399e590..f0c640da9 100644 --- a/src/share/vm/c1/c1_LIRGenerator.hpp +++ b/src/share/vm/c1/c1_LIRGenerator.hpp @@ -436,6 +436,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { #endif ciKlass* profile_arg_type(ciMethodData* md, int md_first_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_k); void profile_arguments(ProfileCall* x); + void profile_parameters(Base* x); + void profile_parameters_at_call(ProfileCall* x); public: Compilation* compilation() const { return _compilation; } |