diff --git a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index cb4c04a388b82ad072540b233a4d07613a404f3a..115302c9e1a3e6b62b5de0c7ae748e7e9b31ebfa 100644 --- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -3100,6 +3100,10 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { } } +void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { + fatal("Type profiling not implemented on this platform"); +} + void LIR_Assembler::align_backward_branch_target() { __ align(OptoLoopAlignment); } diff --git a/src/cpu/sparc/vm/globals_sparc.hpp b/src/cpu/sparc/vm/globals_sparc.hpp index acffc90f2cf2b7b5575c5bb0da2d54953af4a68f..ecc6eb61524b09a9582c559240e0281333dbe282 100644 --- a/src/cpu/sparc/vm/globals_sparc.hpp +++ b/src/cpu/sparc/vm/globals_sparc.hpp @@ -76,6 +76,8 @@ define_pd_global(bool, UseMembar, false); // GC Ergo Flags define_pd_global(uintx, CMSYoungGenPerWorker, 16*M); // default max size of CMS young gen, per GC worker thread +define_pd_global(uintx, TypeProfileLevel, 0); + #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \ \ product(intx, UseVIS, 99, \ diff --git a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index 94c2c39d26fb4896f45e63d6d527703df114e99d..5ed890cfb4a9eced9d1cb80ba15f2f6595d3b5cc 100644 --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -3632,6 +3632,161 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { } } +void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { + Register obj = op->obj()->as_register(); + Register tmp = op->tmp()->as_pointer_register(); + Address mdo_addr = as_Address(op->mdp()->as_address_ptr()); + ciKlass* exact_klass = op->exact_klass(); + intptr_t current_klass = op->current_klass(); + bool not_null = op->not_null(); + bool no_conflict = op->no_conflict(); + + Label update, next, none; + + bool do_null = !not_null; + bool exact_klass_set = exact_klass != NULL && ciTypeEntries::valid_ciklass(current_klass) == exact_klass; + bool do_update = !TypeEntries::is_type_unknown(current_klass) && !exact_klass_set; + + assert(do_null || do_update, "why are we here?"); + assert(!TypeEntries::was_null_seen(current_klass) || do_update, "why are we here?"); + + __ verify_oop(obj); + + if (tmp != obj) { + __ mov(tmp, obj); + } + if (do_null) { + __ testptr(tmp, tmp); + __ jccb(Assembler::notZero, update); + if (!TypeEntries::was_null_seen(current_klass)) { + __ orptr(mdo_addr, TypeEntries::null_seen); + } + if (do_update) { +#ifndef ASSERT + __ jmpb(next); + } +#else + __ jmp(next); + } + } else { + __ testptr(tmp, tmp); + __ jccb(Assembler::notZero, update); + __ stop("unexpect null obj"); +#endif + } + + __ bind(update); + + if (do_update) { +#ifdef ASSERT + if (exact_klass != NULL) { + Label ok; + __ load_klass(tmp, tmp); + __ push(tmp); + __ mov_metadata(tmp, exact_klass->constant_encoding()); + __ cmpptr(tmp, Address(rsp, 0)); + __ jccb(Assembler::equal, ok); + __ stop("exact klass and actual klass differ"); + __ bind(ok); + __ pop(tmp); + } +#endif + if (!no_conflict) { + if (exact_klass == NULL || TypeEntries::is_type_none(current_klass)) { + if (exact_klass != NULL) { + __ mov_metadata(tmp, exact_klass->constant_encoding()); + } else { + __ load_klass(tmp, tmp); + } + + __ xorptr(tmp, mdo_addr); + __ testptr(tmp, TypeEntries::type_klass_mask); + // klass seen before, nothing to do. The unknown bit may have been + // set already but no need to check. + __ jccb(Assembler::zero, next); + + __ testptr(tmp, TypeEntries::type_unknown); + __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. + + if (TypeEntries::is_type_none(current_klass)) { + __ cmpptr(mdo_addr, 0); + __ jccb(Assembler::equal, none); + __ cmpptr(mdo_addr, TypeEntries::null_seen); + __ jccb(Assembler::equal, none); + // There is a chance that the checks above (re-reading profiling + // data from memory) fail if another thread has just set the + // profiling to this obj's klass + __ xorptr(tmp, mdo_addr); + __ testptr(tmp, TypeEntries::type_klass_mask); + __ jccb(Assembler::zero, next); + } + } else { + assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && + ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only"); + + __ movptr(tmp, mdo_addr); + __ testptr(tmp, TypeEntries::type_unknown); + __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. + } + + // different than before. Cannot keep accurate profile. + __ orptr(mdo_addr, TypeEntries::type_unknown); + + if (TypeEntries::is_type_none(current_klass)) { + __ jmpb(next); + + __ bind(none); + // first time here. Set profile type. + __ movptr(mdo_addr, tmp); + } + } else { + // There's a single possible klass at this profile point + assert(exact_klass != NULL, "should be"); + if (TypeEntries::is_type_none(current_klass)) { + __ mov_metadata(tmp, exact_klass->constant_encoding()); + __ xorptr(tmp, mdo_addr); + __ testptr(tmp, TypeEntries::type_klass_mask); +#ifdef ASSERT + __ jcc(Assembler::zero, next); + + { + Label ok; + __ push(tmp); + __ cmpptr(mdo_addr, 0); + __ jcc(Assembler::equal, ok); + __ cmpptr(mdo_addr, TypeEntries::null_seen); + __ jcc(Assembler::equal, ok); + // may have been set by another thread + __ mov_metadata(tmp, exact_klass->constant_encoding()); + __ xorptr(tmp, mdo_addr); + __ testptr(tmp, TypeEntries::type_mask); + __ jcc(Assembler::zero, ok); + + __ stop("unexpected profiling mismatch"); + __ bind(ok); + __ pop(tmp); + } +#else + __ jccb(Assembler::zero, next); +#endif + // first time here. Set profile type. + __ movptr(mdo_addr, tmp); + } else { + assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && + ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); + + __ movptr(tmp, mdo_addr); + __ testptr(tmp, TypeEntries::type_unknown); + __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. + + __ orptr(mdo_addr, TypeEntries::type_unknown); + } + } + + __ bind(next); + } +} + void LIR_Assembler::emit_delay(LIR_OpDelay*) { Unimplemented(); } diff --git a/src/cpu/x86/vm/globals_x86.hpp b/src/cpu/x86/vm/globals_x86.hpp index c47f7d1c193c3d6338e1c205608984fabb25bdf7..8e8c42fabb6f853f3de3d3599e3088f08472d261 100644 --- a/src/cpu/x86/vm/globals_x86.hpp +++ b/src/cpu/x86/vm/globals_x86.hpp @@ -79,6 +79,8 @@ define_pd_global(bool, UseMembar, false); // 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, 1); + #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \ \ develop(bool, IEEEPrecision, true, \ diff --git a/src/cpu/x86/vm/interp_masm_x86_32.cpp b/src/cpu/x86/vm/interp_masm_x86_32.cpp index 0e7f483a6494b3461ca951a53a22d5d082e9c85f..1a602ae8c09d98f7de363fc7560d592d2e82503b 100644 --- a/src/cpu/x86/vm/interp_masm_x86_32.cpp +++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp @@ -1046,6 +1046,98 @@ void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) { } } +void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { + Label update, next, none; + + verify_oop(obj); + + testptr(obj, obj); + jccb(Assembler::notZero, update); + orptr(mdo_addr, TypeEntries::null_seen); + jmpb(next); + + bind(update); + load_klass(obj, obj); + + xorptr(obj, mdo_addr); + testptr(obj, TypeEntries::type_klass_mask); + jccb(Assembler::zero, next); // klass seen before, nothing to + // do. The unknown bit may have been + // set already but no need to check. + + testptr(obj, TypeEntries::type_unknown); + jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. + + cmpptr(mdo_addr, 0); + jccb(Assembler::equal, none); + cmpptr(mdo_addr, TypeEntries::null_seen); + jccb(Assembler::equal, none); + // There is a chance that the checks above (re-reading profiling + // data from memory) fail if another thread has just set the + // profiling to this obj's klass + xorptr(obj, mdo_addr); + testptr(obj, TypeEntries::type_klass_mask); + jccb(Assembler::zero, next); + + // different than before. Cannot keep accurate profile. + orptr(mdo_addr, TypeEntries::type_unknown); + jmpb(next); + + bind(none); + // first time here. Set profile type. + movptr(mdo_addr, obj); + + bind(next); +} + +void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) { + if (!ProfileInterpreter) { + return; + } + + if (MethodData::profile_arguments()) { + Label profile_continue; + + test_method_data_pointer(mdp, profile_continue); + + int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); + + cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag); + jcc(Assembler::notEqual, profile_continue); + + Label done; + int off_to_args = in_bytes(TypeStackSlotEntries::args_data_offset()); + addptr(mdp, off_to_args); + + for (int i = 0; i < TypeProfileArgsLimit; i++) { + if (i > 0) { + movl(tmp, Address(mdp, in_bytes(TypeStackSlotEntries::cell_count_offset())-off_to_args)); + subl(tmp, i*TypeStackSlotEntries::per_arg_count()); + cmpl(tmp, TypeStackSlotEntries::per_arg_count()); + jcc(Assembler::less, done); + } + movptr(tmp, Address(callee, Method::const_offset())); + load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset())); + subl(tmp, Address(mdp, in_bytes(TypeStackSlotEntries::stack_slot_offset(i))-off_to_args)); + subl(tmp, 1); + Address arg_addr = argument_address(tmp); + movptr(tmp, arg_addr); + + Address mdo_arg_addr(mdp, in_bytes(TypeStackSlotEntries::type_offset(i))-off_to_args); + profile_obj_type(tmp, mdo_arg_addr); + + int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); + addptr(mdp, to_add); + off_to_args += to_add; + } + + bind(done); + + movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp); + + bind(profile_continue); + } +} void InterpreterMacroAssembler::profile_call(Register mdp) { if (ProfileInterpreter) { diff --git a/src/cpu/x86/vm/interp_masm_x86_32.hpp b/src/cpu/x86/vm/interp_masm_x86_32.hpp index 49a41f61d545b28f4548afb19e08934d9ca9ae75..6ccac4a126ee739d3d1fa3a64555844b00a048ac 100644 --- a/src/cpu/x86/vm/interp_masm_x86_32.hpp +++ b/src/cpu/x86/vm/interp_masm_x86_32.hpp @@ -215,6 +215,8 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_taken_branch(Register mdp, Register bumped_count); void profile_not_taken_branch(Register mdp); + 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_call(Register mdp); void profile_final_call(Register mdp); void profile_virtual_call(Register receiver, Register mdp, Register scratch2, diff --git a/src/cpu/x86/vm/interp_masm_x86_64.cpp b/src/cpu/x86/vm/interp_masm_x86_64.cpp index 88d57d046a53bf5863f74fc244b1efb32f6d0c8c..28c7c8b383f9ebccf06b492e4a9875cbdb187b96 100644 --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp @@ -1067,6 +1067,102 @@ void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) { } } +void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { + Label update, next, none; + + verify_oop(obj); + + testptr(obj, obj); + jccb(Assembler::notZero, update); + orptr(mdo_addr, TypeEntries::null_seen); + jmpb(next); + + bind(update); + load_klass(obj, obj); + + xorptr(obj, mdo_addr); + testptr(obj, TypeEntries::type_klass_mask); + jccb(Assembler::zero, next); // klass seen before, nothing to + // do. The unknown bit may have been + // set already but no need to check. + + testptr(obj, TypeEntries::type_unknown); + jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. + + // There is a chance that by the time we do these checks (re-reading + // profiling data from memory) another thread has set the profling + // to this obj's klass and we set the profiling as unknow + // erroneously + cmpptr(mdo_addr, 0); + jccb(Assembler::equal, none); + cmpptr(mdo_addr, TypeEntries::null_seen); + jccb(Assembler::equal, none); + // There is a chance that the checks above (re-reading profiling + // data from memory) fail if another thread has just set the + // profiling to this obj's klass + xorptr(obj, mdo_addr); + testptr(obj, TypeEntries::type_klass_mask); + jccb(Assembler::zero, next); + + // different than before. Cannot keep accurate profile. + orptr(mdo_addr, TypeEntries::type_unknown); + jmpb(next); + + bind(none); + // first time here. Set profile type. + movptr(mdo_addr, obj); + + bind(next); +} + +void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) { + if (!ProfileInterpreter) { + return; + } + + if (MethodData::profile_arguments()) { + Label profile_continue; + + test_method_data_pointer(mdp, profile_continue); + + int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); + + cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag); + jcc(Assembler::notEqual, profile_continue); + + Label done; + int off_to_args = in_bytes(TypeStackSlotEntries::args_data_offset()); + addptr(mdp, off_to_args); + + for (int i = 0; i < TypeProfileArgsLimit; i++) { + if (i > 0) { + movq(tmp, Address(mdp, in_bytes(TypeStackSlotEntries::cell_count_offset())-off_to_args)); + subl(tmp, i*TypeStackSlotEntries::per_arg_count()); + cmpl(tmp, TypeStackSlotEntries::per_arg_count()); + jcc(Assembler::less, done); + } + movptr(tmp, Address(callee, Method::const_offset())); + load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset())); + subq(tmp, Address(mdp, in_bytes(TypeStackSlotEntries::stack_slot_offset(i))-off_to_args)); + subl(tmp, 1); + Address arg_addr = argument_address(tmp); + movptr(tmp, arg_addr); + + Address mdo_arg_addr(mdp, in_bytes(TypeStackSlotEntries::type_offset(i))-off_to_args); + profile_obj_type(tmp, mdo_arg_addr); + + int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); + addptr(mdp, to_add); + off_to_args += to_add; + } + + bind(done); + + movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp); + + bind(profile_continue); + } +} void InterpreterMacroAssembler::profile_call(Register mdp) { if (ProfileInterpreter) { diff --git a/src/cpu/x86/vm/interp_masm_x86_64.hpp b/src/cpu/x86/vm/interp_masm_x86_64.hpp index 8bfc44fe4bc86fb740c8f4c71ad31c4437295f13..2e1ea945c1dc7ea3a7eb0cebf8addebb7f4a0938 100644 --- a/src/cpu/x86/vm/interp_masm_x86_64.hpp +++ b/src/cpu/x86/vm/interp_masm_x86_64.hpp @@ -224,6 +224,8 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_taken_branch(Register mdp, Register bumped_count); void profile_not_taken_branch(Register mdp); + 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_call(Register mdp); void profile_final_call(Register mdp); void profile_virtual_call(Register receiver, Register mdp, diff --git a/src/cpu/x86/vm/macroAssembler_x86.hpp b/src/cpu/x86/vm/macroAssembler_x86.hpp index 293b3b73a371f2ad7f4f0b41c6a240a2e8343108..198fc98e86ae9bba6ab252d10604c81f135d8033 100644 --- a/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -773,6 +773,7 @@ class MacroAssembler: public Assembler { void orptr(Register dst, Address src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); } void orptr(Register dst, Register src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); } void orptr(Register dst, int32_t src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); } + void orptr(Address dst, int32_t imm32) { LP64_ONLY(orq(dst, imm32)) NOT_LP64(orl(dst, imm32)); } void testptr(Register src, int32_t imm32) { LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); } void testptr(Register src1, Register src2); diff --git a/src/cpu/x86/vm/templateTable_x86_32.cpp b/src/cpu/x86/vm/templateTable_x86_32.cpp index 6c6cc4f9474d5db34bfa24d16036bc34dd1d8070..6e6033b02b6bbdd980d15961a158f78e5b19736b 100644 --- a/src/cpu/x86/vm/templateTable_x86_32.cpp +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp @@ -2970,6 +2970,7 @@ void TemplateTable::invokevirtual_helper(Register index, // profile this call __ profile_final_call(rax); + __ profile_arguments_type(rax, method, rsi, true); __ jump_from_interpreted(method, rax); @@ -2984,6 +2985,7 @@ void TemplateTable::invokevirtual_helper(Register index, // get target Method* & entry point __ lookup_virtual_method(rax, index, method); + __ profile_arguments_type(rdx, method, rsi, true); __ jump_from_interpreted(method, rdx); } @@ -3013,6 +3015,7 @@ void TemplateTable::invokespecial(int byte_no) { __ null_check(rcx); // do the call __ profile_call(rax); + __ profile_arguments_type(rax, rbx, rsi, false); __ jump_from_interpreted(rbx, rax); } @@ -3023,6 +3026,7 @@ void TemplateTable::invokestatic(int byte_no) { prepare_invoke(byte_no, rbx); // get f1 Method* // do the call __ profile_call(rax); + __ profile_arguments_type(rax, rbx, rsi, false); __ jump_from_interpreted(rbx, rax); } @@ -3082,6 +3086,8 @@ void TemplateTable::invokeinterface(int byte_no) { __ testptr(rbx, rbx); __ jcc(Assembler::zero, no_such_method); + __ profile_arguments_type(rdx, rbx, rsi, true); + // do the call // rcx: receiver // rbx,: Method* @@ -3138,6 +3144,7 @@ void TemplateTable::invokehandle(int byte_no) { // FIXME: profile the LambdaForm also __ profile_final_call(rax); + __ profile_arguments_type(rdx, rbx_method, rsi, true); __ jump_from_interpreted(rbx_method, rdx); } @@ -3171,6 +3178,7 @@ void TemplateTable::invokedynamic(int byte_no) { // %%% should make a type profile for any invokedynamic that takes a ref argument // profile this call __ profile_call(rsi); + __ profile_arguments_type(rdx, rbx, rsi, false); __ verify_oop(rax_callsite); diff --git a/src/cpu/x86/vm/templateTable_x86_64.cpp b/src/cpu/x86/vm/templateTable_x86_64.cpp index e97c5386c7aa7c0e6cf6e040f0c84304f1b8cace..8c49726e5fff5cef7fbeccc2e59af9c028f2c40a 100644 --- a/src/cpu/x86/vm/templateTable_x86_64.cpp +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp @@ -3026,6 +3026,7 @@ void TemplateTable::invokevirtual_helper(Register index, // profile this call __ profile_final_call(rax); + __ profile_arguments_type(rax, method, r13, true); __ jump_from_interpreted(method, rax); @@ -3040,6 +3041,7 @@ void TemplateTable::invokevirtual_helper(Register index, // get target Method* & entry point __ lookup_virtual_method(rax, index, method); + __ profile_arguments_type(rdx, method, r13, true); __ jump_from_interpreted(method, rdx); } @@ -3069,6 +3071,7 @@ void TemplateTable::invokespecial(int byte_no) { __ null_check(rcx); // do the call __ profile_call(rax); + __ profile_arguments_type(rax, rbx, r13, false); __ jump_from_interpreted(rbx, rax); } @@ -3079,6 +3082,7 @@ void TemplateTable::invokestatic(int byte_no) { prepare_invoke(byte_no, rbx); // get f1 Method* // do the call __ profile_call(rax); + __ profile_arguments_type(rax, rbx, r13, false); __ jump_from_interpreted(rbx, rax); } @@ -3136,6 +3140,8 @@ void TemplateTable::invokeinterface(int byte_no) { __ testptr(rbx, rbx); __ jcc(Assembler::zero, no_such_method); + __ profile_arguments_type(rdx, rbx, r13, true); + // do the call // rcx: receiver // rbx,: Method* @@ -3193,6 +3199,7 @@ void TemplateTable::invokehandle(int byte_no) { // FIXME: profile the LambdaForm also __ profile_final_call(rax); + __ profile_arguments_type(rdx, rbx_method, r13, true); __ jump_from_interpreted(rbx_method, rdx); } @@ -3226,6 +3233,7 @@ void TemplateTable::invokedynamic(int byte_no) { // %%% should make a type profile for any invokedynamic that takes a ref argument // profile this call __ profile_call(r13); + __ profile_arguments_type(rdx, rbx_method, r13, false); __ verify_oop(rax_callsite); diff --git a/src/share/vm/c1/c1_Compilation.cpp b/src/share/vm/c1/c1_Compilation.cpp index 1cdcab542fa07c2b56fe8699e7aa043e82c33334..574fda19401f083773d71ad196361f3b43b0fb16 100644 --- a/src/share/vm/c1/c1_Compilation.cpp +++ b/src/share/vm/c1/c1_Compilation.cpp @@ -601,6 +601,17 @@ void Compilation::bailout(const char* msg) { } } +ciKlass* Compilation::cha_exact_type(ciType* type) { + if (type != NULL && type->is_loaded() && type->is_instance_klass()) { + ciInstanceKlass* ik = type->as_instance_klass(); + assert(ik->exact_klass() == NULL, "no cha for final klass"); + if (DeoptC1 && UseCHA && !(ik->has_subklass() || ik->is_interface())) { + dependency_recorder()->assert_leaf_type(ik); + return ik; + } + } + return NULL; +} void Compilation::print_timers() { // tty->print_cr(" Native methods : %6.3f s, Average : %2.3f", CompileBroker::_t_native_compilation.seconds(), CompileBroker::_t_native_compilation.seconds() / CompileBroker::_total_native_compile_count); diff --git a/src/share/vm/c1/c1_Compilation.hpp b/src/share/vm/c1/c1_Compilation.hpp index f98ae97f309708778d0be7d98ffa4a1e890f76f0..7386dc414c81b6f3f116afcebda342b33fe7fd70 100644 --- a/src/share/vm/c1/c1_Compilation.hpp +++ b/src/share/vm/c1/c1_Compilation.hpp @@ -246,6 +246,8 @@ class Compilation: public StackObj { (RangeCheckElimination || UseLoopInvariantCodeMotion) && method()->method_data()->trap_count(Deoptimization::Reason_none) == 0; } + + ciKlass* cha_exact_type(ciType* type); }; diff --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp index 03d0d75fa303129eb34787d6cd9c0cc0eeb9def8..f93a6e890503592affabfd0dc4375c524170c226 100644 --- a/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/src/share/vm/c1/c1_GraphBuilder.cpp @@ -1658,6 +1658,42 @@ Dependencies* GraphBuilder::dependency_recorder() const { return compilation()->dependency_recorder(); } +// How many arguments do we want to profile? +Values* GraphBuilder::args_list_for_profiling(int& start, bool may_have_receiver) { + int n = 0; + assert(start == 0, "should be initialized"); + 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 (n > 0) { + return new Values(n); + } + return NULL; +} + +// Collect arguments that we want to profile in a list +Values* GraphBuilder::collect_args_for_profiling(Values* args, bool may_have_receiver) { + int start = 0; + Values* obj_args = args_list_for_profiling(start, may_have_receiver); + if (obj_args == NULL) { + return NULL; + } + int s = obj_args->size(); + for (int i = start, j = 0; j < s; i++) { + if (args->at(i)->type()->is_object_kind()) { + obj_args->push(args->at(i)); + j++; + } + } + assert(s == obj_args->length(), "missed on arg?"); + return obj_args; +} + void GraphBuilder::invoke(Bytecodes::Code code) { bool will_link; @@ -1957,7 +1993,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) { } else if (exact_target != NULL) { target_klass = exact_target->holder(); } - profile_call(target, recv, target_klass); + profile_call(target, recv, target_klass, collect_args_for_profiling(args, false), false); } } @@ -3509,7 +3545,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) { recv = args->at(0); null_check(recv); } - profile_call(callee, recv, NULL); + profile_call(callee, recv, NULL, collect_args_for_profiling(args, true), true); } } } @@ -3763,7 +3799,28 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode compilation()->set_would_profile(true); if (profile_calls()) { - profile_call(callee, recv, holder_known ? callee->holder() : NULL); + int start = 0; + Values* obj_args = args_list_for_profiling(start, has_receiver); + if (obj_args != NULL) { + int s = obj_args->size(); + // if called through method handle invoke, some arguments may have been popped + for (int i = args_base+start, j = 0; j < obj_args->size() && i < state()->stack_size(); ) { + Value v = state()->stack_at_inc(i); + if (v->type()->is_object_kind()) { + obj_args->push(v); + j++; + } + } +#ifdef ASSERT + { + bool ignored_will_link; + ciSignature* declared_signature = NULL; + ciMethod* real_target = method()->get_method_at_bci(bci(), ignored_will_link, &declared_signature); + assert(s == obj_args->length() || real_target->is_method_handle_intrinsic(), "missed on arg?"); + } +#endif + } + profile_call(callee, recv, holder_known ? callee->holder() : NULL, obj_args, true); } } @@ -4251,8 +4308,8 @@ void GraphBuilder::print_stats() { } #endif // PRODUCT -void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder) { - append(new ProfileCall(method(), bci(), callee, recv, known_holder)); +void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined) { + append(new ProfileCall(method(), bci(), callee, recv, known_holder, obj_args, inlined)); } void GraphBuilder::profile_invocation(ciMethod* callee, ValueStack* state) { diff --git a/src/share/vm/c1/c1_GraphBuilder.hpp b/src/share/vm/c1/c1_GraphBuilder.hpp index ae5afd4e04d8ac190c35697365197d1e5ada0feb..217da78bb269624db521a2779d8e095f750b2f12 100644 --- a/src/share/vm/c1/c1_GraphBuilder.hpp +++ b/src/share/vm/c1/c1_GraphBuilder.hpp @@ -374,7 +374,7 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC { void print_inlining(ciMethod* callee, const char* msg = NULL, bool success = true); - void profile_call(ciMethod* callee, Value recv, ciKlass* predicted_holder); + void profile_call(ciMethod* callee, Value recv, ciKlass* predicted_holder, Values* obj_args, bool inlined); void profile_invocation(ciMethod* inlinee, ValueStack* state); // Shortcuts to profiling control. @@ -386,6 +386,9 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC { 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); + public: NOT_PRODUCT(void print_stats();) diff --git a/src/share/vm/c1/c1_Instruction.cpp b/src/share/vm/c1/c1_Instruction.cpp index a026b4cbea088c44f773bb05fdfd63ffeb89ec97..e5829611e661bd5782e3703d7b863e30ef35eeff 100644 --- a/src/share/vm/c1/c1_Instruction.cpp +++ b/src/share/vm/c1/c1_Instruction.cpp @@ -104,6 +104,14 @@ void Instruction::state_values_do(ValueVisitor* f) { } } +ciType* Instruction::exact_type() const { + ciType* t = declared_type(); + if (t != NULL && t->is_klass()) { + return t->as_klass()->exact_klass(); + } + return NULL; +} + #ifndef PRODUCT void Instruction::check_state(ValueStack* state) { @@ -135,9 +143,7 @@ void Instruction::print(InstructionPrinter& ip) { // perform constant and interval tests on index value bool AccessIndexed::compute_needs_range_check() { - if (length()) { - Constant* clength = length()->as_Constant(); Constant* cindex = index()->as_Constant(); if (clength && cindex) { @@ -157,34 +163,8 @@ bool AccessIndexed::compute_needs_range_check() { } -ciType* Local::exact_type() const { - ciType* type = declared_type(); - - // for primitive arrays, the declared type is the exact type - if (type->is_type_array_klass()) { - return type; - } else if (type->is_instance_klass()) { - ciInstanceKlass* ik = (ciInstanceKlass*)type; - if (ik->is_loaded() && ik->is_final() && !ik->is_interface()) { - return type; - } - } else if (type->is_obj_array_klass()) { - ciObjArrayKlass* oak = (ciObjArrayKlass*)type; - ciType* base = oak->base_element_type(); - if (base->is_instance_klass()) { - ciInstanceKlass* ik = base->as_instance_klass(); - if (ik->is_loaded() && ik->is_final()) { - return type; - } - } else if (base->is_primitive_type()) { - return type; - } - } - return NULL; -} - ciType* Constant::exact_type() const { - if (type()->is_object()) { + if (type()->is_object() && type()->as_ObjectType()->is_loaded()) { return type()->as_ObjectType()->exact_type(); } return NULL; @@ -192,19 +172,18 @@ ciType* Constant::exact_type() const { ciType* LoadIndexed::exact_type() const { ciType* array_type = array()->exact_type(); - if (array_type == NULL) { - return NULL; - } - assert(array_type->is_array_klass(), "what else?"); - ciArrayKlass* ak = (ciArrayKlass*)array_type; + if (array_type != NULL) { + assert(array_type->is_array_klass(), "what else?"); + ciArrayKlass* ak = (ciArrayKlass*)array_type; - if (ak->element_type()->is_instance_klass()) { - ciInstanceKlass* ik = (ciInstanceKlass*)ak->element_type(); - if (ik->is_loaded() && ik->is_final()) { - return ik; + if (ak->element_type()->is_instance_klass()) { + ciInstanceKlass* ik = (ciInstanceKlass*)ak->element_type(); + if (ik->is_loaded() && ik->is_final()) { + return ik; + } } } - return NULL; + return Instruction::exact_type(); } @@ -224,22 +203,6 @@ ciType* LoadField::declared_type() const { } -ciType* LoadField::exact_type() const { - ciType* type = declared_type(); - // for primitive arrays, the declared type is the exact type - if (type->is_type_array_klass()) { - return type; - } - if (type->is_instance_klass()) { - ciInstanceKlass* ik = (ciInstanceKlass*)type; - if (ik->is_loaded() && ik->is_final()) { - return type; - } - } - return NULL; -} - - ciType* NewTypeArray::exact_type() const { return ciTypeArrayKlass::make(elt_type()); } @@ -264,16 +227,6 @@ ciType* CheckCast::declared_type() const { return klass(); } -ciType* CheckCast::exact_type() const { - if (klass()->is_instance_klass()) { - ciInstanceKlass* ik = (ciInstanceKlass*)klass(); - if (ik->is_loaded() && ik->is_final()) { - return ik; - } - } - return NULL; -} - // Implementation of ArithmeticOp bool ArithmeticOp::is_commutative() const { diff --git a/src/share/vm/c1/c1_Instruction.hpp b/src/share/vm/c1/c1_Instruction.hpp index 9563b720a102fb1788b5db3b5dfe4016c3b56f72..466d814c674fa36255b46a52285f86e1af2f915d 100644 --- a/src/share/vm/c1/c1_Instruction.hpp +++ b/src/share/vm/c1/c1_Instruction.hpp @@ -322,6 +322,36 @@ class Instruction: public CompilationResourceObj { _type = type; } + // Helper class to keep track of which arguments need a null check + class ArgsNonNullState { + private: + int _nonnull_state; // mask identifying which args are nonnull + public: + ArgsNonNullState() + : _nonnull_state(AllBits) {} + + // Does argument number i needs a null check? + bool arg_needs_null_check(int i) const { + // No data is kept for arguments starting at position 33 so + // conservatively assume that they need a null check. + if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) { + return is_set_nth_bit(_nonnull_state, i); + } + return true; + } + + // Set whether argument number i needs a null check or not + void set_arg_needs_null_check(int i, bool check) { + if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) { + if (check) { + _nonnull_state |= nth_bit(i); + } else { + _nonnull_state &= ~(nth_bit(i)); + } + } + } + }; + public: void* operator new(size_t size) throw() { Compilation* c = Compilation::current(); @@ -566,7 +596,7 @@ class Instruction: public CompilationResourceObj { virtual void other_values_do(ValueVisitor* f) { /* usually no other - override on demand */ } void values_do(ValueVisitor* f) { input_values_do(f); state_values_do(f); other_values_do(f); } - virtual ciType* exact_type() const { return NULL; } + virtual ciType* exact_type() const; virtual ciType* declared_type() const { return NULL; } // hashing @@ -689,7 +719,6 @@ LEAF(Local, Instruction) int java_index() const { return _java_index; } virtual ciType* declared_type() const { return _declared_type; } - virtual ciType* exact_type() const; // generic virtual void input_values_do(ValueVisitor* f) { /* no values */ } @@ -806,7 +835,6 @@ LEAF(LoadField, AccessField) {} ciType* declared_type() const; - ciType* exact_type() const; // generic HASHING2(LoadField, !needs_patching() && !field()->is_volatile(), obj()->subst(), offset()) // cannot be eliminated if needs patching or if volatile @@ -1299,6 +1327,7 @@ BASE(NewArray, StateSplit) virtual bool needs_exception_state() const { return false; } + ciType* exact_type() const { return NULL; } ciType* declared_type() const; // generic @@ -1422,7 +1451,6 @@ LEAF(CheckCast, TypeCheck) } ciType* declared_type() const; - ciType* exact_type() const; }; @@ -1490,7 +1518,7 @@ LEAF(Intrinsic, StateSplit) vmIntrinsics::ID _id; Values* _args; Value _recv; - int _nonnull_state; // mask identifying which args are nonnull + ArgsNonNullState _nonnull_state; public: // preserves_state can be set to true for Intrinsics @@ -1511,7 +1539,6 @@ LEAF(Intrinsic, StateSplit) , _id(id) , _args(args) , _recv(NULL) - , _nonnull_state(AllBits) { assert(args != NULL, "args must exist"); ASSERT_VALUES @@ -1537,21 +1564,12 @@ LEAF(Intrinsic, StateSplit) Value receiver() const { assert(has_receiver(), "must have receiver"); return _recv; } bool preserves_state() const { return check_flag(PreservesStateFlag); } - bool arg_needs_null_check(int i) { - if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) { - return is_set_nth_bit(_nonnull_state, i); - } - return true; + bool arg_needs_null_check(int i) const { + return _nonnull_state.arg_needs_null_check(i); } void set_arg_needs_null_check(int i, bool check) { - if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) { - if (check) { - _nonnull_state |= nth_bit(i); - } else { - _nonnull_state &= ~(nth_bit(i)); - } - } + _nonnull_state.set_arg_needs_null_check(i, check); } // generic @@ -2450,34 +2468,55 @@ LEAF(UnsafePrefetchWrite, UnsafePrefetch) LEAF(ProfileCall, Instruction) private: - ciMethod* _method; - int _bci_of_invoke; - ciMethod* _callee; // the method that is called at the given bci - Value _recv; - ciKlass* _known_holder; + ciMethod* _method; + int _bci_of_invoke; + ciMethod* _callee; // the method that is called at the given bci + Value _recv; + ciKlass* _known_holder; + Values* _obj_args; // arguments for type profiling + ArgsNonNullState _nonnull_state; // Do we know whether some arguments are never null? + bool _inlined; // Are we profiling a call that is inlined public: - ProfileCall(ciMethod* method, int bci, ciMethod* callee, Value recv, ciKlass* known_holder) + ProfileCall(ciMethod* method, int bci, ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined) : Instruction(voidType) , _method(method) , _bci_of_invoke(bci) , _callee(callee) , _recv(recv) , _known_holder(known_holder) + , _obj_args(obj_args) + , _inlined(inlined) { // The ProfileCall has side-effects and must occur precisely where located pin(); } - ciMethod* method() { return _method; } - int bci_of_invoke() { return _bci_of_invoke; } - ciMethod* callee() { return _callee; } - Value recv() { return _recv; } - ciKlass* known_holder() { return _known_holder; } + ciMethod* method() const { return _method; } + int bci_of_invoke() const { return _bci_of_invoke; } + ciMethod* callee() const { return _callee; } + Value recv() const { return _recv; } + ciKlass* known_holder() const { return _known_holder; } + int nb_profiled_args() const { return _obj_args == NULL ? 0 : _obj_args->length(); } + Value profiled_arg_at(int i) const { return _obj_args->at(i); } + bool arg_needs_null_check(int i) const { + return _nonnull_state.arg_needs_null_check(i); + } + bool inlined() const { return _inlined; } - virtual void input_values_do(ValueVisitor* f) { if (_recv != NULL) f->visit(&_recv); } -}; + void set_arg_needs_null_check(int i, bool check) { + _nonnull_state.set_arg_needs_null_check(i, check); + } + virtual void input_values_do(ValueVisitor* f) { + if (_recv != NULL) { + f->visit(&_recv); + } + for (int i = 0; i < nb_profiled_args(); i++) { + f->visit(_obj_args->adr_at(i)); + } + } +}; // Call some C runtime function that doesn't safepoint, // optionally passing the current thread as the first argument. diff --git a/src/share/vm/c1/c1_InstructionPrinter.cpp b/src/share/vm/c1/c1_InstructionPrinter.cpp index cfca00ab277f6a31a3cbd6c0d9c519d6336b36ce..c15538116fd8ff35a2b752947621ead27dac6736 100644 --- a/src/share/vm/c1/c1_InstructionPrinter.cpp +++ b/src/share/vm/c1/c1_InstructionPrinter.cpp @@ -892,6 +892,14 @@ void InstructionPrinter::do_ProfileCall(ProfileCall* x) { if (x->known_holder() != NULL) { output()->print(", "); print_klass(x->known_holder()); + output()->print(" "); + } + for (int i = 0; i < x->nb_profiled_args(); i++) { + if (i > 0) output()->print(", "); + print_value(x->profiled_arg_at(i)); + if (x->arg_needs_null_check(i)) { + output()->print(" [NC]"); + } } output()->put(')'); } diff --git a/src/share/vm/c1/c1_LIR.cpp b/src/share/vm/c1/c1_LIR.cpp index cb0ceab90c060ece33ab62fc5da72dab6798ce56..f40d9133306b36501ee7758903f9fe836b5e565a 100644 --- a/src/share/vm/c1/c1_LIR.cpp +++ b/src/share/vm/c1/c1_LIR.cpp @@ -1001,6 +1001,17 @@ void LIR_OpVisitState::visit(LIR_Op* op) { assert(opProfileCall->_tmp1->is_valid(), "used"); do_temp(opProfileCall->_tmp1); break; } + +// LIR_OpProfileType: + case lir_profile_type: { + assert(op->as_OpProfileType() != NULL, "must be"); + LIR_OpProfileType* opProfileType = (LIR_OpProfileType*)op; + + do_input(opProfileType->_mdp); do_temp(opProfileType->_mdp); + do_input(opProfileType->_obj); + do_temp(opProfileType->_tmp); + break; + } default: ShouldNotReachHere(); } @@ -1151,6 +1162,10 @@ void LIR_OpProfileCall::emit_code(LIR_Assembler* masm) { masm->emit_profile_call(this); } +void LIR_OpProfileType::emit_code(LIR_Assembler* masm) { + masm->emit_profile_type(this); +} + // LIR_List LIR_List::LIR_List(Compilation* compilation, BlockBegin* block) : _operations(8) @@ -1803,6 +1818,8 @@ const char * LIR_Op::name() const { case lir_cas_int: s = "cas_int"; break; // LIR_OpProfileCall case lir_profile_call: s = "profile_call"; break; + // LIR_OpProfileType + case lir_profile_type: s = "profile_type"; break; // LIR_OpAssert #ifdef ASSERT case lir_assert: s = "assert"; break; @@ -2086,6 +2103,15 @@ void LIR_OpProfileCall::print_instr(outputStream* out) const { tmp1()->print(out); out->print(" "); } +// LIR_OpProfileType +void LIR_OpProfileType::print_instr(outputStream* out) const { + out->print("exact = "); exact_klass()->print_name_on(out); + out->print("current = "); ciTypeEntries::print_ciklass(out, current_klass()); + mdp()->print(out); out->print(" "); + obj()->print(out); out->print(" "); + tmp()->print(out); out->print(" "); +} + #endif // PRODUCT // Implementation of LIR_InsertionBuffer diff --git a/src/share/vm/c1/c1_LIR.hpp b/src/share/vm/c1/c1_LIR.hpp index d0dca72f386a353ac6f45f358445cc405a7a0a28..a339af5098f687edacafe081225ba05de6780590 100644 --- a/src/share/vm/c1/c1_LIR.hpp +++ b/src/share/vm/c1/c1_LIR.hpp @@ -882,6 +882,7 @@ class LIR_OpLock; class LIR_OpTypeCheck; class LIR_OpCompareAndSwap; class LIR_OpProfileCall; +class LIR_OpProfileType; #ifdef ASSERT class LIR_OpAssert; #endif @@ -1005,6 +1006,7 @@ enum LIR_Code { , end_opCompareAndSwap , begin_opMDOProfile , lir_profile_call + , lir_profile_type , end_opMDOProfile , begin_opAssert , lir_assert @@ -1145,6 +1147,7 @@ class LIR_Op: public CompilationResourceObj { virtual LIR_OpTypeCheck* as_OpTypeCheck() { return NULL; } virtual LIR_OpCompareAndSwap* as_OpCompareAndSwap() { return NULL; } virtual LIR_OpProfileCall* as_OpProfileCall() { return NULL; } + virtual LIR_OpProfileType* as_OpProfileType() { return NULL; } #ifdef ASSERT virtual LIR_OpAssert* as_OpAssert() { return NULL; } #endif @@ -1925,8 +1928,8 @@ class LIR_OpProfileCall : public LIR_Op { public: // Destroys recv - LIR_OpProfileCall(LIR_Code code, ciMethod* profiled_method, int profiled_bci, ciMethod* profiled_callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* known_holder) - : LIR_Op(code, LIR_OprFact::illegalOpr, NULL) // no result, no info + LIR_OpProfileCall(ciMethod* profiled_method, int profiled_bci, ciMethod* profiled_callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* known_holder) + : LIR_Op(lir_profile_call, LIR_OprFact::illegalOpr, NULL) // no result, no info , _profiled_method(profiled_method) , _profiled_bci(profiled_bci) , _profiled_callee(profiled_callee) @@ -1948,6 +1951,45 @@ class LIR_OpProfileCall : public LIR_Op { virtual void print_instr(outputStream* out) const PRODUCT_RETURN; }; +// LIR_OpProfileType +class LIR_OpProfileType : public LIR_Op { + friend class LIR_OpVisitState; + + private: + LIR_Opr _mdp; + LIR_Opr _obj; + LIR_Opr _tmp; + ciKlass* _exact_klass; // non NULL if we know the klass statically (no need to load it from _obj) + intptr_t _current_klass; // what the profiling currently reports + bool _not_null; // true if we know statically that _obj cannot be null + bool _no_conflict; // true if we're profling parameters, _exact_klass is not NULL and we know + // _exact_klass it the only possible type for this parameter in any context. + + public: + // Destroys recv + LIR_OpProfileType(LIR_Opr mdp, LIR_Opr obj, ciKlass* exact_klass, intptr_t current_klass, LIR_Opr tmp, bool not_null, bool no_conflict) + : LIR_Op(lir_profile_type, LIR_OprFact::illegalOpr, NULL) // no result, no info + , _mdp(mdp) + , _obj(obj) + , _exact_klass(exact_klass) + , _current_klass(current_klass) + , _tmp(tmp) + , _not_null(not_null) + , _no_conflict(no_conflict) { } + + LIR_Opr mdp() const { return _mdp; } + LIR_Opr obj() const { return _obj; } + LIR_Opr tmp() const { return _tmp; } + ciKlass* exact_klass() const { return _exact_klass; } + intptr_t current_klass() const { return _current_klass; } + bool not_null() const { return _not_null; } + bool no_conflict() const { return _no_conflict; } + + virtual void emit_code(LIR_Assembler* masm); + virtual LIR_OpProfileType* as_OpProfileType() { return this; } + virtual void print_instr(outputStream* out) const PRODUCT_RETURN; +}; + class LIR_InsertionBuffer; //--------------------------------LIR_List--------------------------------------------------- @@ -2247,7 +2289,10 @@ class LIR_List: public CompilationResourceObj { ciMethod* profiled_method, int profiled_bci); // MethodData* profiling void profile_call(ciMethod* method, int bci, ciMethod* callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* cha_klass) { - append(new LIR_OpProfileCall(lir_profile_call, method, bci, callee, mdo, recv, t1, cha_klass)); + append(new LIR_OpProfileCall(method, bci, callee, mdo, recv, t1, cha_klass)); + } + void profile_type(LIR_Address* mdp, LIR_Opr obj, ciKlass* exact_klass, intptr_t current_klass, LIR_Opr tmp, bool not_null, bool no_conflict) { + append(new LIR_OpProfileType(LIR_OprFact::address(mdp), obj, exact_klass, current_klass, tmp, not_null, no_conflict)); } void xadd(LIR_Opr src, LIR_Opr add, LIR_Opr res, LIR_Opr tmp) { append(new LIR_Op2(lir_xadd, src, add, res, tmp)); } diff --git a/src/share/vm/c1/c1_LIRAssembler.hpp b/src/share/vm/c1/c1_LIRAssembler.hpp index 57df2725ee29b08a36ef0c08280b1637664ba94c..68f249a2aed5bc814f068c76db8bb93330cedc83 100644 --- a/src/share/vm/c1/c1_LIRAssembler.hpp +++ b/src/share/vm/c1/c1_LIRAssembler.hpp @@ -208,6 +208,7 @@ class LIR_Assembler: public CompilationResourceObj { void emit_call(LIR_OpJavaCall* op); void emit_rtcall(LIR_OpRTCall* op); void emit_profile_call(LIR_OpProfileCall* op); + void emit_profile_type(LIR_OpProfileType* op); void emit_delay(LIR_OpDelay* op); void arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, CodeEmitInfo* info, bool pop_fpu_stack); diff --git a/src/share/vm/c1/c1_LIRGenerator.cpp b/src/share/vm/c1/c1_LIRGenerator.cpp index f71470e5ee08a07ef3ecc1b241b7fb8fea0349f8..3eedf1f313ae9813d148bcda10df0b78ec35e250 100644 --- a/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/src/share/vm/c1/c1_LIRGenerator.cpp @@ -2571,6 +2571,78 @@ void LIRGenerator::do_Goto(Goto* x) { } +ciKlass* LIRGenerator::profile_arg_type(ciMethodData* md, int md_base_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_k) { + ciKlass* result = NULL; + bool do_null = !not_null && !TypeEntries::was_null_seen(profiled_k); + bool do_update = !TypeEntries::is_type_unknown(profiled_k); + // known not to be null or null bit already set and already set to + // unknown: nothing we can do to improve profiling + if (!do_null && !do_update) { + return result; + } + + ciKlass* exact_klass = NULL; + Compilation* comp = Compilation::current(); + if (do_update) { + // try to find exact type, using CHA if possible, so that loading + // the klass from the object can be avoided + ciType* type = arg->exact_type(); + if (type == NULL) { + type = arg->declared_type(); + type = comp->cha_exact_type(type); + } + assert(type == NULL || type->is_klass(), "type should be class"); + exact_klass = (type != NULL && type->is_loaded()) ? (ciKlass*)type : NULL; + + do_update = exact_klass == NULL || ciTypeEntries::valid_ciklass(profiled_k) != exact_klass; + } + + if (!do_null && !do_update) { + return result; + } + + ciKlass* exact_signature_k = NULL; + if (do_update) { + // Is the type from the signature exact (the only one possible)? + exact_signature_k = signature_k->exact_klass(); + if (exact_signature_k == NULL) { + exact_signature_k = comp->cha_exact_type(signature_k); + } else { + result = exact_signature_k; + do_update = false; + // Known statically. No need to emit any code: prevent + // LIR_Assembler::emit_profile_type() from emitting useless code + profiled_k = ciTypeEntries::with_status(result, profiled_k); + } + if (exact_signature_k != NULL && exact_klass != exact_signature_k) { + assert(exact_klass == NULL, "arg and signature disagree?"); + // sometimes the type of the signature is better than the best type + // the compiler has + exact_klass = exact_signature_k; + do_update = exact_klass == NULL || ciTypeEntries::valid_ciklass(profiled_k) != exact_klass; + } + } + + if (!do_null && !do_update) { + return result; + } + + if (mdp == LIR_OprFact::illegalOpr) { + mdp = new_register(T_METADATA); + __ metadata2reg(md->constant_encoding(), mdp); + if (md_base_offset != 0) { + LIR_Address* base_type_address = new LIR_Address(mdp, md_base_offset, T_ADDRESS); + mdp = new_pointer_register(); + __ leal(LIR_OprFact::address(base_type_address), mdp); + } + } + LIRItem value(arg, this); + value.load_item(); + __ profile_type(new LIR_Address(mdp, md_offset, T_METADATA), + value.result(), exact_klass, profiled_k, new_pointer_register(), not_null, exact_signature_k != NULL); + return result; +} + void LIRGenerator::do_Base(Base* x) { __ std_entry(LIR_OprFact::illegalOpr); // Emit moves from physical registers / stack slots to virtual registers @@ -3004,12 +3076,52 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) { } } +void LIRGenerator::profile_arguments(ProfileCall* x) { + if (MethodData::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()) { + 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; + ciTypeStackSlotEntries* args = data->is_CallTypeData() ? ((ciCallTypeData*)data)->args() : ((ciVirtualCallTypeData*)data)->args(); + + Bytecodes::Code bc = x->method()->java_code_at_bci(bci); + int start = 0; + int stop = args->number_of_arguments(); + if (x->nb_profiled_args() < stop) { + // if called through method handle invoke, some arguments may have been popped + stop = x->nb_profiled_args(); + } + ciSignature* sig = x->callee()->signature(); + // method handle call to virtual method + bool has_receiver = x->inlined() && !x->callee()->is_static() && !Bytecodes::has_receiver(bc); + ciSignatureStream sig_stream(sig, has_receiver ? x->callee()->holder() : NULL); + for (int i = 0; i < stop; i++) { + int off = in_bytes(TypeStackSlotEntries::type_offset(i)) - in_bytes(TypeStackSlotEntries::args_data_offset()); + ciKlass* exact = profile_arg_type(md, base_offset, off, + args->type(i), x->profiled_arg_at(i+start), mdp, + !x->arg_needs_null_check(i+start), sig_stream.next_klass()); + if (exact != NULL) { + md->set_argument_type(bci, i, exact); + } + } + } + } +} + void LIRGenerator::do_ProfileCall(ProfileCall* x) { // Need recv in a temporary register so it interferes with the other temporaries LIR_Opr recv = LIR_OprFact::illegalOpr; LIR_Opr mdo = new_register(T_OBJECT); // tmp is used to hold the counters on SPARC LIR_Opr tmp = new_pointer_register(); + + if (x->nb_profiled_args() > 0) { + profile_arguments(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 0a0292073084f0f53f5108014abfe731d21152f5..fce938a03d811164ac5befea14c9d1dfab16a450 100644 --- a/src/share/vm/c1/c1_LIRGenerator.hpp +++ b/src/share/vm/c1/c1_LIRGenerator.hpp @@ -434,6 +434,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void do_ThreadIDIntrinsic(Intrinsic* x); void do_ClassIDIntrinsic(Intrinsic* x); #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); public: Compilation* compilation() const { return _compilation; } diff --git a/src/share/vm/c1/c1_Optimizer.cpp b/src/share/vm/c1/c1_Optimizer.cpp index 90dc279721090f443293b370d2cd75a6dffbce95..0be6099aa61d6a8facdedc8c4696a85b4d931b3a 100644 --- a/src/share/vm/c1/c1_Optimizer.cpp +++ b/src/share/vm/c1/c1_Optimizer.cpp @@ -657,6 +657,7 @@ class NullCheckEliminator: public ValueVisitor { void handle_Intrinsic (Intrinsic* x); void handle_ExceptionObject (ExceptionObject* x); void handle_Phi (Phi* x); + void handle_ProfileCall (ProfileCall* x); }; @@ -715,7 +716,8 @@ void NullCheckVisitor::do_UnsafePutObject(UnsafePutObject* x) {} void NullCheckVisitor::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {} void NullCheckVisitor::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {} void NullCheckVisitor::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) {} -void NullCheckVisitor::do_ProfileCall (ProfileCall* x) { nce()->clear_last_explicit_null_check(); } +void NullCheckVisitor::do_ProfileCall (ProfileCall* x) { nce()->clear_last_explicit_null_check(); + nce()->handle_ProfileCall(x); } void NullCheckVisitor::do_ProfileInvoke (ProfileInvoke* x) {} void NullCheckVisitor::do_RuntimeCall (RuntimeCall* x) {} void NullCheckVisitor::do_MemBar (MemBar* x) {} @@ -1134,6 +1136,11 @@ void NullCheckEliminator::handle_Phi(Phi* x) { } } +void NullCheckEliminator::handle_ProfileCall(ProfileCall* x) { + for (int i = 0; i < x->nb_profiled_args(); i++) { + x->set_arg_needs_null_check(i, !set_contains(x->profiled_arg_at(i))); + } +} void Optimizer::eliminate_null_checks() { ResourceMark rm; diff --git a/src/share/vm/c1/c1_RangeCheckElimination.hpp b/src/share/vm/c1/c1_RangeCheckElimination.hpp index ae1a255688169db51e08b29051a14f7762d988a0..1d7897bda9aec9bc172a3d8cfcaad42a3edbd73c 100644 --- a/src/share/vm/c1/c1_RangeCheckElimination.hpp +++ b/src/share/vm/c1/c1_RangeCheckElimination.hpp @@ -162,7 +162,7 @@ public: void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ }; void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ }; void do_ProfileCall (ProfileCall* x) { /* nothing to do */ }; - void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ }; + void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ }; void do_RuntimeCall (RuntimeCall* x) { /* nothing to do */ }; void do_MemBar (MemBar* x) { /* nothing to do */ }; void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ }; diff --git a/src/share/vm/ci/ciClassList.hpp b/src/share/vm/ci/ciClassList.hpp index 71e5dd18c7f3a1978bdbec5c856bc6ebf244cf45..c3131f5ee67a99e1c15409171434fd676afcf761 100644 --- a/src/share/vm/ci/ciClassList.hpp +++ b/src/share/vm/ci/ciClassList.hpp @@ -102,6 +102,7 @@ friend class ciMethodData; \ friend class ciMethodHandle; \ friend class ciMethodType; \ friend class ciReceiverTypeData; \ +friend class ciTypeEntries; \ friend class ciSymbol; \ friend class ciArray; \ friend class ciObjArray; \ diff --git a/src/share/vm/ci/ciInstanceKlass.hpp b/src/share/vm/ci/ciInstanceKlass.hpp index 0b244a2972c08bca7b264d75d3a269ea337cc42a..fdd93ddc58c8e7389098731a782b0198bc3c472d 100644 --- a/src/share/vm/ci/ciInstanceKlass.hpp +++ b/src/share/vm/ci/ciInstanceKlass.hpp @@ -235,6 +235,13 @@ public: bool is_instance_klass() const { return true; } bool is_java_klass() const { return true; } + virtual ciKlass* exact_klass() { + if (is_loaded() && is_final() && !is_interface()) { + return this; + } + return NULL; + } + // Dump the current state of this klass for compilation replay. virtual void dump_replay_data(outputStream* out); }; diff --git a/src/share/vm/ci/ciKlass.hpp b/src/share/vm/ci/ciKlass.hpp index d378059fcbc15795b5a2e6698abae099a5027911..7e03c1ede61b81c34ffd51d4c9e9b60fc0c5dd8b 100644 --- a/src/share/vm/ci/ciKlass.hpp +++ b/src/share/vm/ci/ciKlass.hpp @@ -41,6 +41,7 @@ class ciKlass : public ciType { friend class ciEnv; friend class ciField; friend class ciMethod; + friend class ciMethodData; friend class ciObjArrayKlass; private: @@ -121,6 +122,8 @@ public: // What kind of ciObject is this? bool is_klass() const { return true; } + virtual ciKlass* exact_klass() = 0; + void print_name_on(outputStream* st); }; diff --git a/src/share/vm/ci/ciMethodData.cpp b/src/share/vm/ci/ciMethodData.cpp index 268888bfd567b4eefea2301c8f1a76515108c97b..fb06759154a6113e912bb1a8fa1eb2995f713c98 100644 --- a/src/share/vm/ci/ciMethodData.cpp +++ b/src/share/vm/ci/ciMethodData.cpp @@ -125,7 +125,7 @@ void ciMethodData::load_data() { #endif } -void ciReceiverTypeData::translate_receiver_data_from(ProfileData* data) { +void ciReceiverTypeData::translate_receiver_data_from(const ProfileData* data) { for (uint row = 0; row < row_limit(); row++) { Klass* k = data->as_ReceiverTypeData()->receiver(row); if (k != NULL) { @@ -136,6 +136,13 @@ void ciReceiverTypeData::translate_receiver_data_from(ProfileData* data) { } +void ciTypeStackSlotEntries::translate_type_data_from(const TypeStackSlotEntries* entries) { + for (int i = 0; i < number_of_arguments(); i++) { + intptr_t k = entries->type(i); + TypeStackSlotEntries::set_type(i, translate_klass(k)); + } +} + // Get the data at an arbitrary (sort of) data index. ciProfileData* ciMethodData::data_at(int data_index) { if (out_of_bounds(data_index)) { @@ -166,6 +173,10 @@ ciProfileData* ciMethodData::data_at(int data_index) { return new ciMultiBranchData(data_layout); case DataLayout::arg_info_data_tag: return new ciArgInfoData(data_layout); + case DataLayout::call_type_data_tag: + return new ciCallTypeData(data_layout); + case DataLayout::virtual_call_type_data_tag: + return new ciVirtualCallTypeData(data_layout); }; } @@ -288,6 +299,20 @@ void ciMethodData::set_would_profile(bool p) { } } +void ciMethodData::set_argument_type(int bci, int i, ciKlass* k) { + VM_ENTRY_MARK; + MethodData* mdo = get_MethodData(); + if (mdo != NULL) { + ProfileData* data = mdo->bci_to_data(bci); + if (data->is_CallTypeData()) { + data->as_CallTypeData()->set_argument_type(i, k->get_Klass()); + } else { + assert(data->is_VirtualCallTypeData(), "no arguments!"); + data->as_VirtualCallTypeData()->set_argument_type(i, k->get_Klass()); + } + } +} + bool ciMethodData::has_escape_info() { return eflag_set(MethodData::estimated); } @@ -478,7 +503,36 @@ void ciMethodData::print_data_on(outputStream* st) { } } -void ciReceiverTypeData::print_receiver_data_on(outputStream* st) { +void ciTypeEntries::print_ciklass(outputStream* st, intptr_t k) { + if (TypeEntries::is_type_none(k)) { + st->print("none"); + } else if (TypeEntries::is_type_unknown(k)) { + st->print("unknown"); + } else { + valid_ciklass(k)->print_name_on(st); + } + if (TypeEntries::was_null_seen(k)) { + st->print(" (null seen)"); + } +} + +void ciTypeStackSlotEntries::print_data_on(outputStream* st) const { + _pd->tab(st, true); + st->print("argument types"); + for (int i = 0; i < number_of_arguments(); i++) { + _pd->tab(st); + st->print("%d: stack (%u) ", i, stack_slot(i)); + print_ciklass(st, type(i)); + st->cr(); + } +} + +void ciCallTypeData::print_data_on(outputStream* st) const { + print_shared(st, "ciCallTypeData"); + args()->print_data_on(st); +} + +void ciReceiverTypeData::print_receiver_data_on(outputStream* st) const { uint row; int entries = 0; for (row = 0; row < row_limit(); row++) { @@ -494,13 +548,19 @@ void ciReceiverTypeData::print_receiver_data_on(outputStream* st) { } } -void ciReceiverTypeData::print_data_on(outputStream* st) { +void ciReceiverTypeData::print_data_on(outputStream* st) const { print_shared(st, "ciReceiverTypeData"); print_receiver_data_on(st); } -void ciVirtualCallData::print_data_on(outputStream* st) { +void ciVirtualCallData::print_data_on(outputStream* st) const { print_shared(st, "ciVirtualCallData"); rtd_super()->print_receiver_data_on(st); } + +void ciVirtualCallTypeData::print_data_on(outputStream* st) const { + print_shared(st, "ciVirtualCallTypeData"); + rtd_super()->print_receiver_data_on(st); + args()->print_data_on(st); +} #endif diff --git a/src/share/vm/ci/ciMethodData.hpp b/src/share/vm/ci/ciMethodData.hpp index 913ae31847ed71f4e05abc79393d8731ea455b9d..8de598117a68d2dc0e76540beedb2f5749cf7b4a 100644 --- a/src/share/vm/ci/ciMethodData.hpp +++ b/src/share/vm/ci/ciMethodData.hpp @@ -41,6 +41,8 @@ class ciBranchData; class ciArrayData; class ciMultiBranchData; class ciArgInfoData; +class ciCallTypeData; +class ciVirtualCallTypeData; typedef ProfileData ciProfileData; @@ -59,6 +61,68 @@ public: ciJumpData(DataLayout* layout) : JumpData(layout) {}; }; +class ciTypeEntries { +protected: + static intptr_t translate_klass(intptr_t k) { + Klass* v = TypeEntries::valid_klass(k); + if (v != NULL) { + ciKlass* klass = CURRENT_ENV->get_klass(v); + return with_status(klass, k); + } + return with_status(NULL, k); + } + +public: + static ciKlass* valid_ciklass(intptr_t k) { + if (!TypeEntries::is_type_none(k) && + !TypeEntries::is_type_unknown(k)) { + return (ciKlass*)TypeEntries::klass_part(k); + } else { + return NULL; + } + } + + static intptr_t with_status(ciKlass* k, intptr_t in) { + return TypeEntries::with_status((intptr_t)k, in); + } + +#ifndef PRODUCT + static void print_ciklass(outputStream* st, intptr_t k); +#endif +}; + +class ciTypeStackSlotEntries : public TypeStackSlotEntries, ciTypeEntries { +public: + void translate_type_data_from(const TypeStackSlotEntries* args); + + ciKlass* valid_type(int i) const { + return valid_ciklass(type(i)); + } + +#ifndef PRODUCT + void print_data_on(outputStream* st) const; +#endif +}; + +class ciCallTypeData : public CallTypeData { +public: + ciCallTypeData(DataLayout* layout) : CallTypeData(layout) {} + + ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)CallTypeData::args(); } + + virtual void translate_from(const ProfileData* data) { + args()->translate_type_data_from(data->as_CallTypeData()->args()); + } + + ciKlass* valid_argument_type(int i) const { + return args()->valid_type(i); + } + +#ifndef PRODUCT + void print_data_on(outputStream* st) const; +#endif +}; + class ciReceiverTypeData : public ReceiverTypeData { public: ciReceiverTypeData(DataLayout* layout) : ReceiverTypeData(layout) {}; @@ -69,7 +133,7 @@ public: (intptr_t) recv); } - ciKlass* receiver(uint row) { + ciKlass* receiver(uint row) const { assert((uint)row < row_limit(), "oob"); ciKlass* recv = (ciKlass*)intptr_at(receiver0_offset + row * receiver_type_row_cell_count); assert(recv == NULL || recv->is_klass(), "wrong type"); @@ -77,19 +141,19 @@ public: } // Copy & translate from oop based ReceiverTypeData - virtual void translate_from(ProfileData* data) { + virtual void translate_from(const ProfileData* data) { translate_receiver_data_from(data); } - void translate_receiver_data_from(ProfileData* data); + void translate_receiver_data_from(const ProfileData* data); #ifndef PRODUCT - void print_data_on(outputStream* st); - void print_receiver_data_on(outputStream* st); + void print_data_on(outputStream* st) const; + void print_receiver_data_on(outputStream* st) const; #endif }; class ciVirtualCallData : public VirtualCallData { // Fake multiple inheritance... It's a ciReceiverTypeData also. - ciReceiverTypeData* rtd_super() { return (ciReceiverTypeData*) this; } + ciReceiverTypeData* rtd_super() const { return (ciReceiverTypeData*) this; } public: ciVirtualCallData(DataLayout* layout) : VirtualCallData(layout) {}; @@ -103,11 +167,44 @@ public: } // Copy & translate from oop based VirtualCallData - virtual void translate_from(ProfileData* data) { + virtual void translate_from(const ProfileData* data) { rtd_super()->translate_receiver_data_from(data); } #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; +#endif +}; + +class ciVirtualCallTypeData : public VirtualCallTypeData { +private: + // Fake multiple inheritance... It's a ciReceiverTypeData also. + ciReceiverTypeData* rtd_super() const { return (ciReceiverTypeData*) this; } + +public: + ciVirtualCallTypeData(DataLayout* layout) : VirtualCallTypeData(layout) {} + + ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)VirtualCallTypeData::args(); } + + void set_receiver(uint row, ciKlass* recv) { + rtd_super()->set_receiver(row, recv); + } + + ciKlass* receiver(uint row) const { + return rtd_super()->receiver(row); + } + + // Copy & translate from oop based VirtualCallData + virtual void translate_from(const ProfileData* data) { + rtd_super()->translate_receiver_data_from(data); + args()->translate_type_data_from(data->as_VirtualCallTypeData()->args()); + } + + ciKlass* valid_argument_type(int i) const { + return args()->valid_type(i); + } + +#ifndef PRODUCT + void print_data_on(outputStream* st) const; #endif }; @@ -247,6 +344,9 @@ public: // Also set the numer of loops and blocks in the method. // Again, this is used to determine if a method is trivial. void set_compilation_stats(short loops, short blocks); + // 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 load_data(); diff --git a/src/share/vm/ci/ciObjArrayKlass.cpp b/src/share/vm/ci/ciObjArrayKlass.cpp index 3ccb54eac9cbc414e2d30b1567298ff905daab17..91f2ebc42a0bca79efaae8d1bcd8cc36cf8691f4 100644 --- a/src/share/vm/ci/ciObjArrayKlass.cpp +++ b/src/share/vm/ci/ciObjArrayKlass.cpp @@ -179,3 +179,16 @@ ciObjArrayKlass* ciObjArrayKlass::make_impl(ciKlass* element_klass) { ciObjArrayKlass* ciObjArrayKlass::make(ciKlass* element_klass) { GUARDED_VM_ENTRY(return make_impl(element_klass);) } + +ciKlass* ciObjArrayKlass::exact_klass() { + ciType* base = base_element_type(); + if (base->is_instance_klass()) { + ciInstanceKlass* ik = base->as_instance_klass(); + if (ik->exact_klass() != NULL) { + return this; + } + } else if (base->is_primitive_type()) { + return this; + } + return NULL; +} diff --git a/src/share/vm/ci/ciObjArrayKlass.hpp b/src/share/vm/ci/ciObjArrayKlass.hpp index ffbf85028043505330f1f48d28375b83c1a9a5e0..7a45e8674382f065b1a2f7d6bf3085b81f955939 100644 --- a/src/share/vm/ci/ciObjArrayKlass.hpp +++ b/src/share/vm/ci/ciObjArrayKlass.hpp @@ -73,6 +73,8 @@ public: bool is_obj_array_klass() const { return true; } static ciObjArrayKlass* make(ciKlass* element_klass); + + virtual ciKlass* exact_klass(); }; #endif // SHARE_VM_CI_CIOBJARRAYKLASS_HPP diff --git a/src/share/vm/ci/ciStreams.hpp b/src/share/vm/ci/ciStreams.hpp index db46a4a85d31e35cd33201e197bf107cc07eb71f..92a1a4adf88fc4da3fe51c2ec925e63033a72600 100644 --- a/src/share/vm/ci/ciStreams.hpp +++ b/src/share/vm/ci/ciStreams.hpp @@ -277,11 +277,14 @@ public: class ciSignatureStream : public StackObj { private: ciSignature* _sig; - int _pos; + int _pos; + // holder is a method's holder + ciKlass* _holder; public: - ciSignatureStream(ciSignature* signature) { + ciSignatureStream(ciSignature* signature, ciKlass* holder = NULL) { _sig = signature; _pos = 0; + _holder = holder; } bool at_return_type() { return _pos == _sig->count(); } @@ -301,6 +304,23 @@ public: return _sig->type_at(_pos); } } + + // next klass in the signature + ciKlass* next_klass() { + ciKlass* sig_k; + if (_holder != NULL) { + sig_k = _holder; + _holder = NULL; + } else { + while (!type()->is_klass()) { + next(); + } + assert(!at_return_type(), "passed end of signature"); + sig_k = type()->as_klass(); + next(); + } + return sig_k; + } }; diff --git a/src/share/vm/ci/ciTypeArrayKlass.hpp b/src/share/vm/ci/ciTypeArrayKlass.hpp index 5a57f74c49784856fe1938b6b4e0f29b7c667329..b88aecb9c6c11d5c6425d530f51f9c5981a46cf4 100644 --- a/src/share/vm/ci/ciTypeArrayKlass.hpp +++ b/src/share/vm/ci/ciTypeArrayKlass.hpp @@ -57,6 +57,10 @@ public: // Make an array klass corresponding to the specified primitive type. static ciTypeArrayKlass* make(BasicType type); + + virtual ciKlass* exact_klass() { + return this; + } }; #endif // SHARE_VM_CI_CITYPEARRAYKLASS_HPP diff --git a/src/share/vm/oops/methodData.cpp b/src/share/vm/oops/methodData.cpp index 89a4cd4aa6b9c7279bb67eb0ccef4e17aa9e30d5..efb45934d7e23ef9e416e024c5a415860ae5a6f1 100644 --- a/src/share/vm/oops/methodData.cpp +++ b/src/share/vm/oops/methodData.cpp @@ -56,6 +56,11 @@ void DataLayout::initialize(u1 tag, u2 bci, int cell_count) { if (needs_array_len(tag)) { set_cell_at(ArrayData::array_len_off_set, cell_count - 1); // -1 for header. } + if (tag == call_type_data_tag) { + CallTypeData::initialize(this, cell_count); + } else if (tag == virtual_call_type_data_tag) { + VirtualCallTypeData::initialize(this, cell_count); + } } void DataLayout::clean_weak_klass_links(BoolObjectClosure* cl) { @@ -76,7 +81,7 @@ ProfileData::ProfileData() { } #ifndef PRODUCT -void ProfileData::print_shared(outputStream* st, const char* name) { +void ProfileData::print_shared(outputStream* st, const char* name) const { st->print("bci: %d", bci()); st->fill_to(tab_width_one); st->print("%s", name); @@ -91,8 +96,8 @@ void ProfileData::print_shared(outputStream* st, const char* name) { st->print("flags(%d) ", flags); } -void ProfileData::tab(outputStream* st) { - st->fill_to(tab_width_two); +void ProfileData::tab(outputStream* st, bool first) const { + st->fill_to(first ? tab_width_one : tab_width_two); } #endif // !PRODUCT @@ -104,7 +109,7 @@ void ProfileData::tab(outputStream* st) { #ifndef PRODUCT -void BitData::print_data_on(outputStream* st) { +void BitData::print_data_on(outputStream* st) const { print_shared(st, "BitData"); } #endif // !PRODUCT @@ -115,7 +120,7 @@ void BitData::print_data_on(outputStream* st) { // A CounterData corresponds to a simple counter. #ifndef PRODUCT -void CounterData::print_data_on(outputStream* st) { +void CounterData::print_data_on(outputStream* st) const { print_shared(st, "CounterData"); st->print_cr("count(%u)", count()); } @@ -145,12 +150,130 @@ void JumpData::post_initialize(BytecodeStream* stream, MethodData* mdo) { } #ifndef PRODUCT -void JumpData::print_data_on(outputStream* st) { +void JumpData::print_data_on(outputStream* st) const { print_shared(st, "JumpData"); st->print_cr("taken(%u) displacement(%d)", taken(), displacement()); } #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()); + + ResourceMark rm; + SignatureStream ss(inv.signature()); + int args_count = MIN2(ss.reference_parameter_count(), max); + + return args_count * per_arg_cell_count + (args_count > 0 ? header_cell_count() : 0); +} + +class ArgumentOffsetComputer : public SignatureInfo { +private: + int _max; + GrowableArray _offsets; + + void set(int size, BasicType type) { _size += size; } + void do_object(int begin, int end) { + if (_offsets.length() < _max) { + _offsets.push(_size); + } + SignatureInfo::do_object(begin, end); + } + void do_array (int begin, int end) { + if (_offsets.length() < _max) { + _offsets.push(_size); + } + SignatureInfo::do_array(begin, end); + } + +public: + ArgumentOffsetComputer(Symbol* signature, int max) + : SignatureInfo(signature), _max(max), _offsets(Thread::current(), max) { + } + + int total() { lazy_iterate_parameters(); return _size; } + + int off_at(int i) const { return _offsets.at(i); } +}; + +void TypeStackSlotEntries::post_initialize(BytecodeStream* stream) { + ResourceMark rm; + + assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); + Bytecode_invoke inv(stream->method(), stream->bci()); + +#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); +#endif + + 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()); + } +} + +bool TypeEntries::is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p) { + return !is_type_none(p) && + !((Klass*)klass_part(p))->is_loader_alive(is_alive_cl); +} + +void TypeStackSlotEntries::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { + for (int i = 0; i < number_of_arguments(); i++) { + intptr_t p = type(i); + if (is_loader_alive(is_alive_cl, p)) { + set_type(i, type_none()); + } + } +} + +bool TypeStackSlotEntries::arguments_profiling_enabled() { + return MethodData::profile_arguments(); +} + +#ifndef PRODUCT +void TypeEntries::print_klass(outputStream* st, intptr_t k) { + if (is_type_none(k)) { + st->print("none"); + } else if (is_type_unknown(k)) { + st->print("unknown"); + } else { + valid_klass(k)->print_value_on(st); + } + if (was_null_seen(k)) { + st->print(" (null seen)"); + } +} + +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++) { + _pd->tab(st); + st->print("%d: stack(%u) ", i, stack_slot(i)); + print_klass(st, type(i)); + st->cr(); + } +} + +void CallTypeData::print_data_on(outputStream* st) const { + CounterData::print_data_on(st); + _args.print_data_on(st); +} + +void VirtualCallTypeData::print_data_on(outputStream* st) const { + VirtualCallData::print_data_on(st); + _args.print_data_on(st); +} +#endif + // ================================================================== // ReceiverTypeData // @@ -169,7 +292,7 @@ void ReceiverTypeData::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { } #ifndef PRODUCT -void ReceiverTypeData::print_receiver_data_on(outputStream* st) { +void ReceiverTypeData::print_receiver_data_on(outputStream* st) const { uint row; int entries = 0; for (row = 0; row < row_limit(); row++) { @@ -190,11 +313,11 @@ void ReceiverTypeData::print_receiver_data_on(outputStream* st) { } } } -void ReceiverTypeData::print_data_on(outputStream* st) { +void ReceiverTypeData::print_data_on(outputStream* st) const { print_shared(st, "ReceiverTypeData"); print_receiver_data_on(st); } -void VirtualCallData::print_data_on(outputStream* st) { +void VirtualCallData::print_data_on(outputStream* st) const { print_shared(st, "VirtualCallData"); print_receiver_data_on(st); } @@ -246,7 +369,7 @@ address RetData::fixup_ret(int return_bci, MethodData* h_mdo) { #ifndef PRODUCT -void RetData::print_data_on(outputStream* st) { +void RetData::print_data_on(outputStream* st) const { print_shared(st, "RetData"); uint row; int entries = 0; @@ -281,7 +404,7 @@ void BranchData::post_initialize(BytecodeStream* stream, MethodData* mdo) { } #ifndef PRODUCT -void BranchData::print_data_on(outputStream* st) { +void BranchData::print_data_on(outputStream* st) const { print_shared(st, "BranchData"); st->print_cr("taken(%u) displacement(%d)", taken(), displacement()); @@ -355,7 +478,7 @@ void MultiBranchData::post_initialize(BytecodeStream* stream, } #ifndef PRODUCT -void MultiBranchData::print_data_on(outputStream* st) { +void MultiBranchData::print_data_on(outputStream* st) const { print_shared(st, "MultiBranchData"); st->print_cr("default_count(%u) displacement(%d)", default_count(), default_displacement()); @@ -369,7 +492,7 @@ void MultiBranchData::print_data_on(outputStream* st) { #endif #ifndef PRODUCT -void ArgInfoData::print_data_on(outputStream* st) { +void ArgInfoData::print_data_on(outputStream* st) const { print_shared(st, "ArgInfoData"); int nargs = number_of_args(); for (int i = 0; i < nargs; i++) { @@ -407,7 +530,11 @@ int MethodData::bytecode_cell_count(Bytecodes::Code code) { } case Bytecodes::_invokespecial: case Bytecodes::_invokestatic: - return CounterData::static_cell_count(); + if (MethodData::profile_arguments()) { + return variable_cell_count; + } else { + return CounterData::static_cell_count(); + } case Bytecodes::_goto: case Bytecodes::_goto_w: case Bytecodes::_jsr: @@ -415,9 +542,17 @@ int MethodData::bytecode_cell_count(Bytecodes::Code code) { return JumpData::static_cell_count(); case Bytecodes::_invokevirtual: case Bytecodes::_invokeinterface: - return VirtualCallData::static_cell_count(); + if (MethodData::profile_arguments()) { + return variable_cell_count; + } else { + return VirtualCallData::static_cell_count(); + } case Bytecodes::_invokedynamic: - return CounterData::static_cell_count(); + if (MethodData::profile_arguments()) { + return variable_cell_count; + } else { + return CounterData::static_cell_count(); + } case Bytecodes::_ret: return RetData::static_cell_count(); case Bytecodes::_ifeq: @@ -453,7 +588,34 @@ int MethodData::compute_data_size(BytecodeStream* stream) { return 0; } if (cell_count == variable_cell_count) { - cell_count = MultiBranchData::compute_cell_count(stream); + switch (stream->code()) { + case Bytecodes::_lookupswitch: + case Bytecodes::_tableswitch: + cell_count = MultiBranchData::compute_cell_count(stream); + break; + 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())) { + cell_count = CallTypeData::compute_cell_count(stream); + } else { + cell_count = CounterData::static_cell_count(); + } + 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())) { + cell_count = VirtualCallTypeData::compute_cell_count(stream); + } else { + cell_count = VirtualCallData::static_cell_count(); + } + break; + } + default: + fatal("unexpected bytecode for var length profile data"); + } } // Note: cell_count might be zero, meaning that there is just // a DataLayout header, with no extra cells. @@ -499,6 +661,7 @@ int MethodData::compute_allocation_size_in_bytes(methodHandle method) { // Add a cell to record information about modified arguments. int arg_size = method->size_of_parameters(); object_size += DataLayout::compute_size_in_bytes(arg_size+1); + return object_size; } @@ -534,10 +697,20 @@ int MethodData::initialize_data(BytecodeStream* stream, } break; case Bytecodes::_invokespecial: - case Bytecodes::_invokestatic: - cell_count = CounterData::static_cell_count(); - tag = DataLayout::counter_data_tag; + case Bytecodes::_invokestatic: { + int counter_data_cell_count = CounterData::static_cell_count(); + if (profile_arguments_for_invoke(stream->method(), stream->bci())) { + cell_count = CallTypeData::compute_cell_count(stream); + } else { + cell_count = counter_data_cell_count; + } + if (cell_count > counter_data_cell_count) { + tag = DataLayout::call_type_data_tag; + } else { + tag = DataLayout::counter_data_tag; + } break; + } case Bytecodes::_goto: case Bytecodes::_goto_w: case Bytecodes::_jsr: @@ -546,15 +719,35 @@ int MethodData::initialize_data(BytecodeStream* stream, tag = DataLayout::jump_data_tag; break; case Bytecodes::_invokevirtual: - case Bytecodes::_invokeinterface: - cell_count = VirtualCallData::static_cell_count(); - tag = DataLayout::virtual_call_data_tag; + case Bytecodes::_invokeinterface: { + int virtual_call_data_cell_count = VirtualCallData::static_cell_count(); + if (profile_arguments_for_invoke(stream->method(), stream->bci())) { + cell_count = VirtualCallTypeData::compute_cell_count(stream); + } else { + cell_count = virtual_call_data_cell_count; + } + if (cell_count > virtual_call_data_cell_count) { + tag = DataLayout::virtual_call_type_data_tag; + } else { + tag = DataLayout::virtual_call_data_tag; + } break; - case Bytecodes::_invokedynamic: + } + case Bytecodes::_invokedynamic: { // %%% should make a type profile for any invokedynamic that takes a ref argument - cell_count = CounterData::static_cell_count(); - tag = DataLayout::counter_data_tag; + int counter_data_cell_count = CounterData::static_cell_count(); + if (profile_arguments_for_invoke(stream->method(), stream->bci())) { + cell_count = CallTypeData::compute_cell_count(stream); + } else { + cell_count = counter_data_cell_count; + } + if (cell_count > counter_data_cell_count) { + tag = DataLayout::call_type_data_tag; + } else { + tag = DataLayout::counter_data_tag; + } break; + } case Bytecodes::_ret: cell_count = RetData::static_cell_count(); tag = DataLayout::ret_data_tag; @@ -585,6 +778,11 @@ int MethodData::initialize_data(BytecodeStream* stream, break; } assert(tag == DataLayout::multi_branch_data_tag || + (MethodData::profile_arguments() && + (tag == DataLayout::call_type_data_tag || + tag == DataLayout::counter_data_tag || + tag == DataLayout::virtual_call_type_data_tag || + tag == DataLayout::virtual_call_data_tag)) || cell_count == bytecode_cell_count(c), "cell counts must agree"); if (cell_count >= 0) { assert(tag != DataLayout::no_tag, "bad tag"); @@ -631,6 +829,10 @@ ProfileData* DataLayout::data_in() { return new MultiBranchData(this); case DataLayout::arg_info_data_tag: return new ArgInfoData(this); + case DataLayout::call_type_data_tag: + return new CallTypeData(this); + case DataLayout::virtual_call_type_data_tag: + return new VirtualCallTypeData(this); }; } @@ -898,3 +1100,42 @@ void MethodData::verify_data_on(outputStream* st) { NEEDS_CLEANUP; // not yet implemented. } + +bool MethodData::profile_jsr292(methodHandle m, int bci) { + if (m->is_compiled_lambda_form()) { + return true; + } + + Bytecode_invoke inv(m , bci); + return inv.is_invokedynamic() || inv.is_invokehandle(); +} + +int MethodData::profile_arguments_flag() { + return TypeProfileLevel; +} + +bool MethodData::profile_arguments() { + return profile_arguments_flag() > no_type_profile && profile_arguments_flag() <= type_profile_all; +} + +bool MethodData::profile_arguments_jsr292_only() { + return profile_arguments_flag() == type_profile_jsr292; +} + +bool MethodData::profile_all_arguments() { + return profile_arguments_flag() == type_profile_all; +} + +bool MethodData::profile_arguments_for_invoke(methodHandle m, int bci) { + if (!profile_arguments()) { + return false; + } + + if (profile_all_arguments()) { + return true; + } + + assert(profile_arguments_jsr292_only(), "inconsistent"); + return profile_jsr292(m, bci); +} + diff --git a/src/share/vm/oops/methodData.hpp b/src/share/vm/oops/methodData.hpp index 76f9b1f221a63c4867534c01f0791a1d4d2f7e0e..2064d4365d6e328301105851c06ecb58bef1cc34 100644 --- a/src/share/vm/oops/methodData.hpp +++ b/src/share/vm/oops/methodData.hpp @@ -117,7 +117,9 @@ public: ret_data_tag, branch_data_tag, multi_branch_data_tag, - arg_info_data_tag + arg_info_data_tag, + call_type_data_tag, + virtual_call_type_data_tag }; enum { @@ -165,7 +167,7 @@ public: // occurred, and the MDO shows N occurrences of X, we make the // simplifying assumption that all N occurrences can be blamed // on that BCI. - int trap_state() { + int trap_state() const { return ((_header._struct._flags >> trap_shift) & trap_mask); } @@ -175,11 +177,11 @@ public: _header._struct._flags = (new_state << trap_shift) | old_flags; } - u1 flags() { + u1 flags() const { return _header._struct._flags; } - u2 bci() { + u2 bci() const { return _header._struct._bci; } @@ -198,7 +200,7 @@ public: void release_set_cell_at(int index, intptr_t value) { OrderAccess::release_store_ptr(&_cells[index], value); } - intptr_t cell_at(int index) { + intptr_t cell_at(int index) const { return _cells[index]; } @@ -206,7 +208,7 @@ public: assert(flag_number < flag_limit, "oob"); _header._struct._flags |= (0x1 << flag_number); } - bool flag_at(int flag_number) { + bool flag_at(int flag_number) const { assert(flag_number < flag_limit, "oob"); return (_header._struct._flags & (0x1 << flag_number)) != 0; } @@ -254,19 +256,22 @@ class BitData; class CounterData; class ReceiverTypeData; class VirtualCallData; +class VirtualCallTypeData; class RetData; +class CallTypeData; class JumpData; class BranchData; class ArrayData; class MultiBranchData; class ArgInfoData; - // ProfileData // // A ProfileData object is created to refer to a section of profiling // data in a structured way. class ProfileData : public ResourceObj { + friend class TypeEntries; + friend class TypeStackSlotEntries; private: #ifndef PRODUCT enum { @@ -280,6 +285,7 @@ private: protected: DataLayout* data() { return _data; } + const DataLayout* data() const { return _data; } enum { cell_size = DataLayout::cell_size @@ -287,7 +293,7 @@ protected: public: // How many cells are in this? - virtual int cell_count() { + virtual int cell_count() const { ShouldNotReachHere(); return -1; } @@ -307,7 +313,7 @@ protected: assert(0 <= index && index < cell_count(), "oob"); data()->release_set_cell_at(index, value); } - intptr_t intptr_at(int index) { + intptr_t intptr_at(int index) const { assert(0 <= index && index < cell_count(), "oob"); return data()->cell_at(index); } @@ -317,7 +323,7 @@ protected: void release_set_uint_at(int index, uint value) { release_set_intptr_at(index, (intptr_t) value); } - uint uint_at(int index) { + uint uint_at(int index) const { return (uint)intptr_at(index); } void set_int_at(int index, int value) { @@ -326,23 +332,23 @@ protected: void release_set_int_at(int index, int value) { release_set_intptr_at(index, (intptr_t) value); } - int int_at(int index) { + int int_at(int index) const { return (int)intptr_at(index); } - int int_at_unchecked(int index) { + int int_at_unchecked(int index) const { return (int)data()->cell_at(index); } void set_oop_at(int index, oop value) { set_intptr_at(index, cast_from_oop(value)); } - oop oop_at(int index) { + oop oop_at(int index) const { return cast_to_oop(intptr_at(index)); } void set_flag_at(int flag_number) { data()->set_flag_at(flag_number); } - bool flag_at(int flag_number) { + bool flag_at(int flag_number) const { return data()->flag_at(flag_number); } @@ -362,7 +368,7 @@ public: // Constructor for invalid ProfileData. ProfileData(); - u2 bci() { + u2 bci() const { return data()->bci(); } @@ -370,7 +376,7 @@ public: return (address)_data; } - int trap_state() { + int trap_state() const { return data()->trap_state(); } void set_trap_state(int new_state) { @@ -378,58 +384,68 @@ public: } // Type checking - virtual bool is_BitData() { return false; } - virtual bool is_CounterData() { return false; } - virtual bool is_JumpData() { return false; } - virtual bool is_ReceiverTypeData(){ return false; } - virtual bool is_VirtualCallData() { return false; } - virtual bool is_RetData() { return false; } - virtual bool is_BranchData() { return false; } - virtual bool is_ArrayData() { return false; } - virtual bool is_MultiBranchData() { return false; } - virtual bool is_ArgInfoData() { return false; } - - - BitData* as_BitData() { + virtual bool is_BitData() const { return false; } + virtual bool is_CounterData() const { return false; } + virtual bool is_JumpData() const { return false; } + virtual bool is_ReceiverTypeData()const { return false; } + virtual bool is_VirtualCallData() const { return false; } + virtual bool is_RetData() const { return false; } + virtual bool is_BranchData() const { return false; } + virtual bool is_ArrayData() const { return false; } + virtual bool is_MultiBranchData() const { return false; } + virtual bool is_ArgInfoData() const { return false; } + virtual bool is_CallTypeData() const { return false; } + virtual bool is_VirtualCallTypeData()const { return false; } + + + BitData* as_BitData() const { assert(is_BitData(), "wrong type"); return is_BitData() ? (BitData*) this : NULL; } - CounterData* as_CounterData() { + CounterData* as_CounterData() const { assert(is_CounterData(), "wrong type"); return is_CounterData() ? (CounterData*) this : NULL; } - JumpData* as_JumpData() { + JumpData* as_JumpData() const { assert(is_JumpData(), "wrong type"); return is_JumpData() ? (JumpData*) this : NULL; } - ReceiverTypeData* as_ReceiverTypeData() { + ReceiverTypeData* as_ReceiverTypeData() const { assert(is_ReceiverTypeData(), "wrong type"); return is_ReceiverTypeData() ? (ReceiverTypeData*)this : NULL; } - VirtualCallData* as_VirtualCallData() { + VirtualCallData* as_VirtualCallData() const { assert(is_VirtualCallData(), "wrong type"); return is_VirtualCallData() ? (VirtualCallData*)this : NULL; } - RetData* as_RetData() { + RetData* as_RetData() const { assert(is_RetData(), "wrong type"); return is_RetData() ? (RetData*) this : NULL; } - BranchData* as_BranchData() { + BranchData* as_BranchData() const { assert(is_BranchData(), "wrong type"); return is_BranchData() ? (BranchData*) this : NULL; } - ArrayData* as_ArrayData() { + ArrayData* as_ArrayData() const { assert(is_ArrayData(), "wrong type"); return is_ArrayData() ? (ArrayData*) this : NULL; } - MultiBranchData* as_MultiBranchData() { + MultiBranchData* as_MultiBranchData() const { assert(is_MultiBranchData(), "wrong type"); return is_MultiBranchData() ? (MultiBranchData*)this : NULL; } - ArgInfoData* as_ArgInfoData() { + ArgInfoData* as_ArgInfoData() const { assert(is_ArgInfoData(), "wrong type"); return is_ArgInfoData() ? (ArgInfoData*)this : NULL; } + CallTypeData* as_CallTypeData() const { + assert(is_CallTypeData(), "wrong type"); + return is_CallTypeData() ? (CallTypeData*)this : NULL; + } + VirtualCallTypeData* as_VirtualCallTypeData() const { + assert(is_VirtualCallTypeData(), "wrong type"); + return is_VirtualCallTypeData() ? (VirtualCallTypeData*)this : NULL; + } // Subclass specific initialization @@ -443,15 +459,15 @@ public: // an oop in a ProfileData to the ci equivalent. Generally speaking, // most ProfileData don't require any translation, so we provide the null // translation here, and the required translators are in the ci subclasses. - virtual void translate_from(ProfileData* data) {} + virtual void translate_from(const ProfileData* data) {} - virtual void print_data_on(outputStream* st) { + virtual void print_data_on(outputStream* st) const { ShouldNotReachHere(); } #ifndef PRODUCT - void print_shared(outputStream* st, const char* name); - void tab(outputStream* st); + void print_shared(outputStream* st, const char* name) const; + void tab(outputStream* st, bool first = false) const; #endif }; @@ -470,13 +486,13 @@ public: BitData(DataLayout* layout) : ProfileData(layout) { } - virtual bool is_BitData() { return true; } + virtual bool is_BitData() const { return true; } static int static_cell_count() { return bit_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } @@ -498,7 +514,7 @@ public: } #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -514,18 +530,18 @@ protected: public: CounterData(DataLayout* layout) : BitData(layout) {} - virtual bool is_CounterData() { return true; } + virtual bool is_CounterData() const { return true; } static int static_cell_count() { return counter_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } // Direct accessor - uint count() { + uint count() const { return uint_at(count_off); } @@ -542,7 +558,7 @@ public: } #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -570,18 +586,18 @@ public: layout->tag() == DataLayout::branch_data_tag, "wrong type"); } - virtual bool is_JumpData() { return true; } + virtual bool is_JumpData() const { return true; } static int static_cell_count() { return jump_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } // Direct accessor - uint taken() { + uint taken() const { return uint_at(taken_off_set); } @@ -598,7 +614,7 @@ public: return cnt; } - int displacement() { + int displacement() const { return int_at(displacement_off_set); } @@ -615,7 +631,332 @@ public: void post_initialize(BytecodeStream* stream, MethodData* mdo); #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; +#endif +}; + +// Entries in a ProfileData object to record types: it can either be +// none (no profile), unknown (conflicting profile data) or a klass if +// a single one is seen. Whether a null reference was seen is also +// recorded. No counter is associated with the type and a single type +// is tracked (unlike VirtualCallData). +class TypeEntries { + +public: + + // A single cell is used to record information for a type: + // - the cell is initialized to 0 + // - when a type is discovered it is stored in the cell + // - bit zero of the cell is used to record whether a null reference + // was encountered or not + // - bit 1 is set to record a conflict in the type information + + enum { + null_seen = 1, + type_mask = ~null_seen, + type_unknown = 2, + status_bits = null_seen | type_unknown, + type_klass_mask = ~status_bits + }; + + // what to initialize a cell to + static intptr_t type_none() { + return 0; + } + + // null seen = bit 0 set? + static bool was_null_seen(intptr_t v) { + return (v & null_seen) != 0; + } + + // conflicting type information = bit 1 set? + static bool is_type_unknown(intptr_t v) { + return (v & type_unknown) != 0; + } + + // not type information yet = all bits cleared, ignoring bit 0? + static bool is_type_none(intptr_t v) { + return (v & type_mask) == 0; + } + + // recorded type: cell without bit 0 and 1 + static intptr_t klass_part(intptr_t v) { + intptr_t r = v & type_klass_mask; + assert (r != 0, "invalid"); + return r; + } + + // type recorded + static Klass* valid_klass(intptr_t k) { + if (!is_type_none(k) && + !is_type_unknown(k)) { + return (Klass*)klass_part(k); + } else { + return NULL; + } + } + + static intptr_t with_status(intptr_t k, intptr_t in) { + return k | (in & status_bits); + } + + static intptr_t with_status(Klass* k, intptr_t in) { + return with_status((intptr_t)k, in); + } + +#ifndef PRODUCT + static void print_klass(outputStream* st, intptr_t k); +#endif + + // GC support + static bool is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p); + +protected: + // ProfileData object these entries are part of + ProfileData* _pd; + // offset within the ProfileData object where the entries start + const int _base_off; + + TypeEntries(int base_off) + : _base_off(base_off), _pd(NULL) {} + + void set_intptr_at(int index, intptr_t value) { + _pd->set_intptr_at(index, value); + } + + intptr_t intptr_at(int index) const { + return _pd->intptr_at(index); + } + +public: + void set_profile_data(ProfileData* pd) { + _pd = pd; + } +}; + +// Type entries used for arguments passed at a call and parameters on +// method entry. 2 cells per entry: one for the type encoded as in +// TypeEntries and one initialized with the stack slot where the +// profiled object is to be found so that the interpreter can locate +// it quickly. +class TypeStackSlotEntries : public TypeEntries { + +private: + enum { + stack_slot_entry, + type_entry, + per_arg_cell_count + }; + + // Start with a header if needed. It stores the number of cells used + // for this call type information. Unless we collect only profiling + // for a single argument the number of cells is unknown statically. + static int header_cell_count() { + return (TypeProfileArgsLimit > 1) ? 1 : 0; + } + + static int cell_count_local_offset() { + assert(arguments_profiling_enabled() && TypeProfileArgsLimit > 1, "no cell count"); + return 0; + } + + int cell_count_global_offset() const { + return _base_off + cell_count_local_offset(); + } + + // offset of cell for stack slot for entry i within ProfileData object + int stack_slot_global_offset(int i) const { + return _base_off + stack_slot_local_offset(i); + } + + void check_number_of_arguments(int total) { + assert(number_of_arguments() == total, "should be set in DataLayout::initialize"); + } + + // number of cells not counting the header + int cell_count_no_header() const { + return _pd->uint_at(cell_count_global_offset()); + } + + static bool arguments_profiling_enabled(); + static void assert_arguments_profiling_enabled() { + assert(arguments_profiling_enabled(), "args profiling should be on"); + } + +protected: + + // offset of cell for type for entry i within ProfileData object + int type_global_offset(int i) const { + return _base_off + type_local_offset(i); + } + +public: + + TypeStackSlotEntries(int base_off) + : TypeEntries(base_off) {} + + static int compute_cell_count(BytecodeStream* stream); + + static void initialize(DataLayout* dl, int base, int cell_count) { + if (TypeProfileArgsLimit > 1) { + int off = base + cell_count_local_offset(); + dl->set_cell_at(off, cell_count - base - header_cell_count()); + } + } + + void post_initialize(BytecodeStream* stream); + + int number_of_arguments() const { + assert_arguments_profiling_enabled(); + if (TypeProfileArgsLimit > 1) { + int cell_count = cell_count_no_header(); + int nb = cell_count / TypeStackSlotEntries::per_arg_count(); + assert(nb > 0 && nb <= TypeProfileArgsLimit , "only when we profile args"); + return nb; + } else { + assert(TypeProfileArgsLimit == 1, "at least one arg"); + return 1; + } + } + + int cell_count() const { + assert_arguments_profiling_enabled(); + if (TypeProfileArgsLimit > 1) { + return _base_off + header_cell_count() + _pd->int_at_unchecked(cell_count_global_offset()); + } else { + return _base_off + TypeStackSlotEntries::per_arg_count(); + } + } + + // 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) { + assert_arguments_profiling_enabled(); + return header_cell_count() + i * per_arg_cell_count + stack_slot_entry; + } + + // offset of cell for type for entry i within this block of cells for a TypeStackSlotEntries + static int type_local_offset(int i) { + return header_cell_count() + i * per_arg_cell_count + type_entry; + } + + // stack slot for entry i + uint stack_slot(int i) const { + assert(i >= 0 && i < number_of_arguments(), "oob"); + return _pd->uint_at(stack_slot_global_offset(i)); + } + + // set stack slot for entry i + void set_stack_slot(int i, uint num) { + assert(i >= 0 && i < number_of_arguments(), "oob"); + _pd->set_uint_at(stack_slot_global_offset(i), num); + } + + // type for entry i + intptr_t type(int i) const { + assert(i >= 0 && i < number_of_arguments(), "oob"); + return _pd->intptr_at(type_global_offset(i)); + } + + // set type for entry i + void set_type(int i, intptr_t k) { + assert(i >= 0 && i < number_of_arguments(), "oob"); + _pd->set_intptr_at(type_global_offset(i), k); + } + + static ByteSize per_arg_size() { + return in_ByteSize(per_arg_cell_count * DataLayout::cell_size); + } + + static int per_arg_count() { + return per_arg_cell_count ; + } + + // Code generation support + static ByteSize cell_count_offset() { + return in_ByteSize(cell_count_local_offset() * DataLayout::cell_size); + } + + static ByteSize args_data_offset() { + return in_ByteSize(header_cell_count() * DataLayout::cell_size); + } + + static ByteSize stack_slot_offset(int i) { + return in_ByteSize(stack_slot_local_offset(i) * DataLayout::cell_size); + } + + static ByteSize type_offset(int i) { + return in_ByteSize(type_local_offset(i) * DataLayout::cell_size); + } + + // GC support + void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); + +#ifndef PRODUCT + void print_data_on(outputStream* st) const; +#endif +}; + +// CallTypeData +// +// A CallTypeData is used to access profiling information about a non +// virtual call for which we collect type information about arguments. +class CallTypeData : public CounterData { +private: + TypeStackSlotEntries _args; + +public: + CallTypeData(DataLayout* layout) : + CounterData(layout), _args(CounterData::static_cell_count()) { + assert(layout->tag() == DataLayout::call_type_data_tag, "wrong type"); + // Some compilers (VC++) don't want this passed in member initialization list + _args.set_profile_data(this); + } + + const TypeStackSlotEntries* args() const { return &_args; } + + virtual bool is_CallTypeData() const { return true; } + + static int static_cell_count() { + return -1; + } + + static int compute_cell_count(BytecodeStream* stream) { + return CounterData::static_cell_count() + TypeStackSlotEntries::compute_cell_count(stream); + } + + static void initialize(DataLayout* dl, int cell_count) { + TypeStackSlotEntries::initialize(dl, CounterData::static_cell_count(), cell_count); + } + + virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) { + _args.post_initialize(stream); + } + + virtual int cell_count() const { + return _args.cell_count(); + } + + uint number_of_arguments() const { + return args()->number_of_arguments(); + } + + void set_argument_type(int i, Klass* k) { + intptr_t current = _args.type(i); + _args.set_type(i, TypeEntries::with_status(k, current)); + } + + // Code generation support + static ByteSize args_data_offset() { + return cell_offset(CounterData::static_cell_count()) + TypeStackSlotEntries::args_data_offset(); + } + + // GC support + virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) { + _args.clean_weak_klass_links(is_alive_closure); + } + +#ifndef PRODUCT + virtual void print_data_on(outputStream* st) const; #endif }; @@ -636,16 +977,17 @@ protected: public: ReceiverTypeData(DataLayout* layout) : CounterData(layout) { assert(layout->tag() == DataLayout::receiver_type_data_tag || - layout->tag() == DataLayout::virtual_call_data_tag, "wrong type"); + layout->tag() == DataLayout::virtual_call_data_tag || + layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type"); } - virtual bool is_ReceiverTypeData() { return true; } + virtual bool is_ReceiverTypeData() const { return true; } static int static_cell_count() { return counter_cell_count + (uint) TypeProfileWidth * receiver_type_row_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } @@ -660,7 +1002,7 @@ public: return count0_offset + row * receiver_type_row_cell_count; } - Klass* receiver(uint row) { + Klass* receiver(uint row) const { assert(row < row_limit(), "oob"); Klass* recv = (Klass*)intptr_at(receiver_cell_index(row)); @@ -673,7 +1015,7 @@ public: set_intptr_at(receiver_cell_index(row), (uintptr_t)k); } - uint receiver_count(uint row) { + uint receiver_count(uint row) const { assert(row < row_limit(), "oob"); return uint_at(receiver_count_cell_index(row)); } @@ -721,8 +1063,8 @@ public: virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); #ifndef PRODUCT - void print_receiver_data_on(outputStream* st); - void print_data_on(outputStream* st); + void print_receiver_data_on(outputStream* st) const; + void print_data_on(outputStream* st) const; #endif }; @@ -733,10 +1075,11 @@ public: class VirtualCallData : public ReceiverTypeData { public: VirtualCallData(DataLayout* layout) : ReceiverTypeData(layout) { - assert(layout->tag() == DataLayout::virtual_call_data_tag, "wrong type"); + assert(layout->tag() == DataLayout::virtual_call_data_tag || + layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type"); } - virtual bool is_VirtualCallData() { return true; } + virtual bool is_VirtualCallData() const { return true; } static int static_cell_count() { // At this point we could add more profile state, e.g., for arguments. @@ -744,7 +1087,7 @@ public: return ReceiverTypeData::static_cell_count(); } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } @@ -754,7 +1097,73 @@ public: } #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; +#endif +}; + +// VirtualCallTypeData +// +// A VirtualCallTypeData is used to access profiling information about +// a virtual call for which we collect type information about +// arguments. +class VirtualCallTypeData : public VirtualCallData { +private: + TypeStackSlotEntries _args; + +public: + VirtualCallTypeData(DataLayout* layout) : + VirtualCallData(layout), _args(VirtualCallData::static_cell_count()) { + assert(layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type"); + // Some compilers (VC++) don't want this passed in member initialization list + _args.set_profile_data(this); + } + + const TypeStackSlotEntries* args() const { return &_args; } + + virtual bool is_VirtualCallTypeData() const { return true; } + + static int static_cell_count() { + return -1; + } + + static int compute_cell_count(BytecodeStream* stream) { + return VirtualCallData::static_cell_count() + TypeStackSlotEntries::compute_cell_count(stream); + } + + static void initialize(DataLayout* dl, int cell_count) { + TypeStackSlotEntries::initialize(dl, VirtualCallData::static_cell_count(), cell_count); + } + + virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) { + _args.post_initialize(stream); + } + + virtual int cell_count() const { + return _args.cell_count(); + } + + uint number_of_arguments() const { + return args()->number_of_arguments(); + } + + void set_argument_type(int i, Klass* k) { + intptr_t current = _args.type(i); + _args.set_type(i, TypeEntries::with_status(k, current)); + } + + // Code generation support + static ByteSize args_data_offset() { + return cell_offset(VirtualCallData::static_cell_count()) + TypeStackSlotEntries::args_data_offset(); + } + + // GC support + virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) { + ReceiverTypeData::clean_weak_klass_links(is_alive_closure); + _args.clean_weak_klass_links(is_alive_closure); + } + +#ifndef PRODUCT + virtual void print_data_on(outputStream* st) const; #endif }; @@ -797,7 +1206,7 @@ public: assert(layout->tag() == DataLayout::ret_data_tag, "wrong type"); } - virtual bool is_RetData() { return true; } + virtual bool is_RetData() const { return true; } enum { no_bci = -1 // value of bci when bci1/2 are not in use. @@ -807,7 +1216,7 @@ public: return counter_cell_count + (uint) BciProfileWidth * ret_row_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } @@ -825,13 +1234,13 @@ public: } // Direct accessors - int bci(uint row) { + int bci(uint row) const { return int_at(bci_cell_index(row)); } - uint bci_count(uint row) { + uint bci_count(uint row) const { return uint_at(bci_count_cell_index(row)); } - int bci_displacement(uint row) { + int bci_displacement(uint row) const { return int_at(bci_displacement_cell_index(row)); } @@ -853,7 +1262,7 @@ public: void post_initialize(BytecodeStream* stream, MethodData* mdo); #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -878,18 +1287,18 @@ public: assert(layout->tag() == DataLayout::branch_data_tag, "wrong type"); } - virtual bool is_BranchData() { return true; } + virtual bool is_BranchData() const { return true; } static int static_cell_count() { return branch_cell_count; } - virtual int cell_count() { + virtual int cell_count() const { return static_cell_count(); } // Direct accessor - uint not_taken() { + uint not_taken() const { return uint_at(not_taken_off_set); } @@ -917,7 +1326,7 @@ public: void post_initialize(BytecodeStream* stream, MethodData* mdo); #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -935,15 +1344,15 @@ protected: array_start_off_set }; - uint array_uint_at(int index) { + uint array_uint_at(int index) const { int aindex = index + array_start_off_set; return uint_at(aindex); } - int array_int_at(int index) { + int array_int_at(int index) const { int aindex = index + array_start_off_set; return int_at(aindex); } - oop array_oop_at(int index) { + oop array_oop_at(int index) const { int aindex = index + array_start_off_set; return oop_at(aindex); } @@ -960,17 +1369,17 @@ protected: public: ArrayData(DataLayout* layout) : ProfileData(layout) {} - virtual bool is_ArrayData() { return true; } + virtual bool is_ArrayData() const { return true; } static int static_cell_count() { return -1; } - int array_len() { + int array_len() const { return int_at_unchecked(array_len_off_set); } - virtual int cell_count() { + virtual int cell_count() const { return array_len() + 1; } @@ -1017,29 +1426,29 @@ public: assert(layout->tag() == DataLayout::multi_branch_data_tag, "wrong type"); } - virtual bool is_MultiBranchData() { return true; } + virtual bool is_MultiBranchData() const { return true; } static int compute_cell_count(BytecodeStream* stream); - int number_of_cases() { + int number_of_cases() const { int alen = array_len() - 2; // get rid of default case here. assert(alen % per_case_cell_count == 0, "must be even"); return (alen / per_case_cell_count); } - uint default_count() { + uint default_count() const { return array_uint_at(default_count_off_set); } - int default_displacement() { + int default_displacement() const { return array_int_at(default_disaplacement_off_set); } - uint count_at(int index) { + uint count_at(int index) const { return array_uint_at(case_array_start + index * per_case_cell_count + relative_count_off_set); } - int displacement_at(int index) { + int displacement_at(int index) const { return array_int_at(case_array_start + index * per_case_cell_count + relative_displacement_off_set); @@ -1074,7 +1483,7 @@ public: void post_initialize(BytecodeStream* stream, MethodData* mdo); #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -1085,14 +1494,14 @@ public: assert(layout->tag() == DataLayout::arg_info_data_tag, "wrong type"); } - virtual bool is_ArgInfoData() { return true; } + virtual bool is_ArgInfoData() const { return true; } - int number_of_args() { + int number_of_args() const { return array_len(); } - uint arg_modified(int arg) { + uint arg_modified(int arg) const { return array_uint_at(arg); } @@ -1101,7 +1510,7 @@ public: } #ifndef PRODUCT - void print_data_on(outputStream* st); + void print_data_on(outputStream* st) const; #endif }; @@ -1271,6 +1680,18 @@ private: // return the argument info cell ArgInfoData *arg_info(); + enum { + no_type_profile = 0, + type_profile_jsr292 = 1, + type_profile_all = 2 + }; + + static bool profile_jsr292(methodHandle m, int bci); + static int profile_arguments_flag(); + static bool profile_arguments_jsr292_only(); + static bool profile_all_arguments(); + static bool profile_arguments_for_invoke(methodHandle m, int bci); + public: static int header_size() { return sizeof(MethodData)/wordSize; @@ -1510,6 +1931,8 @@ public: // verification void verify_on(outputStream* st); void verify_data_on(outputStream* st); + + static bool profile_arguments(); }; #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp index e8b7d171934ee1b3e31b5f545b956e03e2d62ba6..181ce69a8f49de67f935866848ddb050584528ce 100644 --- a/src/share/vm/runtime/globals.hpp +++ b/src/share/vm/runtime/globals.hpp @@ -2648,6 +2648,13 @@ class CommandLineFlags { product(bool, AggressiveOpts, false, \ "Enable aggressive optimizations - see arguments.cpp") \ \ + product_pd(uintx, TypeProfileLevel, \ + "Type profiling of arguments at call:" \ + "0->off ; 1->js292 only; 2->all methods") \ + \ + product(intx, TypeProfileArgsLimit, 2, \ + "max number of call arguments to consider for type profiling") \ + \ /* statistics */ \ develop(bool, CountCompiledCalls, false, \ "counts method invocations") \ @@ -3760,7 +3767,6 @@ class CommandLineFlags { product(bool, UseLockedTracing, false, \ "Use locked-tracing when doing event-based tracing") - /* * Macros for factoring of globals */ diff --git a/src/share/vm/runtime/java.cpp b/src/share/vm/runtime/java.cpp index 874765fa3e5017af57b2bbb11df67889299b361a..e33e935fb6f4ff4e5274a954b3ca8874b8c99aca 100644 --- a/src/share/vm/runtime/java.cpp +++ b/src/share/vm/runtime/java.cpp @@ -183,6 +183,7 @@ void print_method_profiling_data() { collected_profiled_methods->sort(&compare_methods); int count = collected_profiled_methods->length(); + int total_size = 0; if (count > 0) { for (int index = 0; index < count; index++) { Method* m = collected_profiled_methods->at(index); @@ -190,10 +191,13 @@ void print_method_profiling_data() { tty->print_cr("------------------------------------------------------------------------"); //m->print_name(tty); m->print_invocation_count(); + tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes()); tty->cr(); m->print_codes(); + total_size += m->method_data()->size_in_bytes(); } tty->print_cr("------------------------------------------------------------------------"); + tty->print_cr("Total MDO size: %d bytes", total_size); } } diff --git a/src/share/vm/runtime/signature.cpp b/src/share/vm/runtime/signature.cpp index ce1b069ee6b58a9db48c2a4a8e539a18cad9b788..388058aa538e1507799ca3addd5766df18e944b8 100644 --- a/src/share/vm/runtime/signature.cpp +++ b/src/share/vm/runtime/signature.cpp @@ -378,6 +378,16 @@ Symbol* SignatureStream::as_symbol_or_null() { return result; } +int SignatureStream::reference_parameter_count() { + int args_count = 0; + for ( ; !at_return_type(); next()) { + if (is_object()) { + args_count++; + } + } + return args_count; +} + bool SignatureVerifier::is_valid_signature(Symbol* sig) { const char* signature = (const char*)sig->bytes(); ssize_t len = sig->utf8_length(); diff --git a/src/share/vm/runtime/signature.hpp b/src/share/vm/runtime/signature.hpp index 33c8c8232ca08e0f295ed64ac57deda04485e695..4bd4d4bab1f14a72609a194496ab4605c5216ed1 100644 --- a/src/share/vm/runtime/signature.hpp +++ b/src/share/vm/runtime/signature.hpp @@ -401,6 +401,9 @@ class SignatureStream : public StackObj { // return same as_symbol except allocation of new symbols is avoided. Symbol* as_symbol_or_null(); + + // count the number of references in the signature + int reference_parameter_count(); }; class SignatureVerifier : public StackObj {