Mercurial > hg > truffle
comparison 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 |
comparison
equal
deleted
inserted
replaced
12881:ed2c74787eb5 | 12882:ce0cc25bc5e2 |
---|---|
154 print_shared(st, "JumpData"); | 154 print_shared(st, "JumpData"); |
155 st->print_cr("taken(%u) displacement(%d)", taken(), displacement()); | 155 st->print_cr("taken(%u) displacement(%d)", taken(), displacement()); |
156 } | 156 } |
157 #endif // !PRODUCT | 157 #endif // !PRODUCT |
158 | 158 |
159 int TypeStackSlotEntries::compute_cell_count(BytecodeStream* stream) { | 159 int TypeStackSlotEntries::compute_cell_count(Symbol* signature, int max) { |
160 int max = TypeProfileArgsLimit; | 160 ResourceMark rm; |
161 SignatureStream ss(signature); | |
162 int args_count = MIN2(ss.reference_parameter_count(), max); | |
163 return args_count * per_arg_cell_count; | |
164 } | |
165 | |
166 int TypeEntriesAtCall::compute_cell_count(BytecodeStream* stream) { | |
161 assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); | 167 assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); |
168 assert(TypeStackSlotEntries::per_arg_count() > ReturnTypeEntry::static_cell_count(), "code to test for arguments/results broken"); | |
162 Bytecode_invoke inv(stream->method(), stream->bci()); | 169 Bytecode_invoke inv(stream->method(), stream->bci()); |
163 | 170 int args_cell = 0; |
164 ResourceMark rm; | 171 if (arguments_profiling_enabled()) { |
165 SignatureStream ss(inv.signature()); | 172 args_cell = TypeStackSlotEntries::compute_cell_count(inv.signature(), TypeProfileArgsLimit); |
166 int args_count = MIN2(ss.reference_parameter_count(), max); | 173 } |
167 | 174 int ret_cell = 0; |
168 return args_count * per_arg_cell_count + (args_count > 0 ? header_cell_count() : 0); | 175 if (return_profiling_enabled() && (inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY)) { |
176 ret_cell = ReturnTypeEntry::static_cell_count(); | |
177 } | |
178 int header_cell = 0; | |
179 if (args_cell + ret_cell > 0) { | |
180 header_cell = header_cell_count(); | |
181 } | |
182 | |
183 return header_cell + args_cell + ret_cell; | |
169 } | 184 } |
170 | 185 |
171 class ArgumentOffsetComputer : public SignatureInfo { | 186 class ArgumentOffsetComputer : public SignatureInfo { |
172 private: | 187 private: |
173 int _max; | 188 int _max; |
195 int total() { lazy_iterate_parameters(); return _size; } | 210 int total() { lazy_iterate_parameters(); return _size; } |
196 | 211 |
197 int off_at(int i) const { return _offsets.at(i); } | 212 int off_at(int i) const { return _offsets.at(i); } |
198 }; | 213 }; |
199 | 214 |
200 void TypeStackSlotEntries::post_initialize(BytecodeStream* stream) { | 215 void TypeStackSlotEntries::post_initialize(Symbol* signature, bool has_receiver) { |
201 ResourceMark rm; | 216 ResourceMark rm; |
202 | 217 ArgumentOffsetComputer aos(signature, _number_of_entries); |
218 aos.total(); | |
219 for (int i = 0; i < _number_of_entries; i++) { | |
220 set_stack_slot(i, aos.off_at(i) + (has_receiver ? 1 : 0)); | |
221 set_type(i, type_none()); | |
222 } | |
223 } | |
224 | |
225 void CallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) { | |
203 assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); | 226 assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); |
204 Bytecode_invoke inv(stream->method(), stream->bci()); | 227 Bytecode_invoke inv(stream->method(), stream->bci()); |
205 | 228 |
229 SignatureStream ss(inv.signature()); | |
230 if (has_arguments()) { | |
206 #ifdef ASSERT | 231 #ifdef ASSERT |
207 SignatureStream ss(inv.signature()); | 232 ResourceMark rm; |
208 int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit); | 233 int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit); |
209 assert(count > 0, "room for args type but none found?"); | 234 assert(count > 0, "room for args type but none found?"); |
210 check_number_of_arguments(count); | 235 check_number_of_arguments(count); |
211 #endif | 236 #endif |
212 | 237 _args.post_initialize(inv.signature(), inv.has_receiver()); |
213 int start = 0; | 238 } |
214 ArgumentOffsetComputer aos(inv.signature(), number_of_arguments()-start); | 239 |
215 aos.total(); | 240 if (has_return()) { |
216 bool has_receiver = inv.has_receiver(); | 241 assert(inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY, "room for a ret type but doesn't return obj?"); |
217 for (int i = start; i < number_of_arguments(); i++) { | 242 _ret.post_initialize(); |
218 set_stack_slot(i, aos.off_at(i-start) + (has_receiver ? 1 : 0)); | 243 } |
219 set_type(i, type_none()); | 244 } |
245 | |
246 void VirtualCallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) { | |
247 assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); | |
248 Bytecode_invoke inv(stream->method(), stream->bci()); | |
249 | |
250 if (has_arguments()) { | |
251 #ifdef ASSERT | |
252 ResourceMark rm; | |
253 SignatureStream ss(inv.signature()); | |
254 int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit); | |
255 assert(count > 0, "room for args type but none found?"); | |
256 check_number_of_arguments(count); | |
257 #endif | |
258 _args.post_initialize(inv.signature(), inv.has_receiver()); | |
259 } | |
260 | |
261 if (has_return()) { | |
262 assert(inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY, "room for a ret type but doesn't return obj?"); | |
263 _ret.post_initialize(); | |
220 } | 264 } |
221 } | 265 } |
222 | 266 |
223 bool TypeEntries::is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p) { | 267 bool TypeEntries::is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p) { |
224 return !is_type_none(p) && | 268 return !is_type_none(p) && |
225 !((Klass*)klass_part(p))->is_loader_alive(is_alive_cl); | 269 !((Klass*)klass_part(p))->is_loader_alive(is_alive_cl); |
226 } | 270 } |
227 | 271 |
228 void TypeStackSlotEntries::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { | 272 void TypeStackSlotEntries::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { |
229 for (int i = 0; i < number_of_arguments(); i++) { | 273 for (int i = 0; i < _number_of_entries; i++) { |
230 intptr_t p = type(i); | 274 intptr_t p = type(i); |
231 if (is_loader_alive(is_alive_cl, p)) { | 275 if (is_loader_alive(is_alive_cl, p)) { |
232 set_type(i, type_none()); | 276 set_type(i, type_none()); |
233 } | 277 } |
234 } | 278 } |
235 } | 279 } |
236 | 280 |
237 bool TypeStackSlotEntries::arguments_profiling_enabled() { | 281 void ReturnTypeEntry::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { |
282 intptr_t p = type(); | |
283 if (is_loader_alive(is_alive_cl, p)) { | |
284 set_type(type_none()); | |
285 } | |
286 } | |
287 | |
288 bool TypeEntriesAtCall::return_profiling_enabled() { | |
289 return MethodData::profile_return(); | |
290 } | |
291 | |
292 bool TypeEntriesAtCall::arguments_profiling_enabled() { | |
238 return MethodData::profile_arguments(); | 293 return MethodData::profile_arguments(); |
239 } | 294 } |
240 | 295 |
241 #ifndef PRODUCT | 296 #ifndef PRODUCT |
242 void TypeEntries::print_klass(outputStream* st, intptr_t k) { | 297 void TypeEntries::print_klass(outputStream* st, intptr_t k) { |
251 st->print(" (null seen)"); | 306 st->print(" (null seen)"); |
252 } | 307 } |
253 } | 308 } |
254 | 309 |
255 void TypeStackSlotEntries::print_data_on(outputStream* st) const { | 310 void TypeStackSlotEntries::print_data_on(outputStream* st) const { |
256 _pd->tab(st, true); | 311 for (int i = 0; i < _number_of_entries; i++) { |
257 st->print("argument types"); | |
258 for (int i = 0; i < number_of_arguments(); i++) { | |
259 _pd->tab(st); | 312 _pd->tab(st); |
260 st->print("%d: stack(%u) ", i, stack_slot(i)); | 313 st->print("%d: stack(%u) ", i, stack_slot(i)); |
261 print_klass(st, type(i)); | 314 print_klass(st, type(i)); |
262 st->cr(); | 315 st->cr(); |
263 } | 316 } |
264 } | 317 } |
265 | 318 |
319 void ReturnTypeEntry::print_data_on(outputStream* st) const { | |
320 _pd->tab(st); | |
321 print_klass(st, type()); | |
322 st->cr(); | |
323 } | |
324 | |
266 void CallTypeData::print_data_on(outputStream* st) const { | 325 void CallTypeData::print_data_on(outputStream* st) const { |
267 CounterData::print_data_on(st); | 326 CounterData::print_data_on(st); |
268 _args.print_data_on(st); | 327 if (has_arguments()) { |
328 tab(st, true); | |
329 st->print("argument types"); | |
330 _args.print_data_on(st); | |
331 } | |
332 if (has_return()) { | |
333 tab(st, true); | |
334 st->print("return type"); | |
335 _ret.print_data_on(st); | |
336 } | |
269 } | 337 } |
270 | 338 |
271 void VirtualCallTypeData::print_data_on(outputStream* st) const { | 339 void VirtualCallTypeData::print_data_on(outputStream* st) const { |
272 VirtualCallData::print_data_on(st); | 340 VirtualCallData::print_data_on(st); |
273 _args.print_data_on(st); | 341 if (has_arguments()) { |
342 tab(st, true); | |
343 st->print("argument types"); | |
344 _args.print_data_on(st); | |
345 } | |
346 if (has_return()) { | |
347 tab(st, true); | |
348 st->print("return type"); | |
349 _ret.print_data_on(st); | |
350 } | |
274 } | 351 } |
275 #endif | 352 #endif |
276 | 353 |
277 // ================================================================== | 354 // ================================================================== |
278 // ReceiverTypeData | 355 // ReceiverTypeData |
528 } else { | 605 } else { |
529 return BitData::static_cell_count(); | 606 return BitData::static_cell_count(); |
530 } | 607 } |
531 case Bytecodes::_invokespecial: | 608 case Bytecodes::_invokespecial: |
532 case Bytecodes::_invokestatic: | 609 case Bytecodes::_invokestatic: |
533 if (MethodData::profile_arguments()) { | 610 if (MethodData::profile_arguments() || MethodData::profile_return()) { |
534 return variable_cell_count; | 611 return variable_cell_count; |
535 } else { | 612 } else { |
536 return CounterData::static_cell_count(); | 613 return CounterData::static_cell_count(); |
537 } | 614 } |
538 case Bytecodes::_goto: | 615 case Bytecodes::_goto: |
540 case Bytecodes::_jsr: | 617 case Bytecodes::_jsr: |
541 case Bytecodes::_jsr_w: | 618 case Bytecodes::_jsr_w: |
542 return JumpData::static_cell_count(); | 619 return JumpData::static_cell_count(); |
543 case Bytecodes::_invokevirtual: | 620 case Bytecodes::_invokevirtual: |
544 case Bytecodes::_invokeinterface: | 621 case Bytecodes::_invokeinterface: |
545 if (MethodData::profile_arguments()) { | 622 if (MethodData::profile_arguments() || MethodData::profile_return()) { |
546 return variable_cell_count; | 623 return variable_cell_count; |
547 } else { | 624 } else { |
548 return VirtualCallData::static_cell_count(); | 625 return VirtualCallData::static_cell_count(); |
549 } | 626 } |
550 case Bytecodes::_invokedynamic: | 627 case Bytecodes::_invokedynamic: |
551 if (MethodData::profile_arguments()) { | 628 if (MethodData::profile_arguments() || MethodData::profile_return()) { |
552 return variable_cell_count; | 629 return variable_cell_count; |
553 } else { | 630 } else { |
554 return CounterData::static_cell_count(); | 631 return CounterData::static_cell_count(); |
555 } | 632 } |
556 case Bytecodes::_ret: | 633 case Bytecodes::_ret: |
594 cell_count = MultiBranchData::compute_cell_count(stream); | 671 cell_count = MultiBranchData::compute_cell_count(stream); |
595 break; | 672 break; |
596 case Bytecodes::_invokespecial: | 673 case Bytecodes::_invokespecial: |
597 case Bytecodes::_invokestatic: | 674 case Bytecodes::_invokestatic: |
598 case Bytecodes::_invokedynamic: | 675 case Bytecodes::_invokedynamic: |
599 assert(MethodData::profile_arguments(), "should be collecting args profile"); | 676 assert(MethodData::profile_arguments() || MethodData::profile_return(), "should be collecting args profile"); |
600 if (profile_arguments_for_invoke(stream->method(), stream->bci())) { | 677 if (profile_arguments_for_invoke(stream->method(), stream->bci()) || |
678 profile_return_for_invoke(stream->method(), stream->bci())) { | |
601 cell_count = CallTypeData::compute_cell_count(stream); | 679 cell_count = CallTypeData::compute_cell_count(stream); |
602 } else { | 680 } else { |
603 cell_count = CounterData::static_cell_count(); | 681 cell_count = CounterData::static_cell_count(); |
604 } | 682 } |
605 break; | 683 break; |
606 case Bytecodes::_invokevirtual: | 684 case Bytecodes::_invokevirtual: |
607 case Bytecodes::_invokeinterface: { | 685 case Bytecodes::_invokeinterface: { |
608 assert(MethodData::profile_arguments(), "should be collecting args profile"); | 686 assert(MethodData::profile_arguments() || MethodData::profile_return(), "should be collecting args profile"); |
609 if (profile_arguments_for_invoke(stream->method(), stream->bci())) { | 687 if (profile_arguments_for_invoke(stream->method(), stream->bci()) || |
688 profile_return_for_invoke(stream->method(), stream->bci())) { | |
610 cell_count = VirtualCallTypeData::compute_cell_count(stream); | 689 cell_count = VirtualCallTypeData::compute_cell_count(stream); |
611 } else { | 690 } else { |
612 cell_count = VirtualCallData::static_cell_count(); | 691 cell_count = VirtualCallData::static_cell_count(); |
613 } | 692 } |
614 break; | 693 break; |
697 } | 776 } |
698 break; | 777 break; |
699 case Bytecodes::_invokespecial: | 778 case Bytecodes::_invokespecial: |
700 case Bytecodes::_invokestatic: { | 779 case Bytecodes::_invokestatic: { |
701 int counter_data_cell_count = CounterData::static_cell_count(); | 780 int counter_data_cell_count = CounterData::static_cell_count(); |
702 if (profile_arguments_for_invoke(stream->method(), stream->bci())) { | 781 if (profile_arguments_for_invoke(stream->method(), stream->bci()) || |
782 profile_return_for_invoke(stream->method(), stream->bci())) { | |
703 cell_count = CallTypeData::compute_cell_count(stream); | 783 cell_count = CallTypeData::compute_cell_count(stream); |
704 } else { | 784 } else { |
705 cell_count = counter_data_cell_count; | 785 cell_count = counter_data_cell_count; |
706 } | 786 } |
707 if (cell_count > counter_data_cell_count) { | 787 if (cell_count > counter_data_cell_count) { |
719 tag = DataLayout::jump_data_tag; | 799 tag = DataLayout::jump_data_tag; |
720 break; | 800 break; |
721 case Bytecodes::_invokevirtual: | 801 case Bytecodes::_invokevirtual: |
722 case Bytecodes::_invokeinterface: { | 802 case Bytecodes::_invokeinterface: { |
723 int virtual_call_data_cell_count = VirtualCallData::static_cell_count(); | 803 int virtual_call_data_cell_count = VirtualCallData::static_cell_count(); |
724 if (profile_arguments_for_invoke(stream->method(), stream->bci())) { | 804 if (profile_arguments_for_invoke(stream->method(), stream->bci()) || |
805 profile_return_for_invoke(stream->method(), stream->bci())) { | |
725 cell_count = VirtualCallTypeData::compute_cell_count(stream); | 806 cell_count = VirtualCallTypeData::compute_cell_count(stream); |
726 } else { | 807 } else { |
727 cell_count = virtual_call_data_cell_count; | 808 cell_count = virtual_call_data_cell_count; |
728 } | 809 } |
729 if (cell_count > virtual_call_data_cell_count) { | 810 if (cell_count > virtual_call_data_cell_count) { |
734 break; | 815 break; |
735 } | 816 } |
736 case Bytecodes::_invokedynamic: { | 817 case Bytecodes::_invokedynamic: { |
737 // %%% should make a type profile for any invokedynamic that takes a ref argument | 818 // %%% should make a type profile for any invokedynamic that takes a ref argument |
738 int counter_data_cell_count = CounterData::static_cell_count(); | 819 int counter_data_cell_count = CounterData::static_cell_count(); |
739 if (profile_arguments_for_invoke(stream->method(), stream->bci())) { | 820 if (profile_arguments_for_invoke(stream->method(), stream->bci()) || |
821 profile_return_for_invoke(stream->method(), stream->bci())) { | |
740 cell_count = CallTypeData::compute_cell_count(stream); | 822 cell_count = CallTypeData::compute_cell_count(stream); |
741 } else { | 823 } else { |
742 cell_count = counter_data_cell_count; | 824 cell_count = counter_data_cell_count; |
743 } | 825 } |
744 if (cell_count > counter_data_cell_count) { | 826 if (cell_count > counter_data_cell_count) { |
776 cell_count = MultiBranchData::compute_cell_count(stream); | 858 cell_count = MultiBranchData::compute_cell_count(stream); |
777 tag = DataLayout::multi_branch_data_tag; | 859 tag = DataLayout::multi_branch_data_tag; |
778 break; | 860 break; |
779 } | 861 } |
780 assert(tag == DataLayout::multi_branch_data_tag || | 862 assert(tag == DataLayout::multi_branch_data_tag || |
781 (MethodData::profile_arguments() && | 863 ((MethodData::profile_arguments() || MethodData::profile_return()) && |
782 (tag == DataLayout::call_type_data_tag || | 864 (tag == DataLayout::call_type_data_tag || |
783 tag == DataLayout::counter_data_tag || | 865 tag == DataLayout::counter_data_tag || |
784 tag == DataLayout::virtual_call_type_data_tag || | 866 tag == DataLayout::virtual_call_type_data_tag || |
785 tag == DataLayout::virtual_call_data_tag)) || | 867 tag == DataLayout::virtual_call_data_tag)) || |
786 cell_count == bytecode_cell_count(c), "cell counts must agree"); | 868 cell_count == bytecode_cell_count(c), "cell counts must agree"); |
1109 Bytecode_invoke inv(m , bci); | 1191 Bytecode_invoke inv(m , bci); |
1110 return inv.is_invokedynamic() || inv.is_invokehandle(); | 1192 return inv.is_invokedynamic() || inv.is_invokehandle(); |
1111 } | 1193 } |
1112 | 1194 |
1113 int MethodData::profile_arguments_flag() { | 1195 int MethodData::profile_arguments_flag() { |
1114 return TypeProfileLevel; | 1196 return TypeProfileLevel % 10; |
1115 } | 1197 } |
1116 | 1198 |
1117 bool MethodData::profile_arguments() { | 1199 bool MethodData::profile_arguments() { |
1118 return profile_arguments_flag() > no_type_profile && profile_arguments_flag() <= type_profile_all; | 1200 return profile_arguments_flag() > no_type_profile && profile_arguments_flag() <= type_profile_all; |
1119 } | 1201 } |
1137 | 1219 |
1138 assert(profile_arguments_jsr292_only(), "inconsistent"); | 1220 assert(profile_arguments_jsr292_only(), "inconsistent"); |
1139 return profile_jsr292(m, bci); | 1221 return profile_jsr292(m, bci); |
1140 } | 1222 } |
1141 | 1223 |
1224 int MethodData::profile_return_flag() { | |
1225 return TypeProfileLevel / 10; | |
1226 } | |
1227 | |
1228 bool MethodData::profile_return() { | |
1229 return profile_return_flag() > no_type_profile && profile_return_flag() <= type_profile_all; | |
1230 } | |
1231 | |
1232 bool MethodData::profile_return_jsr292_only() { | |
1233 return profile_return_flag() == type_profile_jsr292; | |
1234 } | |
1235 | |
1236 bool MethodData::profile_all_return() { | |
1237 return profile_return_flag() == type_profile_all; | |
1238 } | |
1239 | |
1240 bool MethodData::profile_return_for_invoke(methodHandle m, int bci) { | |
1241 if (!profile_return()) { | |
1242 return false; | |
1243 } | |
1244 | |
1245 if (profile_all_return()) { | |
1246 return true; | |
1247 } | |
1248 | |
1249 assert(profile_return_jsr292_only(), "inconsistent"); | |
1250 return profile_jsr292(m, bci); | |
1251 } |