--- old/src/cpu/x86/vm/interp_masm_x86_32.hpp 2013-10-17 20:38:39.303635820 +0200 +++ new/src/cpu/x86/vm/interp_masm_x86_32.hpp 2013-10-17 20:38:38.861366599 +0200 @@ -218,6 +218,7 @@ void profile_obj_type(Register obj, const Address& mdo_addr); void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual); void profile_return_type(Register mdp, Register ret, Register tmp); + void profile_parameters_type(Register mdp, Register tmp1, Register tmp2); void profile_call(Register mdp); void profile_final_call(Register mdp); void profile_virtual_call(Register receiver, Register mdp, Register scratch2, --- old/src/share/vm/ci/ciMethodData.cpp 2013-10-17 20:38:39.305298807 +0200 +++ new/src/share/vm/ci/ciMethodData.cpp 2013-10-17 20:38:38.967551665 +0200 @@ -53,6 +53,7 @@ _hint_di = first_di(); // Initialize the escape information (to "don't know."); _eflags = _arg_local = _arg_stack = _arg_returned = 0; + _parameters = NULL; } // ------------------------------------------------------------------ @@ -74,6 +75,7 @@ _hint_di = first_di(); // Initialize the escape information (to "don't know."); _eflags = _arg_local = _arg_stack = _arg_returned = 0; + _parameters = NULL; } void ciMethodData::load_data() { @@ -108,6 +110,12 @@ ci_data = next_data(ci_data); data = mdo->next_data(data); } + if (mdo->parameters_type_data() != NULL) { + _parameters = data_layout_at(mdo->parameters_type_data_di()); + ciParametersTypeData* parameters = new ciParametersTypeData(_parameters); + parameters->translate_from(mdo->parameters_type_data()); + } + // Note: Extra data are all BitData, and do not need translation. _current_mileage = MethodData::mileage_of(mdo->method()); _invocation_counter = mdo->invocation_count(); @@ -182,6 +190,8 @@ return new ciCallTypeData(data_layout); case DataLayout::virtual_call_type_data_tag: return new ciVirtualCallTypeData(data_layout); + case DataLayout::parameters_type_data_tag: + return new ciParametersTypeData(data_layout); }; } @@ -318,6 +328,14 @@ } } +void ciMethodData::set_parameter_type(int i, ciKlass* k) { + VM_ENTRY_MARK; + MethodData* mdo = get_MethodData(); + if (mdo != NULL) { + mdo->parameters_type_data()->set_type(i, k->get_Klass()); + } +} + void ciMethodData::set_return_type(int bci, ciKlass* k) { VM_ENTRY_MARK; MethodData* mdo = get_MethodData(); @@ -605,4 +623,9 @@ ret()->print_data_on(st); } } + +void ciParametersTypeData::print_data_on(outputStream* st) const { + st->print_cr("Parametertypes"); + parameters()->print_data_on(st); +} #endif --- old/src/share/vm/c1/c1_LIRGenerator.hpp 2013-10-17 20:38:39.321208060 +0200 +++ new/src/share/vm/c1/c1_LIRGenerator.hpp 2013-10-17 20:38:38.929047036 +0200 @@ -436,6 +436,8 @@ #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; } --- old/src/cpu/x86/vm/interp_masm_x86_32.cpp 2013-10-17 20:38:39.326381579 +0200 +++ new/src/cpu/x86/vm/interp_masm_x86_32.cpp 2013-10-17 20:38:38.895675606 +0200 @@ -1199,6 +1199,52 @@ } } +void InterpreterMacroAssembler::profile_parameters_type(Register mdp, Register tmp1, Register tmp2) { + if (ProfileInterpreter && MethodData::profile_parameters()) { + Label profile_continue, done; + + test_method_data_pointer(mdp, profile_continue); + + // Load the offset of the area within the MDO used for + // parameters. If it's negative we're not profiling any parameters + movl(tmp1, Address(mdp, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset()))); + testl(tmp1, tmp1); + jcc(Assembler::negative, profile_continue); + + // Compute a pointer to the area for parameters from the offset + // and move the pointer to the slot for the last + // parameters. Collect profiling from last parameter down. + // mdo start + parameters offset + array length - 1 + addptr(mdp, tmp1); + movl(tmp1, Address(mdp, in_bytes(ArrayData::array_len_offset()))); + decrement(tmp1, TypeStackSlotEntries::per_arg_count()); + + Label loop; + bind(loop); + + int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0)); + int type_base = in_bytes(ParametersTypeData::type_offset(0)); + Address::ScaleFactor per_arg_scale = Address::times(DataLayout::cell_size); + Address arg_off(mdp, tmp1, per_arg_scale, off_base); + Address arg_type(mdp, tmp1, per_arg_scale, type_base); + + // load offset on the stack from the slot for this parameter + movl(tmp2, arg_off); + negl(tmp2); + // read the parameter from the local area + movptr(tmp2, Address(rdi, tmp2, Interpreter::stackElementScale())); + + // profile the parameter + profile_obj_type(tmp2, arg_type); + + // go to next parameter + decrement(tmp1, TypeStackSlotEntries::per_arg_count()); + jcc(Assembler::positive, loop); + + bind(profile_continue); + } +} + void InterpreterMacroAssembler::profile_call(Register mdp) { if (ProfileInterpreter) { Label profile_continue; --- old/src/cpu/x86/vm/interp_masm_x86_64.cpp 2013-10-17 20:38:39.402563335 +0200 +++ new/src/cpu/x86/vm/interp_masm_x86_64.cpp 2013-10-17 20:38:39.005281133 +0200 @@ -1221,6 +1221,52 @@ } } +void InterpreterMacroAssembler::profile_parameters_type(Register mdp, Register tmp1, Register tmp2) { + if (ProfileInterpreter && MethodData::profile_parameters()) { + Label profile_continue, done; + + test_method_data_pointer(mdp, profile_continue); + + // Load the offset of the area within the MDO used for + // parameters. If it's negative we're not profiling any parameters + movl(tmp1, Address(mdp, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset()))); + testl(tmp1, tmp1); + jcc(Assembler::negative, profile_continue); + + // Compute a pointer to the area for parameters from the offset + // and move the pointer to the slot for the last + // parameters. Collect profiling from last parameter down. + // mdo start + parameters offset + array length - 1 + addptr(mdp, tmp1); + movq(tmp1, Address(mdp, in_bytes(ArrayData::array_len_offset()))); + decrement(tmp1, TypeStackSlotEntries::per_arg_count()); + + Label loop; + bind(loop); + + int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0)); + int type_base = in_bytes(ParametersTypeData::type_offset(0)); + Address::ScaleFactor per_arg_scale = Address::times(DataLayout::cell_size); + Address arg_off(mdp, tmp1, per_arg_scale, off_base); + Address arg_type(mdp, tmp1, per_arg_scale, type_base); + + // load offset on the stack from the slot for this parameter + movq(tmp2, arg_off); + negq(tmp2); + // read the parameter from the local area + movptr(tmp2, Address(r14, tmp2, Interpreter::stackElementScale())); + + // profile the parameter + profile_obj_type(tmp2, arg_type); + + // go to next parameter + decrement(tmp1, TypeStackSlotEntries::per_arg_count()); + jcc(Assembler::positive, loop); + + bind(profile_continue); + } +} + void InterpreterMacroAssembler::profile_call(Register mdp) { if (ProfileInterpreter) { Label profile_continue; --- old/src/share/vm/c1/c1_LIRGenerator.cpp 2013-10-17 20:38:39.432627178 +0200 +++ new/src/share/vm/c1/c1_LIRGenerator.cpp 2013-10-17 20:38:39.119882926 +0200 @@ -2643,6 +2643,39 @@ return result; } +// profile parameters on entry to the root of the compilation +void LIRGenerator::profile_parameters(Base* x) { + if (MethodData::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 @@ -2718,6 +2751,7 @@ // 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,7 +3115,8 @@ 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; @@ -3107,6 +3142,71 @@ 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 (MethodData::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++; + } + } } } } @@ -3121,6 +3221,11 @@ if (x->nb_profiled_args() > 0) { 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); --- old/src/cpu/x86/vm/templateInterpreter_x86_32.cpp 2013-10-17 20:38:39.422380171 +0200 +++ new/src/cpu/x86/vm/templateInterpreter_x86_32.cpp 2013-10-17 20:38:39.078178707 +0200 @@ -1490,6 +1490,7 @@ in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); __ movbool(do_not_unlock_if_synchronized, true); + __ profile_parameters_type(rax, rcx, rdx); // increment invocation count & check for overflow Label invocation_counter_overflow; Label profile_method; --- old/src/share/vm/c1/c1_GraphBuilder.cpp 2013-10-17 20:38:39.450086327 +0200 +++ new/src/share/vm/c1/c1_GraphBuilder.cpp 2013-10-17 20:38:39.048082440 +0200 @@ -1672,15 +1672,23 @@ } // 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"); + bool has_receiver = may_have_receiver && Bytecodes::has_receiver(method()->java_code_at_bci(bci())); + start = has_receiver ? 1 : 0; if (MethodData::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 (MethodData::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 @@ } // 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 @@ } 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); } } @@ -3561,7 +3569,7 @@ 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); } } } @@ -3820,7 +3828,7 @@ 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 --- old/src/share/vm/c1/c1_GraphBuilder.hpp 2013-10-17 20:38:39.597741857 +0200 +++ new/src/share/vm/c1/c1_GraphBuilder.hpp 2013-10-17 20:38:39.186293885 +0200 @@ -387,8 +387,8 @@ bool profile_inlined_calls() { return _compilation->profile_inlined_calls(); } bool profile_checkcasts() { return _compilation->profile_checkcasts(); } - 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();) --- old/src/cpu/x86/vm/templateInterpreter_x86_64.cpp 2013-10-17 20:38:39.571952630 +0200 +++ new/src/cpu/x86/vm/templateInterpreter_x86_64.cpp 2013-10-17 20:38:39.244143512 +0200 @@ -1497,6 +1497,7 @@ in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); __ movbool(do_not_unlock_if_synchronized, true); + __ profile_parameters_type(rax, rcx, rdx); // increment invocation count & check for overflow Label invocation_counter_overflow; Label profile_method; --- old/src/cpu/x86/vm/globals_x86.hpp 2013-10-17 20:38:39.616131625 +0200 +++ new/src/cpu/x86/vm/globals_x86.hpp 2013-10-17 20:38:39.211025618 +0200 @@ -79,7 +79,7 @@ // GC Ergo Flags define_pd_global(uintx, CMSYoungGenPerWorker, 64*M); // default max size of CMS young gen, per GC worker thread -define_pd_global(uintx, TypeProfileLevel, 11); +define_pd_global(uintx, TypeProfileLevel, 111); #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \ \ --- old/src/cpu/x86/vm/interp_masm_x86_64.hpp 2013-10-17 20:38:39.649330764 +0200 +++ new/src/cpu/x86/vm/interp_masm_x86_64.hpp 2013-10-17 20:38:39.160418557 +0200 @@ -227,6 +227,7 @@ void profile_obj_type(Register obj, const Address& mdo_addr); void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual); void profile_return_type(Register mdp, Register ret, Register tmp); + void profile_parameters_type(Register mdp, Register tmp1, Register tmp2); void profile_call(Register mdp); void profile_final_call(Register mdp); void profile_virtual_call(Register receiver, Register mdp, --- old/src/share/vm/ci/ciMethodData.hpp 2013-10-17 20:38:42.014695788 +0200 +++ new/src/share/vm/ci/ciMethodData.hpp 2013-10-17 20:38:41.722162473 +0200 @@ -43,6 +43,7 @@ class ciArgInfoData; class ciCallTypeData; class ciVirtualCallTypeData; +class ciParametersTypeData; typedef ProfileData ciProfileData; @@ -124,7 +125,7 @@ ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)CallTypeData::args(); } ciReturnTypeEntry* ret() const { return (ciReturnTypeEntry*)CallTypeData::ret(); } - void translate_type_data_from(const ProfileData* data) { + void translate_from(const ProfileData* data) { if (has_arguments()) { args()->translate_type_data_from(data->as_CallTypeData()->args()); } @@ -290,6 +291,25 @@ ciArgInfoData(DataLayout* layout) : ArgInfoData(layout) {}; }; +class ciParametersTypeData : public ParametersTypeData { +public: + ciParametersTypeData(DataLayout* layout) : ParametersTypeData(layout) {} + + virtual void translate_from(const ProfileData* data) { + parameters()->translate_type_data_from(data->as_ParametersTypeData()->parameters()); + } + + ciTypeStackSlotEntries* parameters() const { return (ciTypeStackSlotEntries*)ParametersTypeData::parameters(); } + + ciKlass* valid_parameter_type(int i) const { + return parameters()->valid_type(i); + } + +#ifndef PRODUCT + void print_data_on(outputStream* st) const; +#endif +}; + // ciMethodData // // This class represents a MethodData* in the HotSpot virtual @@ -335,6 +355,10 @@ // Coherent snapshot of original header. MethodData _orig; + // Dedicated area dedicated to parameters. Null if no parameter + // profiling for this method. + DataLayout* _parameters; + ciMethodData(MethodData* md); ciMethodData(); @@ -403,6 +427,7 @@ // If the compiler finds a profiled type that is known statically // for sure, set it in the MethodData void set_argument_type(int bci, int i, ciKlass* k); + void set_parameter_type(int i, ciKlass* k); void set_return_type(int bci, ciKlass* k); void load_data(); @@ -467,6 +492,10 @@ bool is_arg_returned(int i) const; uint arg_modified(int arg) const; + ciParametersTypeData* parameters_type_data() const { + return _parameters != NULL ? new ciParametersTypeData(_parameters) : NULL; + } + // Code generation helper ByteSize offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data); int byte_offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data) { return in_bytes(offset_of_slot(data, slot_offset_in_data)); } --- old/src/share/vm/oops/methodData.cpp 2013-10-17 20:38:42.461740285 +0200 +++ new/src/share/vm/oops/methodData.cpp 2013-10-17 20:38:42.231899941 +0200 @@ -41,7 +41,7 @@ // Some types of data layouts need a length field. bool DataLayout::needs_array_len(u1 tag) { - return (tag == multi_branch_data_tag) || (tag == arg_info_data_tag); + return (tag == multi_branch_data_tag) || (tag == arg_info_data_tag) || (tag == parameters_type_data_tag); } // Perform generic initialization of the data. More specific @@ -156,10 +156,13 @@ } #endif // !PRODUCT -int TypeStackSlotEntries::compute_cell_count(Symbol* signature, int max) { +int TypeStackSlotEntries::compute_cell_count(Symbol* signature, bool include_receiver, int max) { + // Parameter profiling include the receiver + int args_count = include_receiver ? 1 : 0; ResourceMark rm; SignatureStream ss(signature); - int args_count = MIN2(ss.reference_parameter_count(), max); + args_count += ss.reference_parameter_count(); + args_count = MIN2(args_count, max); return args_count * per_arg_cell_count; } @@ -169,7 +172,7 @@ Bytecode_invoke inv(stream->method(), stream->bci()); int args_cell = 0; if (arguments_profiling_enabled()) { - args_cell = TypeStackSlotEntries::compute_cell_count(inv.signature(), TypeProfileArgsLimit); + args_cell = TypeStackSlotEntries::compute_cell_count(inv.signature(), false, TypeProfileArgsLimit); } int ret_cell = 0; if (return_profiling_enabled() && (inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY)) { @@ -212,12 +215,19 @@ int off_at(int i) const { return _offsets.at(i); } }; -void TypeStackSlotEntries::post_initialize(Symbol* signature, bool has_receiver) { +void TypeStackSlotEntries::post_initialize(Symbol* signature, bool has_receiver, bool include_receiver) { ResourceMark rm; - ArgumentOffsetComputer aos(signature, _number_of_entries); + int start = 0; + // Parameter profiling include the receiver + if (include_receiver && has_receiver) { + set_stack_slot(0, 0); + set_type(0, type_none()); + start += 1; + } + ArgumentOffsetComputer aos(signature, _number_of_entries-start); aos.total(); - for (int i = 0; i < _number_of_entries; i++) { - set_stack_slot(i, aos.off_at(i) + (has_receiver ? 1 : 0)); + for (int i = start; i < _number_of_entries; i++) { + set_stack_slot(i, aos.off_at(i-start) + (has_receiver ? 1 : 0)); set_type(i, type_none()); } } @@ -234,7 +244,7 @@ assert(count > 0, "room for args type but none found?"); check_number_of_arguments(count); #endif - _args.post_initialize(inv.signature(), inv.has_receiver()); + _args.post_initialize(inv.signature(), inv.has_receiver(), false); } if (has_return()) { @@ -255,7 +265,7 @@ assert(count > 0, "room for args type but none found?"); check_number_of_arguments(count); #endif - _args.post_initialize(inv.signature(), inv.has_receiver()); + _args.post_initialize(inv.signature(), inv.has_receiver(), false); } if (has_return()) { @@ -579,6 +589,34 @@ } #endif + +int ParametersTypeData::compute_cell_count(Method* m) { + if (!MethodData::profile_parameters_for_method(m)) { + return 0; + } + int max = TypeProfileParmsLimit == -1 ? INT_MAX : TypeProfileParmsLimit; + int obj_args = TypeStackSlotEntries::compute_cell_count(m->signature(), !m->is_static(), max); + if (obj_args > 0) { + return obj_args + 1; // 1 cell for array len + } + return 0; +} + +void ParametersTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) { + _parameters.post_initialize(mdo->method()->signature(), !mdo->method()->is_static(), true); +} + +bool ParametersTypeData::profiling_enabled() { + return MethodData::profile_parameters(); +} + +#ifndef PRODUCT +void ParametersTypeData::print_data_on(outputStream* st) const { + st->print("parameter types"); + _parameters.print_data_on(st); +} +#endif + // ================================================================== // MethodData* // @@ -741,6 +779,12 @@ int arg_size = method->size_of_parameters(); object_size += DataLayout::compute_size_in_bytes(arg_size+1); + // Reserve room for an area of the MDO dedicated to profiling of + // parameters + int args_cell = ParametersTypeData::compute_cell_count(method()); + if (args_cell > 0) { + object_size += DataLayout::compute_size_in_bytes(args_cell); + } return object_size; } @@ -915,6 +959,8 @@ return new CallTypeData(this); case DataLayout::virtual_call_type_data_tag: return new VirtualCallTypeData(this); + case DataLayout::parameters_type_data_tag: + return new ParametersTypeData(this); }; } @@ -936,6 +982,9 @@ stream->next(); data->post_initialize(stream, this); } + if (_parameters_type_data_di != -1) { + parameters_type_data()->post_initialize(NULL, this); + } } // Initialize the MethodData* corresponding to a given method. @@ -975,7 +1024,23 @@ int arg_size = method->size_of_parameters(); dp->initialize(DataLayout::arg_info_data_tag, 0, arg_size+1); - object_size += extra_size + DataLayout::compute_size_in_bytes(arg_size+1); + int arg_data_size = DataLayout::compute_size_in_bytes(arg_size+1); + object_size += extra_size + arg_data_size; + + int args_cell = ParametersTypeData::compute_cell_count(method()); + // If we are profiling parameters, we reserver an area near the end + // of the MDO after the slots for bytecodes (because there's no bci + // for method entry so they don't fit with the framework for the + // profiling of bytecodes). We store the offset within the MDO of + // this area (or -1 if no parameter is profiled) + if (args_cell > 0) { + object_size += DataLayout::compute_size_in_bytes(args_cell); + _parameters_type_data_di = data_size + extra_size + arg_data_size; + DataLayout *dp = data_layout_at(data_size + extra_size + arg_data_size); + dp->initialize(DataLayout::parameters_type_data_tag, 0, args_cell); + } else { + _parameters_type_data_di = -1; + } // Set an initial hint. Don't use set_hint_di() because // first_di() may be out of bounds if data_size is 0. @@ -1134,6 +1199,9 @@ void MethodData::print_data_on(outputStream* st) const { ResourceMark rm; ProfileData* data = first_data(); + if (_parameters_type_data_di != -1) { + parameters_type_data()->print_data_on(st); + } for ( ; is_valid(data); data = next_data(data)) { st->print("%d", dp_to_di(data->dp())); st->fill_to(6); @@ -1222,7 +1290,7 @@ } int MethodData::profile_return_flag() { - return TypeProfileLevel / 10; + return (TypeProfileLevel % 100) / 10; } bool MethodData::profile_return() { @@ -1249,3 +1317,32 @@ assert(profile_return_jsr292_only(), "inconsistent"); return profile_jsr292(m, bci); } + +int MethodData::profile_parameters_flag() { + return TypeProfileLevel / 100; +} + +bool MethodData::profile_parameters() { + return profile_parameters_flag() > no_type_profile && profile_parameters_flag() <= type_profile_all; +} + +bool MethodData::profile_parameters_jsr292_only() { + return profile_parameters_flag() == type_profile_jsr292; +} + +bool MethodData::profile_all_parameters() { + return profile_parameters_flag() == type_profile_all; +} + +bool MethodData::profile_parameters_for_method(methodHandle m) { + if (!profile_parameters()) { + return false; + } + + if (profile_all_parameters()) { + return true; + } + + assert(profile_parameters_jsr292_only(), "inconsistent"); + return m->is_compiled_lambda_form(); +} --- old/src/share/vm/oops/methodData.hpp 2013-10-17 20:38:42.458311006 +0200 +++ new/src/share/vm/oops/methodData.hpp 2013-10-17 20:38:42.263150701 +0200 @@ -119,7 +119,8 @@ multi_branch_data_tag, arg_info_data_tag, call_type_data_tag, - virtual_call_type_data_tag + virtual_call_type_data_tag, + parameters_type_data_tag }; enum { @@ -264,6 +265,7 @@ class ArrayData; class MultiBranchData; class ArgInfoData; +class ParametersTypeData; // ProfileData // @@ -397,6 +399,7 @@ virtual bool is_ArgInfoData() const { return false; } virtual bool is_CallTypeData() const { return false; } virtual bool is_VirtualCallTypeData()const { return false; } + virtual bool is_ParametersTypeData() const { return false; } BitData* as_BitData() const { @@ -447,6 +450,10 @@ assert(is_VirtualCallTypeData(), "wrong type"); return is_VirtualCallTypeData() ? (VirtualCallTypeData*)this : NULL; } + ParametersTypeData* as_ParametersTypeData() const { + assert(is_ParametersTypeData(), "wrong type"); + return is_ParametersTypeData() ? (ParametersTypeData*)this : NULL; + } // Subclass specific initialization @@ -767,9 +774,9 @@ TypeStackSlotEntries(int base_off, int nb_entries) : TypeEntries(base_off), _number_of_entries(nb_entries) {} - static int compute_cell_count(Symbol* signature, int max); + static int compute_cell_count(Symbol* signature, bool include_receiver, int max); - void post_initialize(Symbol* signature, bool has_receiver); + void post_initialize(Symbol* signature, bool has_receiver, bool include_receiver); // offset of cell for stack slot for entry i within this block of cells for a TypeStackSlotEntries static int stack_slot_local_offset(int i) { @@ -946,17 +953,6 @@ assert(number_of_arguments() == total, "should be set in DataLayout::initialize"); } -protected: - // An entry for a return value takes less space than an entry for an - // argument so if the number of cells exceeds the number of cells - // needed for an argument, this object contains type information for - // at least one argument. - bool has_arguments() const { - bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count(); - assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); - return res; - } - public: CallTypeData(DataLayout* layout) : CounterData(layout), @@ -1018,6 +1014,16 @@ } // An entry for a return value takes less space than an entry for an + // argument so if the number of cells exceeds the number of cells + // needed for an argument, this object contains type information for + // at least one argument. + bool has_arguments() const { + bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count(); + assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); + return res; + } + + // An entry for a return value takes less space than an entry for an // argument, so if the remainder of the number of cells divided by // the number of cells for an argument is not null, a return value // is profiled in this object. @@ -1213,17 +1219,6 @@ assert(number_of_arguments() == total, "should be set in DataLayout::initialize"); } -protected: - // An entry for a return value takes less space than an entry for an - // argument so if the number of cells exceeds the number of cells - // needed for an argument, this object contains type information for - // at least one argument. - bool has_arguments() const { - bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count(); - assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); - return res; - } - public: VirtualCallTypeData(DataLayout* layout) : VirtualCallData(layout), @@ -1294,6 +1289,16 @@ return res; } + // An entry for a return value takes less space than an entry for an + // argument so if the number of cells exceeds the number of cells + // needed for an argument, this object contains type information for + // at least one argument. + bool has_arguments() const { + bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count(); + assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments"); + return res; + } + // Code generation support static ByteSize args_data_offset() { return cell_offset(VirtualCallData::static_cell_count()) + TypeEntriesAtCall::args_data_offset(); @@ -1662,6 +1667,75 @@ #endif }; +// ParametersTypeData +// +// A ParametersTypeData is used to access profiling information about +// types of parameters to a method +class ParametersTypeData : public ArrayData { + +private: + TypeStackSlotEntries _parameters; + + static int stack_slot_local_offset(int i) { + assert_profiling_enabled(); + return array_start_off_set + TypeStackSlotEntries::stack_slot_local_offset(i); + } + + static int type_local_offset(int i) { + assert_profiling_enabled(); + return array_start_off_set + TypeStackSlotEntries::type_local_offset(i); + } + + static bool profiling_enabled(); + static void assert_profiling_enabled() { + assert(profiling_enabled(), "method parameters profiling should be on"); + } + +public: + ParametersTypeData(DataLayout* layout) : ArrayData(layout), _parameters(1, number_of_parameters()) { + assert(layout->tag() == DataLayout::parameters_type_data_tag, "wrong type"); + // Some compilers (VC++) don't want this passed in member initialization list + _parameters.set_profile_data(this); + } + + static int compute_cell_count(Method* m); + + virtual bool is_ParametersTypeData() const { return true; } + + virtual void post_initialize(BytecodeStream* stream, MethodData* mdo); + + int number_of_parameters() const { + return array_len() / TypeStackSlotEntries::per_arg_count(); + } + + const TypeStackSlotEntries* parameters() const { return &_parameters; } + + uint stack_slot(int i) const { + return _parameters.stack_slot(i); + } + + void set_type(int i, Klass* k) { + intptr_t current = _parameters.type(i); + _parameters.set_type(i, TypeEntries::with_status((intptr_t)k, current)); + } + + virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) { + _parameters.clean_weak_klass_links(is_alive_closure); + } + +#ifndef PRODUCT + virtual void print_data_on(outputStream* st) const; +#endif + + static ByteSize stack_slot_offset(int i) { + return cell_offset(stack_slot_local_offset(i)); + } + + static ByteSize type_offset(int i) { + return cell_offset(type_local_offset(i)); + } +}; + // MethodData* // // A MethodData* holds information which has been collected about @@ -1773,6 +1847,10 @@ // Size of _data array in bytes. (Excludes header and extra_data fields.) int _data_size; + // Offset with the MDO for the area dedicated to + // parameters. -1 if no parameter profiling. + int _parameters_type_data_di; + // Beginning of the data entries intptr_t _data[1]; @@ -1842,6 +1920,9 @@ static int profile_return_flag(); static bool profile_all_return(); static bool profile_return_for_invoke(methodHandle m, int bci); + static int profile_parameters_flag(); + static bool profile_parameters_jsr292_only(); + static bool profile_all_parameters(); public: static int header_size() { @@ -2048,6 +2129,16 @@ } } + // Return pointer to area dedicated to parameters in MDO + ParametersTypeData* parameters_type_data() const { + return _parameters_type_data_di != -1 ? data_layout_at(_parameters_type_data_di)->data_in()->as_ParametersTypeData() : NULL; + } + + int parameters_type_data_di() const { + assert(_parameters_type_data_di != -1, "no args type data"); + return _parameters_type_data_di; + } + // Support for code generation static ByteSize data_offset() { return byte_offset_of(MethodData, _data[0]); @@ -2060,6 +2151,10 @@ return byte_offset_of(MethodData, _backedge_counter); } + static ByteSize parameters_type_data_di_offset() { + return byte_offset_of(MethodData, _parameters_type_data_di); + } + // Deallocation support - no pointer fields to deallocate void deallocate_contents(ClassLoaderData* loader_data) {} @@ -2083,8 +2178,10 @@ void verify_on(outputStream* st); void verify_data_on(outputStream* st); + static bool profile_parameters_for_method(methodHandle m); static bool profile_arguments(); static bool profile_return(); + static bool profile_parameters(); static bool profile_return_jsr292_only(); }; --- old/src/share/vm/runtime/globals.hpp 2013-10-17 20:38:42.541729363 +0200 +++ new/src/share/vm/runtime/globals.hpp 2013-10-17 20:38:42.307223478 +0200 @@ -2678,13 +2678,18 @@ "Enable aggressive optimizations - see arguments.cpp") \ \ product_pd(uintx, TypeProfileLevel, \ - "=XY, with Y, Type profiling of arguments at call" \ - " X, Type profiling of return value at call" \ - "X and Y in 0->off ; 1->js292 only; 2->all methods") \ + "=XYZ, with Z, Type profiling of arguments at call" \ + " Y, Type profiling of return value at call" \ + " X, Type profiling of parameters to methods" \ + "X, Y and Z in 0->off ; 1->js292 only; 2->all methods") \ \ product(intx, TypeProfileArgsLimit, 2, \ "max number of call arguments to consider for type profiling") \ \ + product(intx, TypeProfileParmsLimit, 2, \ + "max number of incoming parameters to consider for type profiling"\ + "-1 for all") \ + \ /* statistics */ \ develop(bool, CountCompiledCalls, false, \ "Count method invocations") \ --- old/src/share/vm/runtime/java.cpp 2013-10-17 20:38:43.860210553 +0200 +++ new/src/share/vm/runtime/java.cpp 2013-10-17 20:38:43.661442737 +0200 @@ -193,6 +193,11 @@ m->print_invocation_count(); tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes()); tty->cr(); + // Dump data on parameters if any + if (m->method_data() != NULL && m->method_data()->parameters_type_data() != NULL) { + tty->fill_to(2); + m->method_data()->parameters_type_data()->print_data_on(tty); + } m->print_codes(); total_size += m->method_data()->size_in_bytes(); }