aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm/c1
diff options
context:
space:
mode:
authorroland <none@none>2013-10-22 09:51:47 +0200
committerroland <none@none>2013-10-22 09:51:47 +0200
commite1b04a791dcebf4477bb6830ffd11efcce4785f6 (patch)
tree5bb1c34522801d9bf57b1400ed7e357cf2ff42ec /src/share/vm/c1
parent6ec3e5836a130e96037f53c662f1b5c34a32ef9d (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.hpp13
-rw-r--r--src/share/vm/c1/c1_GraphBuilder.cpp34
-rw-r--r--src/share/vm/c1/c1_GraphBuilder.hpp7
-rw-r--r--src/share/vm/c1/c1_LIRGenerator.cpp109
-rw-r--r--src/share/vm/c1/c1_LIRGenerator.hpp2
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; }