Mercurial > hg > graal-jvmci-8
diff src/share/vm/oops/methodData.cpp @ 12882:ce0cc25bc5e2
8026054: New type profiling points: type of return values at calls
Summary: x86 interpreter and c1 type profiling for return values at calls
Reviewed-by: kvn, twisti
author | roland |
---|---|
date | Sat, 12 Oct 2013 12:12:59 +0200 |
parents | d13d7aba8c12 |
children | 5ccbab1c69f3 |
line wrap: on
line diff
--- a/src/share/vm/oops/methodData.cpp Fri Oct 11 19:51:31 2013 -0700 +++ b/src/share/vm/oops/methodData.cpp Sat Oct 12 12:12:59 2013 +0200 @@ -156,16 +156,31 @@ } #endif // !PRODUCT -int TypeStackSlotEntries::compute_cell_count(BytecodeStream* stream) { - int max = TypeProfileArgsLimit; - assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); - Bytecode_invoke inv(stream->method(), stream->bci()); +int TypeStackSlotEntries::compute_cell_count(Symbol* signature, int max) { + ResourceMark rm; + SignatureStream ss(signature); + int args_count = MIN2(ss.reference_parameter_count(), max); + return args_count * per_arg_cell_count; +} - ResourceMark rm; - SignatureStream ss(inv.signature()); - int args_count = MIN2(ss.reference_parameter_count(), max); +int TypeEntriesAtCall::compute_cell_count(BytecodeStream* stream) { + assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); + assert(TypeStackSlotEntries::per_arg_count() > ReturnTypeEntry::static_cell_count(), "code to test for arguments/results broken"); + Bytecode_invoke inv(stream->method(), stream->bci()); + int args_cell = 0; + if (arguments_profiling_enabled()) { + args_cell = TypeStackSlotEntries::compute_cell_count(inv.signature(), TypeProfileArgsLimit); + } + int ret_cell = 0; + if (return_profiling_enabled() && (inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY)) { + ret_cell = ReturnTypeEntry::static_cell_count(); + } + int header_cell = 0; + if (args_cell + ret_cell > 0) { + header_cell = header_cell_count(); + } - return args_count * per_arg_cell_count + (args_count > 0 ? header_cell_count() : 0); + return header_cell + args_cell + ret_cell; } class ArgumentOffsetComputer : public SignatureInfo { @@ -197,26 +212,55 @@ int off_at(int i) const { return _offsets.at(i); } }; -void TypeStackSlotEntries::post_initialize(BytecodeStream* stream) { +void TypeStackSlotEntries::post_initialize(Symbol* signature, bool has_receiver) { ResourceMark rm; + ArgumentOffsetComputer aos(signature, _number_of_entries); + aos.total(); + for (int i = 0; i < _number_of_entries; i++) { + set_stack_slot(i, aos.off_at(i) + (has_receiver ? 1 : 0)); + set_type(i, type_none()); + } +} +void CallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) { assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); Bytecode_invoke inv(stream->method(), stream->bci()); + SignatureStream ss(inv.signature()); + if (has_arguments()) { #ifdef ASSERT - SignatureStream ss(inv.signature()); - int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit); - assert(count > 0, "room for args type but none found?"); - check_number_of_arguments(count); + ResourceMark rm; + int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit); + assert(count > 0, "room for args type but none found?"); + check_number_of_arguments(count); #endif + _args.post_initialize(inv.signature(), inv.has_receiver()); + } + + if (has_return()) { + assert(inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY, "room for a ret type but doesn't return obj?"); + _ret.post_initialize(); + } +} - int start = 0; - ArgumentOffsetComputer aos(inv.signature(), number_of_arguments()-start); - aos.total(); - bool has_receiver = inv.has_receiver(); - for (int i = start; i < number_of_arguments(); i++) { - set_stack_slot(i, aos.off_at(i-start) + (has_receiver ? 1 : 0)); - set_type(i, type_none()); +void VirtualCallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) { + assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); + Bytecode_invoke inv(stream->method(), stream->bci()); + + if (has_arguments()) { +#ifdef ASSERT + ResourceMark rm; + SignatureStream ss(inv.signature()); + int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit); + assert(count > 0, "room for args type but none found?"); + check_number_of_arguments(count); +#endif + _args.post_initialize(inv.signature(), inv.has_receiver()); + } + + if (has_return()) { + assert(inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY, "room for a ret type but doesn't return obj?"); + _ret.post_initialize(); } } @@ -226,7 +270,7 @@ } void TypeStackSlotEntries::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { - for (int i = 0; i < number_of_arguments(); i++) { + for (int i = 0; i < _number_of_entries; i++) { intptr_t p = type(i); if (is_loader_alive(is_alive_cl, p)) { set_type(i, type_none()); @@ -234,7 +278,18 @@ } } -bool TypeStackSlotEntries::arguments_profiling_enabled() { +void ReturnTypeEntry::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { + intptr_t p = type(); + if (is_loader_alive(is_alive_cl, p)) { + set_type(type_none()); + } +} + +bool TypeEntriesAtCall::return_profiling_enabled() { + return MethodData::profile_return(); +} + +bool TypeEntriesAtCall::arguments_profiling_enabled() { return MethodData::profile_arguments(); } @@ -253,9 +308,7 @@ } void TypeStackSlotEntries::print_data_on(outputStream* st) const { - _pd->tab(st, true); - st->print("argument types"); - for (int i = 0; i < number_of_arguments(); i++) { + for (int i = 0; i < _number_of_entries; i++) { _pd->tab(st); st->print("%d: stack(%u) ", i, stack_slot(i)); print_klass(st, type(i)); @@ -263,14 +316,38 @@ } } +void ReturnTypeEntry::print_data_on(outputStream* st) const { + _pd->tab(st); + print_klass(st, type()); + st->cr(); +} + void CallTypeData::print_data_on(outputStream* st) const { CounterData::print_data_on(st); - _args.print_data_on(st); + if (has_arguments()) { + tab(st, true); + st->print("argument types"); + _args.print_data_on(st); + } + if (has_return()) { + tab(st, true); + st->print("return type"); + _ret.print_data_on(st); + } } void VirtualCallTypeData::print_data_on(outputStream* st) const { VirtualCallData::print_data_on(st); - _args.print_data_on(st); + if (has_arguments()) { + tab(st, true); + st->print("argument types"); + _args.print_data_on(st); + } + if (has_return()) { + tab(st, true); + st->print("return type"); + _ret.print_data_on(st); + } } #endif @@ -530,7 +607,7 @@ } case Bytecodes::_invokespecial: case Bytecodes::_invokestatic: - if (MethodData::profile_arguments()) { + if (MethodData::profile_arguments() || MethodData::profile_return()) { return variable_cell_count; } else { return CounterData::static_cell_count(); @@ -542,13 +619,13 @@ return JumpData::static_cell_count(); case Bytecodes::_invokevirtual: case Bytecodes::_invokeinterface: - if (MethodData::profile_arguments()) { + if (MethodData::profile_arguments() || MethodData::profile_return()) { return variable_cell_count; } else { return VirtualCallData::static_cell_count(); } case Bytecodes::_invokedynamic: - if (MethodData::profile_arguments()) { + if (MethodData::profile_arguments() || MethodData::profile_return()) { return variable_cell_count; } else { return CounterData::static_cell_count(); @@ -596,8 +673,9 @@ case Bytecodes::_invokespecial: case Bytecodes::_invokestatic: case Bytecodes::_invokedynamic: - assert(MethodData::profile_arguments(), "should be collecting args profile"); - if (profile_arguments_for_invoke(stream->method(), stream->bci())) { + assert(MethodData::profile_arguments() || MethodData::profile_return(), "should be collecting args profile"); + if (profile_arguments_for_invoke(stream->method(), stream->bci()) || + profile_return_for_invoke(stream->method(), stream->bci())) { cell_count = CallTypeData::compute_cell_count(stream); } else { cell_count = CounterData::static_cell_count(); @@ -605,8 +683,9 @@ break; case Bytecodes::_invokevirtual: case Bytecodes::_invokeinterface: { - assert(MethodData::profile_arguments(), "should be collecting args profile"); - if (profile_arguments_for_invoke(stream->method(), stream->bci())) { + assert(MethodData::profile_arguments() || MethodData::profile_return(), "should be collecting args profile"); + if (profile_arguments_for_invoke(stream->method(), stream->bci()) || + profile_return_for_invoke(stream->method(), stream->bci())) { cell_count = VirtualCallTypeData::compute_cell_count(stream); } else { cell_count = VirtualCallData::static_cell_count(); @@ -699,7 +778,8 @@ case Bytecodes::_invokespecial: case Bytecodes::_invokestatic: { int counter_data_cell_count = CounterData::static_cell_count(); - if (profile_arguments_for_invoke(stream->method(), stream->bci())) { + if (profile_arguments_for_invoke(stream->method(), stream->bci()) || + profile_return_for_invoke(stream->method(), stream->bci())) { cell_count = CallTypeData::compute_cell_count(stream); } else { cell_count = counter_data_cell_count; @@ -721,7 +801,8 @@ case Bytecodes::_invokevirtual: case Bytecodes::_invokeinterface: { int virtual_call_data_cell_count = VirtualCallData::static_cell_count(); - if (profile_arguments_for_invoke(stream->method(), stream->bci())) { + if (profile_arguments_for_invoke(stream->method(), stream->bci()) || + profile_return_for_invoke(stream->method(), stream->bci())) { cell_count = VirtualCallTypeData::compute_cell_count(stream); } else { cell_count = virtual_call_data_cell_count; @@ -736,7 +817,8 @@ case Bytecodes::_invokedynamic: { // %%% should make a type profile for any invokedynamic that takes a ref argument int counter_data_cell_count = CounterData::static_cell_count(); - if (profile_arguments_for_invoke(stream->method(), stream->bci())) { + if (profile_arguments_for_invoke(stream->method(), stream->bci()) || + profile_return_for_invoke(stream->method(), stream->bci())) { cell_count = CallTypeData::compute_cell_count(stream); } else { cell_count = counter_data_cell_count; @@ -778,7 +860,7 @@ break; } assert(tag == DataLayout::multi_branch_data_tag || - (MethodData::profile_arguments() && + ((MethodData::profile_arguments() || MethodData::profile_return()) && (tag == DataLayout::call_type_data_tag || tag == DataLayout::counter_data_tag || tag == DataLayout::virtual_call_type_data_tag || @@ -1111,7 +1193,7 @@ } int MethodData::profile_arguments_flag() { - return TypeProfileLevel; + return TypeProfileLevel % 10; } bool MethodData::profile_arguments() { @@ -1139,3 +1221,31 @@ return profile_jsr292(m, bci); } +int MethodData::profile_return_flag() { + return TypeProfileLevel / 10; +} + +bool MethodData::profile_return() { + return profile_return_flag() > no_type_profile && profile_return_flag() <= type_profile_all; +} + +bool MethodData::profile_return_jsr292_only() { + return profile_return_flag() == type_profile_jsr292; +} + +bool MethodData::profile_all_return() { + return profile_return_flag() == type_profile_all; +} + +bool MethodData::profile_return_for_invoke(methodHandle m, int bci) { + if (!profile_return()) { + return false; + } + + if (profile_all_return()) { + return true; + } + + assert(profile_return_jsr292_only(), "inconsistent"); + return profile_jsr292(m, bci); +}