--- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -3100,6 +3100,10 @@
}
}
+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);
}
--- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -76,6 +76,8 @@
// 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, \
--- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -3632,6 +3632,161 @@
}
}
+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();
}
--- a/hotspot/src/cpu/x86/vm/globals_x86.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -79,6 +79,8 @@
// 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, \
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -1046,6 +1046,98 @@
}
}
+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) {
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -215,6 +215,8 @@
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,
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -1067,6 +1067,102 @@
}
}
+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) {
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -224,6 +224,8 @@
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,
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -773,6 +773,7 @@
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);
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -2970,6 +2970,7 @@
// profile this call
__ profile_final_call(rax);
+ __ profile_arguments_type(rax, method, rsi, true);
__ jump_from_interpreted(method, rax);
@@ -2984,6 +2985,7 @@
// 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 @@
__ 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 @@
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 @@
__ 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 @@
// 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 @@
// %%% 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);
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -3026,6 +3026,7 @@
// profile this call
__ profile_final_call(rax);
+ __ profile_arguments_type(rax, method, r13, true);
__ jump_from_interpreted(method, rax);
@@ -3040,6 +3041,7 @@
// 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 @@
__ 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 @@
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 @@
__ 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 @@
// 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 @@
// %%% 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);
--- a/hotspot/src/share/vm/c1/c1_Compilation.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_Compilation.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -601,6 +601,17 @@
}
}
+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);
--- a/hotspot/src/share/vm/c1/c1_Compilation.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_Compilation.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -246,6 +246,8 @@
(RangeCheckElimination || UseLoopInvariantCodeMotion) &&
method()->method_data()->trap_count(Deoptimization::Reason_none) == 0;
}
+
+ ciKlass* cha_exact_type(ciType* type);
};
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -1658,6 +1658,42 @@
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 @@
} 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 @@
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 @@
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 @@
}
#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) {
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -374,7 +374,7 @@
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 @@
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();)
--- a/hotspot/src/share/vm/c1/c1_Instruction.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_Instruction.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -104,6 +104,14 @@
}
}
+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 @@
// 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 @@
}
-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* 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::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 @@
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 {
--- a/hotspot/src/share/vm/c1/c1_Instruction.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_Instruction.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -322,6 +322,36 @@
_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 @@
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 @@
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 @@
{}
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 @@
virtual bool needs_exception_state() const { return false; }
+ ciType* exact_type() const { return NULL; }
ciType* declared_type() const;
// generic
@@ -1422,7 +1451,6 @@
}
ciType* declared_type() const;
- ciType* exact_type() const;
};
@@ -1490,7 +1518,7 @@
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 @@
, _id(id)
, _args(args)
, _recv(NULL)
- , _nonnull_state(AllBits)
{
assert(args != NULL, "args must exist");
ASSERT_VALUES
@@ -1537,21 +1564,12 @@
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,35 +2468,56 @@
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; }
-
- virtual void input_values_do(ValueVisitor* f) { if (_recv != NULL) f->visit(&_recv); }
+ 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; }
+
+ 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.
LEAF(RuntimeCall, Instruction)
--- a/hotspot/src/share/vm/c1/c1_InstructionPrinter.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_InstructionPrinter.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -892,6 +892,14 @@
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(')');
}
--- a/hotspot/src/share/vm/c1/c1_LIR.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_LIR.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -1001,6 +1001,17 @@
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 @@
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 @@
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 @@
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
--- a/hotspot/src/share/vm/c1/c1_LIR.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_LIR.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -882,6 +882,7 @@
class LIR_OpTypeCheck;
class LIR_OpCompareAndSwap;
class LIR_OpProfileCall;
+class LIR_OpProfileType;
#ifdef ASSERT
class LIR_OpAssert;
#endif
@@ -1005,6 +1006,7 @@
, end_opCompareAndSwap
, begin_opMDOProfile
, lir_profile_call
+ , lir_profile_type
, end_opMDOProfile
, begin_opAssert
, lir_assert
@@ -1145,6 +1147,7 @@
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 @@
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 @@
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 @@
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)); }
--- a/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -208,6 +208,7 @@
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);
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -2571,6 +2571,78 @@
}
+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::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();
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -434,6 +434,8 @@
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; }
--- a/hotspot/src/share/vm/c1/c1_Optimizer.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_Optimizer.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -657,6 +657,7 @@
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_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_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;
--- a/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -162,7 +162,7 @@
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 */ };
--- a/hotspot/src/share/vm/ci/ciClassList.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/ci/ciClassList.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -102,6 +102,7 @@
friend class ciMethodHandle; \
friend class ciMethodType; \
friend class ciReceiverTypeData; \
+friend class ciTypeEntries; \
friend class ciSymbol; \
friend class ciArray; \
friend class ciObjArray; \
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -235,6 +235,13 @@
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);
};
--- a/hotspot/src/share/vm/ci/ciKlass.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/ci/ciKlass.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -41,6 +41,7 @@
friend class ciEnv;
friend class ciField;
friend class ciMethod;
+ friend class ciMethodData;
friend class ciObjArrayKlass;
private:
@@ -121,6 +122,8 @@
// What kind of ciObject is this?
bool is_klass() const { return true; }
+ virtual ciKlass* exact_klass() = 0;
+
void print_name_on(outputStream* st);
};
--- a/hotspot/src/share/vm/ci/ciMethodData.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/ci/ciMethodData.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -125,7 +125,7 @@
#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 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 @@
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_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 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_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
--- a/hotspot/src/share/vm/ci/ciMethodData.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/ci/ciMethodData.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -41,6 +41,8 @@
class ciArrayData;
class ciMultiBranchData;
class ciArgInfoData;
+class ciCallTypeData;
+class ciVirtualCallTypeData;
typedef ProfileData ciProfileData;
@@ -59,6 +61,68 @@
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 @@
(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 @@
}
// 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 @@
}
// 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 @@
// 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();
--- a/hotspot/src/share/vm/ci/ciObjArrayKlass.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/ci/ciObjArrayKlass.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -179,3 +179,16 @@
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;
+}
--- a/hotspot/src/share/vm/ci/ciObjArrayKlass.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/ci/ciObjArrayKlass.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -73,6 +73,8 @@
bool is_obj_array_klass() const { return true; }
static ciObjArrayKlass* make(ciKlass* element_klass);
+
+ virtual ciKlass* exact_klass();
};
#endif // SHARE_VM_CI_CIOBJARRAYKLASS_HPP
--- a/hotspot/src/share/vm/ci/ciStreams.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/ci/ciStreams.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -277,11 +277,14 @@
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 @@
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;
+ }
};
--- a/hotspot/src/share/vm/ci/ciTypeArrayKlass.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/ci/ciTypeArrayKlass.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -57,6 +57,10 @@
// 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
--- a/hotspot/src/share/vm/oops/methodData.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/oops/methodData.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -56,6 +56,11 @@
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 @@
}
#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 @@
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 @@
#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 @@
// 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 @@
}
#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<int> _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 @@
}
#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_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 @@
#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 @@
}
#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 @@
}
#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 @@
#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 @@
}
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 @@
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 @@
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 @@
// 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 @@
}
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 @@
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 @@
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 @@
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 @@
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);
+}
+
--- a/hotspot/src/share/vm/oops/methodData.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/oops/methodData.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -117,7 +117,9 @@
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 @@
// 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 @@
_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 @@
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 @@
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 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 @@
protected:
DataLayout* data() { return _data; }
+ const DataLayout* data() const { return _data; }
enum {
cell_size = DataLayout::cell_size
@@ -287,7 +293,7 @@
public:
// How many cells are in this?
- virtual int cell_count() {
+ virtual int cell_count() const {
ShouldNotReachHere();
return -1;
}
@@ -307,7 +313,7 @@
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 @@
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 @@
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<intptr_t>(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 @@
// Constructor for invalid ProfileData.
ProfileData();
- u2 bci() {
+ u2 bci() const {
return data()->bci();
}
@@ -370,7 +376,7 @@
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 @@
}
// 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; }
+ 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() {
+ 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 @@
// 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 @@
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 @@
}
#ifndef PRODUCT
- void print_data_on(outputStream* st);
+ void print_data_on(outputStream* st) const;
#endif
};
@@ -514,18 +530,18 @@
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 @@
}
#ifndef PRODUCT
- void print_data_on(outputStream* st);
+ void print_data_on(outputStream* st) const;
#endif
};
@@ -570,18 +586,18 @@
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 @@
return cnt;
}
- int displacement() {
+ int displacement() const {
return int_at(displacement_off_set);
}
@@ -615,7 +631,332 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
return ReceiverTypeData::static_cell_count();
}
- virtual int cell_count() {
+ virtual int cell_count() const {
return static_cell_count();
}
@@ -754,7 +1097,73 @@
}
#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 @@
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 @@
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 @@
}
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
#ifndef PRODUCT
- void print_data_on(outputStream* st);
+ void print_data_on(outputStream* st) const;
#endif
};
@@ -1271,6 +1680,18 @@
// 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 @@
// verification
void verify_on(outputStream* st);
void verify_data_on(outputStream* st);
+
+ static bool profile_arguments();
};
#endif // SHARE_VM_OOPS_METHODDATAOOP_HPP
--- a/hotspot/src/share/vm/runtime/globals.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/runtime/globals.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -2648,6 +2648,13 @@
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 @@
product(bool, UseLockedTracing, false, \
"Use locked-tracing when doing event-based tracing")
-
/*
* Macros for factoring of globals
*/
--- a/hotspot/src/share/vm/runtime/java.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/runtime/java.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -183,6 +183,7 @@
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 @@
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);
}
}
--- a/hotspot/src/share/vm/runtime/signature.cpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/runtime/signature.cpp Fri Oct 11 19:16:52 2013 +0000
@@ -378,6 +378,16 @@
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();
--- a/hotspot/src/share/vm/runtime/signature.hpp Fri Oct 11 13:10:22 2013 +0200
+++ b/hotspot/src/share/vm/runtime/signature.hpp Fri Oct 11 19:16:52 2013 +0000
@@ -401,6 +401,9 @@
// 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 {