8023657: New type profiling points: arguments to call
X86 interpreter and c1 type profiling for arguments at calls Reviewed-by: kvn, twisti
This commit is contained in:
parent
b90addac58
commit
cbd0e9bf96
@ -3100,6 +3100,10 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
|
||||||
|
fatal("Type profiling not implemented on this platform");
|
||||||
|
}
|
||||||
|
|
||||||
void LIR_Assembler::align_backward_branch_target() {
|
void LIR_Assembler::align_backward_branch_target() {
|
||||||
__ align(OptoLoopAlignment);
|
__ align(OptoLoopAlignment);
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,8 @@ define_pd_global(bool, UseMembar, false);
|
|||||||
// GC Ergo Flags
|
// 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, 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) \
|
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
|
||||||
\
|
\
|
||||||
product(intx, UseVIS, 99, \
|
product(intx, UseVIS, 99, \
|
||||||
|
@ -3632,6 +3632,161 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
|
||||||
|
Register obj = op->obj()->as_register();
|
||||||
|
Register tmp = op->tmp()->as_pointer_register();
|
||||||
|
Address mdo_addr = as_Address(op->mdp()->as_address_ptr());
|
||||||
|
ciKlass* exact_klass = op->exact_klass();
|
||||||
|
intptr_t current_klass = op->current_klass();
|
||||||
|
bool not_null = op->not_null();
|
||||||
|
bool no_conflict = op->no_conflict();
|
||||||
|
|
||||||
|
Label update, next, none;
|
||||||
|
|
||||||
|
bool do_null = !not_null;
|
||||||
|
bool exact_klass_set = exact_klass != NULL && ciTypeEntries::valid_ciklass(current_klass) == exact_klass;
|
||||||
|
bool do_update = !TypeEntries::is_type_unknown(current_klass) && !exact_klass_set;
|
||||||
|
|
||||||
|
assert(do_null || do_update, "why are we here?");
|
||||||
|
assert(!TypeEntries::was_null_seen(current_klass) || do_update, "why are we here?");
|
||||||
|
|
||||||
|
__ verify_oop(obj);
|
||||||
|
|
||||||
|
if (tmp != obj) {
|
||||||
|
__ mov(tmp, obj);
|
||||||
|
}
|
||||||
|
if (do_null) {
|
||||||
|
__ testptr(tmp, tmp);
|
||||||
|
__ jccb(Assembler::notZero, update);
|
||||||
|
if (!TypeEntries::was_null_seen(current_klass)) {
|
||||||
|
__ orptr(mdo_addr, TypeEntries::null_seen);
|
||||||
|
}
|
||||||
|
if (do_update) {
|
||||||
|
#ifndef ASSERT
|
||||||
|
__ jmpb(next);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
__ jmp(next);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
__ testptr(tmp, tmp);
|
||||||
|
__ jccb(Assembler::notZero, update);
|
||||||
|
__ stop("unexpect null obj");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
__ bind(update);
|
||||||
|
|
||||||
|
if (do_update) {
|
||||||
|
#ifdef ASSERT
|
||||||
|
if (exact_klass != NULL) {
|
||||||
|
Label ok;
|
||||||
|
__ load_klass(tmp, tmp);
|
||||||
|
__ push(tmp);
|
||||||
|
__ mov_metadata(tmp, exact_klass->constant_encoding());
|
||||||
|
__ cmpptr(tmp, Address(rsp, 0));
|
||||||
|
__ jccb(Assembler::equal, ok);
|
||||||
|
__ stop("exact klass and actual klass differ");
|
||||||
|
__ bind(ok);
|
||||||
|
__ pop(tmp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!no_conflict) {
|
||||||
|
if (exact_klass == NULL || TypeEntries::is_type_none(current_klass)) {
|
||||||
|
if (exact_klass != NULL) {
|
||||||
|
__ mov_metadata(tmp, exact_klass->constant_encoding());
|
||||||
|
} else {
|
||||||
|
__ load_klass(tmp, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
__ xorptr(tmp, mdo_addr);
|
||||||
|
__ testptr(tmp, TypeEntries::type_klass_mask);
|
||||||
|
// klass seen before, nothing to do. The unknown bit may have been
|
||||||
|
// set already but no need to check.
|
||||||
|
__ jccb(Assembler::zero, next);
|
||||||
|
|
||||||
|
__ testptr(tmp, TypeEntries::type_unknown);
|
||||||
|
__ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
|
||||||
|
|
||||||
|
if (TypeEntries::is_type_none(current_klass)) {
|
||||||
|
__ cmpptr(mdo_addr, 0);
|
||||||
|
__ jccb(Assembler::equal, none);
|
||||||
|
__ cmpptr(mdo_addr, TypeEntries::null_seen);
|
||||||
|
__ jccb(Assembler::equal, none);
|
||||||
|
// There is a chance that the checks above (re-reading profiling
|
||||||
|
// data from memory) fail if another thread has just set the
|
||||||
|
// profiling to this obj's klass
|
||||||
|
__ xorptr(tmp, mdo_addr);
|
||||||
|
__ testptr(tmp, TypeEntries::type_klass_mask);
|
||||||
|
__ jccb(Assembler::zero, next);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(ciTypeEntries::valid_ciklass(current_klass) != NULL &&
|
||||||
|
ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only");
|
||||||
|
|
||||||
|
__ movptr(tmp, mdo_addr);
|
||||||
|
__ testptr(tmp, TypeEntries::type_unknown);
|
||||||
|
__ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
|
||||||
|
}
|
||||||
|
|
||||||
|
// different than before. Cannot keep accurate profile.
|
||||||
|
__ orptr(mdo_addr, TypeEntries::type_unknown);
|
||||||
|
|
||||||
|
if (TypeEntries::is_type_none(current_klass)) {
|
||||||
|
__ jmpb(next);
|
||||||
|
|
||||||
|
__ bind(none);
|
||||||
|
// first time here. Set profile type.
|
||||||
|
__ movptr(mdo_addr, tmp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// There's a single possible klass at this profile point
|
||||||
|
assert(exact_klass != NULL, "should be");
|
||||||
|
if (TypeEntries::is_type_none(current_klass)) {
|
||||||
|
__ mov_metadata(tmp, exact_klass->constant_encoding());
|
||||||
|
__ xorptr(tmp, mdo_addr);
|
||||||
|
__ testptr(tmp, TypeEntries::type_klass_mask);
|
||||||
|
#ifdef ASSERT
|
||||||
|
__ jcc(Assembler::zero, next);
|
||||||
|
|
||||||
|
{
|
||||||
|
Label ok;
|
||||||
|
__ push(tmp);
|
||||||
|
__ cmpptr(mdo_addr, 0);
|
||||||
|
__ jcc(Assembler::equal, ok);
|
||||||
|
__ cmpptr(mdo_addr, TypeEntries::null_seen);
|
||||||
|
__ jcc(Assembler::equal, ok);
|
||||||
|
// may have been set by another thread
|
||||||
|
__ mov_metadata(tmp, exact_klass->constant_encoding());
|
||||||
|
__ xorptr(tmp, mdo_addr);
|
||||||
|
__ testptr(tmp, TypeEntries::type_mask);
|
||||||
|
__ jcc(Assembler::zero, ok);
|
||||||
|
|
||||||
|
__ stop("unexpected profiling mismatch");
|
||||||
|
__ bind(ok);
|
||||||
|
__ pop(tmp);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
__ jccb(Assembler::zero, next);
|
||||||
|
#endif
|
||||||
|
// first time here. Set profile type.
|
||||||
|
__ movptr(mdo_addr, tmp);
|
||||||
|
} else {
|
||||||
|
assert(ciTypeEntries::valid_ciklass(current_klass) != NULL &&
|
||||||
|
ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent");
|
||||||
|
|
||||||
|
__ movptr(tmp, mdo_addr);
|
||||||
|
__ testptr(tmp, TypeEntries::type_unknown);
|
||||||
|
__ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
|
||||||
|
|
||||||
|
__ orptr(mdo_addr, TypeEntries::type_unknown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__ bind(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LIR_Assembler::emit_delay(LIR_OpDelay*) {
|
void LIR_Assembler::emit_delay(LIR_OpDelay*) {
|
||||||
Unimplemented();
|
Unimplemented();
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,8 @@ define_pd_global(bool, UseMembar, false);
|
|||||||
// GC Ergo Flags
|
// 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, 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) \
|
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
|
||||||
\
|
\
|
||||||
develop(bool, IEEEPrecision, true, \
|
develop(bool, IEEEPrecision, true, \
|
||||||
|
@ -1046,6 +1046,98 @@ void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) {
|
||||||
|
Label update, next, none;
|
||||||
|
|
||||||
|
verify_oop(obj);
|
||||||
|
|
||||||
|
testptr(obj, obj);
|
||||||
|
jccb(Assembler::notZero, update);
|
||||||
|
orptr(mdo_addr, TypeEntries::null_seen);
|
||||||
|
jmpb(next);
|
||||||
|
|
||||||
|
bind(update);
|
||||||
|
load_klass(obj, obj);
|
||||||
|
|
||||||
|
xorptr(obj, mdo_addr);
|
||||||
|
testptr(obj, TypeEntries::type_klass_mask);
|
||||||
|
jccb(Assembler::zero, next); // klass seen before, nothing to
|
||||||
|
// do. The unknown bit may have been
|
||||||
|
// set already but no need to check.
|
||||||
|
|
||||||
|
testptr(obj, TypeEntries::type_unknown);
|
||||||
|
jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
|
||||||
|
|
||||||
|
cmpptr(mdo_addr, 0);
|
||||||
|
jccb(Assembler::equal, none);
|
||||||
|
cmpptr(mdo_addr, TypeEntries::null_seen);
|
||||||
|
jccb(Assembler::equal, none);
|
||||||
|
// There is a chance that the checks above (re-reading profiling
|
||||||
|
// data from memory) fail if another thread has just set the
|
||||||
|
// profiling to this obj's klass
|
||||||
|
xorptr(obj, mdo_addr);
|
||||||
|
testptr(obj, TypeEntries::type_klass_mask);
|
||||||
|
jccb(Assembler::zero, next);
|
||||||
|
|
||||||
|
// different than before. Cannot keep accurate profile.
|
||||||
|
orptr(mdo_addr, TypeEntries::type_unknown);
|
||||||
|
jmpb(next);
|
||||||
|
|
||||||
|
bind(none);
|
||||||
|
// first time here. Set profile type.
|
||||||
|
movptr(mdo_addr, obj);
|
||||||
|
|
||||||
|
bind(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) {
|
||||||
|
if (!ProfileInterpreter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MethodData::profile_arguments()) {
|
||||||
|
Label profile_continue;
|
||||||
|
|
||||||
|
test_method_data_pointer(mdp, profile_continue);
|
||||||
|
|
||||||
|
int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size());
|
||||||
|
|
||||||
|
cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag);
|
||||||
|
jcc(Assembler::notEqual, profile_continue);
|
||||||
|
|
||||||
|
Label done;
|
||||||
|
int off_to_args = in_bytes(TypeStackSlotEntries::args_data_offset());
|
||||||
|
addptr(mdp, off_to_args);
|
||||||
|
|
||||||
|
for (int i = 0; i < TypeProfileArgsLimit; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
movl(tmp, Address(mdp, in_bytes(TypeStackSlotEntries::cell_count_offset())-off_to_args));
|
||||||
|
subl(tmp, i*TypeStackSlotEntries::per_arg_count());
|
||||||
|
cmpl(tmp, TypeStackSlotEntries::per_arg_count());
|
||||||
|
jcc(Assembler::less, done);
|
||||||
|
}
|
||||||
|
movptr(tmp, Address(callee, Method::const_offset()));
|
||||||
|
load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset()));
|
||||||
|
subl(tmp, Address(mdp, in_bytes(TypeStackSlotEntries::stack_slot_offset(i))-off_to_args));
|
||||||
|
subl(tmp, 1);
|
||||||
|
Address arg_addr = argument_address(tmp);
|
||||||
|
movptr(tmp, arg_addr);
|
||||||
|
|
||||||
|
Address mdo_arg_addr(mdp, in_bytes(TypeStackSlotEntries::type_offset(i))-off_to_args);
|
||||||
|
profile_obj_type(tmp, mdo_arg_addr);
|
||||||
|
|
||||||
|
int to_add = in_bytes(TypeStackSlotEntries::per_arg_size());
|
||||||
|
addptr(mdp, to_add);
|
||||||
|
off_to_args += to_add;
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(done);
|
||||||
|
|
||||||
|
movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp);
|
||||||
|
|
||||||
|
bind(profile_continue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void InterpreterMacroAssembler::profile_call(Register mdp) {
|
void InterpreterMacroAssembler::profile_call(Register mdp) {
|
||||||
if (ProfileInterpreter) {
|
if (ProfileInterpreter) {
|
||||||
|
@ -215,6 +215,8 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
|||||||
|
|
||||||
void profile_taken_branch(Register mdp, Register bumped_count);
|
void profile_taken_branch(Register mdp, Register bumped_count);
|
||||||
void profile_not_taken_branch(Register mdp);
|
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_call(Register mdp);
|
||||||
void profile_final_call(Register mdp);
|
void profile_final_call(Register mdp);
|
||||||
void profile_virtual_call(Register receiver, Register mdp, Register scratch2,
|
void profile_virtual_call(Register receiver, Register mdp, Register scratch2,
|
||||||
|
@ -1067,6 +1067,102 @@ void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) {
|
||||||
|
Label update, next, none;
|
||||||
|
|
||||||
|
verify_oop(obj);
|
||||||
|
|
||||||
|
testptr(obj, obj);
|
||||||
|
jccb(Assembler::notZero, update);
|
||||||
|
orptr(mdo_addr, TypeEntries::null_seen);
|
||||||
|
jmpb(next);
|
||||||
|
|
||||||
|
bind(update);
|
||||||
|
load_klass(obj, obj);
|
||||||
|
|
||||||
|
xorptr(obj, mdo_addr);
|
||||||
|
testptr(obj, TypeEntries::type_klass_mask);
|
||||||
|
jccb(Assembler::zero, next); // klass seen before, nothing to
|
||||||
|
// do. The unknown bit may have been
|
||||||
|
// set already but no need to check.
|
||||||
|
|
||||||
|
testptr(obj, TypeEntries::type_unknown);
|
||||||
|
jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
|
||||||
|
|
||||||
|
// There is a chance that by the time we do these checks (re-reading
|
||||||
|
// profiling data from memory) another thread has set the profling
|
||||||
|
// to this obj's klass and we set the profiling as unknow
|
||||||
|
// erroneously
|
||||||
|
cmpptr(mdo_addr, 0);
|
||||||
|
jccb(Assembler::equal, none);
|
||||||
|
cmpptr(mdo_addr, TypeEntries::null_seen);
|
||||||
|
jccb(Assembler::equal, none);
|
||||||
|
// There is a chance that the checks above (re-reading profiling
|
||||||
|
// data from memory) fail if another thread has just set the
|
||||||
|
// profiling to this obj's klass
|
||||||
|
xorptr(obj, mdo_addr);
|
||||||
|
testptr(obj, TypeEntries::type_klass_mask);
|
||||||
|
jccb(Assembler::zero, next);
|
||||||
|
|
||||||
|
// different than before. Cannot keep accurate profile.
|
||||||
|
orptr(mdo_addr, TypeEntries::type_unknown);
|
||||||
|
jmpb(next);
|
||||||
|
|
||||||
|
bind(none);
|
||||||
|
// first time here. Set profile type.
|
||||||
|
movptr(mdo_addr, obj);
|
||||||
|
|
||||||
|
bind(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) {
|
||||||
|
if (!ProfileInterpreter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MethodData::profile_arguments()) {
|
||||||
|
Label profile_continue;
|
||||||
|
|
||||||
|
test_method_data_pointer(mdp, profile_continue);
|
||||||
|
|
||||||
|
int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size());
|
||||||
|
|
||||||
|
cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag);
|
||||||
|
jcc(Assembler::notEqual, profile_continue);
|
||||||
|
|
||||||
|
Label done;
|
||||||
|
int off_to_args = in_bytes(TypeStackSlotEntries::args_data_offset());
|
||||||
|
addptr(mdp, off_to_args);
|
||||||
|
|
||||||
|
for (int i = 0; i < TypeProfileArgsLimit; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
movq(tmp, Address(mdp, in_bytes(TypeStackSlotEntries::cell_count_offset())-off_to_args));
|
||||||
|
subl(tmp, i*TypeStackSlotEntries::per_arg_count());
|
||||||
|
cmpl(tmp, TypeStackSlotEntries::per_arg_count());
|
||||||
|
jcc(Assembler::less, done);
|
||||||
|
}
|
||||||
|
movptr(tmp, Address(callee, Method::const_offset()));
|
||||||
|
load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset()));
|
||||||
|
subq(tmp, Address(mdp, in_bytes(TypeStackSlotEntries::stack_slot_offset(i))-off_to_args));
|
||||||
|
subl(tmp, 1);
|
||||||
|
Address arg_addr = argument_address(tmp);
|
||||||
|
movptr(tmp, arg_addr);
|
||||||
|
|
||||||
|
Address mdo_arg_addr(mdp, in_bytes(TypeStackSlotEntries::type_offset(i))-off_to_args);
|
||||||
|
profile_obj_type(tmp, mdo_arg_addr);
|
||||||
|
|
||||||
|
int to_add = in_bytes(TypeStackSlotEntries::per_arg_size());
|
||||||
|
addptr(mdp, to_add);
|
||||||
|
off_to_args += to_add;
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(done);
|
||||||
|
|
||||||
|
movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp);
|
||||||
|
|
||||||
|
bind(profile_continue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void InterpreterMacroAssembler::profile_call(Register mdp) {
|
void InterpreterMacroAssembler::profile_call(Register mdp) {
|
||||||
if (ProfileInterpreter) {
|
if (ProfileInterpreter) {
|
||||||
|
@ -224,6 +224,8 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
|||||||
|
|
||||||
void profile_taken_branch(Register mdp, Register bumped_count);
|
void profile_taken_branch(Register mdp, Register bumped_count);
|
||||||
void profile_not_taken_branch(Register mdp);
|
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_call(Register mdp);
|
||||||
void profile_final_call(Register mdp);
|
void profile_final_call(Register mdp);
|
||||||
void profile_virtual_call(Register receiver, Register mdp,
|
void profile_virtual_call(Register receiver, Register mdp,
|
||||||
|
@ -773,6 +773,7 @@ class MacroAssembler: public Assembler {
|
|||||||
void orptr(Register dst, Address src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); }
|
void orptr(Register dst, 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, 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(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 src, int32_t imm32) { LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); }
|
||||||
void testptr(Register src1, Register src2);
|
void testptr(Register src1, Register src2);
|
||||||
|
@ -2970,6 +2970,7 @@ void TemplateTable::invokevirtual_helper(Register index,
|
|||||||
|
|
||||||
// profile this call
|
// profile this call
|
||||||
__ profile_final_call(rax);
|
__ profile_final_call(rax);
|
||||||
|
__ profile_arguments_type(rax, method, rsi, true);
|
||||||
|
|
||||||
__ jump_from_interpreted(method, rax);
|
__ jump_from_interpreted(method, rax);
|
||||||
|
|
||||||
@ -2984,6 +2985,7 @@ void TemplateTable::invokevirtual_helper(Register index,
|
|||||||
|
|
||||||
// get target Method* & entry point
|
// get target Method* & entry point
|
||||||
__ lookup_virtual_method(rax, index, method);
|
__ lookup_virtual_method(rax, index, method);
|
||||||
|
__ profile_arguments_type(rdx, method, rsi, true);
|
||||||
__ jump_from_interpreted(method, rdx);
|
__ jump_from_interpreted(method, rdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3013,6 +3015,7 @@ void TemplateTable::invokespecial(int byte_no) {
|
|||||||
__ null_check(rcx);
|
__ null_check(rcx);
|
||||||
// do the call
|
// do the call
|
||||||
__ profile_call(rax);
|
__ profile_call(rax);
|
||||||
|
__ profile_arguments_type(rax, rbx, rsi, false);
|
||||||
__ jump_from_interpreted(rbx, rax);
|
__ jump_from_interpreted(rbx, rax);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3023,6 +3026,7 @@ void TemplateTable::invokestatic(int byte_no) {
|
|||||||
prepare_invoke(byte_no, rbx); // get f1 Method*
|
prepare_invoke(byte_no, rbx); // get f1 Method*
|
||||||
// do the call
|
// do the call
|
||||||
__ profile_call(rax);
|
__ profile_call(rax);
|
||||||
|
__ profile_arguments_type(rax, rbx, rsi, false);
|
||||||
__ jump_from_interpreted(rbx, rax);
|
__ jump_from_interpreted(rbx, rax);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3082,6 +3086,8 @@ void TemplateTable::invokeinterface(int byte_no) {
|
|||||||
__ testptr(rbx, rbx);
|
__ testptr(rbx, rbx);
|
||||||
__ jcc(Assembler::zero, no_such_method);
|
__ jcc(Assembler::zero, no_such_method);
|
||||||
|
|
||||||
|
__ profile_arguments_type(rdx, rbx, rsi, true);
|
||||||
|
|
||||||
// do the call
|
// do the call
|
||||||
// rcx: receiver
|
// rcx: receiver
|
||||||
// rbx,: Method*
|
// rbx,: Method*
|
||||||
@ -3138,6 +3144,7 @@ void TemplateTable::invokehandle(int byte_no) {
|
|||||||
|
|
||||||
// FIXME: profile the LambdaForm also
|
// FIXME: profile the LambdaForm also
|
||||||
__ profile_final_call(rax);
|
__ profile_final_call(rax);
|
||||||
|
__ profile_arguments_type(rdx, rbx_method, rsi, true);
|
||||||
|
|
||||||
__ jump_from_interpreted(rbx_method, rdx);
|
__ jump_from_interpreted(rbx_method, rdx);
|
||||||
}
|
}
|
||||||
@ -3171,6 +3178,7 @@ void TemplateTable::invokedynamic(int byte_no) {
|
|||||||
// %%% should make a type profile for any invokedynamic that takes a ref argument
|
// %%% should make a type profile for any invokedynamic that takes a ref argument
|
||||||
// profile this call
|
// profile this call
|
||||||
__ profile_call(rsi);
|
__ profile_call(rsi);
|
||||||
|
__ profile_arguments_type(rdx, rbx, rsi, false);
|
||||||
|
|
||||||
__ verify_oop(rax_callsite);
|
__ verify_oop(rax_callsite);
|
||||||
|
|
||||||
|
@ -3026,6 +3026,7 @@ void TemplateTable::invokevirtual_helper(Register index,
|
|||||||
|
|
||||||
// profile this call
|
// profile this call
|
||||||
__ profile_final_call(rax);
|
__ profile_final_call(rax);
|
||||||
|
__ profile_arguments_type(rax, method, r13, true);
|
||||||
|
|
||||||
__ jump_from_interpreted(method, rax);
|
__ jump_from_interpreted(method, rax);
|
||||||
|
|
||||||
@ -3040,6 +3041,7 @@ void TemplateTable::invokevirtual_helper(Register index,
|
|||||||
|
|
||||||
// get target Method* & entry point
|
// get target Method* & entry point
|
||||||
__ lookup_virtual_method(rax, index, method);
|
__ lookup_virtual_method(rax, index, method);
|
||||||
|
__ profile_arguments_type(rdx, method, r13, true);
|
||||||
__ jump_from_interpreted(method, rdx);
|
__ jump_from_interpreted(method, rdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3069,6 +3071,7 @@ void TemplateTable::invokespecial(int byte_no) {
|
|||||||
__ null_check(rcx);
|
__ null_check(rcx);
|
||||||
// do the call
|
// do the call
|
||||||
__ profile_call(rax);
|
__ profile_call(rax);
|
||||||
|
__ profile_arguments_type(rax, rbx, r13, false);
|
||||||
__ jump_from_interpreted(rbx, rax);
|
__ jump_from_interpreted(rbx, rax);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3079,6 +3082,7 @@ void TemplateTable::invokestatic(int byte_no) {
|
|||||||
prepare_invoke(byte_no, rbx); // get f1 Method*
|
prepare_invoke(byte_no, rbx); // get f1 Method*
|
||||||
// do the call
|
// do the call
|
||||||
__ profile_call(rax);
|
__ profile_call(rax);
|
||||||
|
__ profile_arguments_type(rax, rbx, r13, false);
|
||||||
__ jump_from_interpreted(rbx, rax);
|
__ jump_from_interpreted(rbx, rax);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3136,6 +3140,8 @@ void TemplateTable::invokeinterface(int byte_no) {
|
|||||||
__ testptr(rbx, rbx);
|
__ testptr(rbx, rbx);
|
||||||
__ jcc(Assembler::zero, no_such_method);
|
__ jcc(Assembler::zero, no_such_method);
|
||||||
|
|
||||||
|
__ profile_arguments_type(rdx, rbx, r13, true);
|
||||||
|
|
||||||
// do the call
|
// do the call
|
||||||
// rcx: receiver
|
// rcx: receiver
|
||||||
// rbx,: Method*
|
// rbx,: Method*
|
||||||
@ -3193,6 +3199,7 @@ void TemplateTable::invokehandle(int byte_no) {
|
|||||||
|
|
||||||
// FIXME: profile the LambdaForm also
|
// FIXME: profile the LambdaForm also
|
||||||
__ profile_final_call(rax);
|
__ profile_final_call(rax);
|
||||||
|
__ profile_arguments_type(rdx, rbx_method, r13, true);
|
||||||
|
|
||||||
__ jump_from_interpreted(rbx_method, rdx);
|
__ jump_from_interpreted(rbx_method, rdx);
|
||||||
}
|
}
|
||||||
@ -3226,6 +3233,7 @@ void TemplateTable::invokedynamic(int byte_no) {
|
|||||||
// %%% should make a type profile for any invokedynamic that takes a ref argument
|
// %%% should make a type profile for any invokedynamic that takes a ref argument
|
||||||
// profile this call
|
// profile this call
|
||||||
__ profile_call(r13);
|
__ profile_call(r13);
|
||||||
|
__ profile_arguments_type(rdx, rbx_method, r13, false);
|
||||||
|
|
||||||
__ verify_oop(rax_callsite);
|
__ verify_oop(rax_callsite);
|
||||||
|
|
||||||
|
@ -601,6 +601,17 @@ void Compilation::bailout(const char* msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ciKlass* Compilation::cha_exact_type(ciType* type) {
|
||||||
|
if (type != NULL && type->is_loaded() && type->is_instance_klass()) {
|
||||||
|
ciInstanceKlass* ik = type->as_instance_klass();
|
||||||
|
assert(ik->exact_klass() == NULL, "no cha for final klass");
|
||||||
|
if (DeoptC1 && UseCHA && !(ik->has_subklass() || ik->is_interface())) {
|
||||||
|
dependency_recorder()->assert_leaf_type(ik);
|
||||||
|
return ik;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void Compilation::print_timers() {
|
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);
|
// 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);
|
||||||
|
@ -246,6 +246,8 @@ class Compilation: public StackObj {
|
|||||||
(RangeCheckElimination || UseLoopInvariantCodeMotion) &&
|
(RangeCheckElimination || UseLoopInvariantCodeMotion) &&
|
||||||
method()->method_data()->trap_count(Deoptimization::Reason_none) == 0;
|
method()->method_data()->trap_count(Deoptimization::Reason_none) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ciKlass* cha_exact_type(ciType* type);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1658,6 +1658,42 @@ Dependencies* GraphBuilder::dependency_recorder() const {
|
|||||||
return compilation()->dependency_recorder();
|
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) {
|
void GraphBuilder::invoke(Bytecodes::Code code) {
|
||||||
bool will_link;
|
bool will_link;
|
||||||
@ -1957,7 +1993,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
|||||||
} else if (exact_target != NULL) {
|
} else if (exact_target != NULL) {
|
||||||
target_klass = exact_target->holder();
|
target_klass = exact_target->holder();
|
||||||
}
|
}
|
||||||
profile_call(target, recv, target_klass);
|
profile_call(target, recv, target_klass, collect_args_for_profiling(args, false), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3509,7 +3545,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
|
|||||||
recv = args->at(0);
|
recv = args->at(0);
|
||||||
null_check(recv);
|
null_check(recv);
|
||||||
}
|
}
|
||||||
profile_call(callee, recv, NULL);
|
profile_call(callee, recv, NULL, collect_args_for_profiling(args, true), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3763,7 +3799,28 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
|
|||||||
compilation()->set_would_profile(true);
|
compilation()->set_would_profile(true);
|
||||||
|
|
||||||
if (profile_calls()) {
|
if (profile_calls()) {
|
||||||
profile_call(callee, recv, holder_known ? callee->holder() : NULL);
|
int start = 0;
|
||||||
|
Values* obj_args = args_list_for_profiling(start, has_receiver);
|
||||||
|
if (obj_args != NULL) {
|
||||||
|
int s = obj_args->size();
|
||||||
|
// if called through method handle invoke, some arguments may have been popped
|
||||||
|
for (int i = args_base+start, j = 0; j < obj_args->size() && i < state()->stack_size(); ) {
|
||||||
|
Value v = state()->stack_at_inc(i);
|
||||||
|
if (v->type()->is_object_kind()) {
|
||||||
|
obj_args->push(v);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef ASSERT
|
||||||
|
{
|
||||||
|
bool ignored_will_link;
|
||||||
|
ciSignature* declared_signature = NULL;
|
||||||
|
ciMethod* real_target = method()->get_method_at_bci(bci(), ignored_will_link, &declared_signature);
|
||||||
|
assert(s == obj_args->length() || real_target->is_method_handle_intrinsic(), "missed on arg?");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
profile_call(callee, recv, holder_known ? callee->holder() : NULL, obj_args, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4251,8 +4308,8 @@ void GraphBuilder::print_stats() {
|
|||||||
}
|
}
|
||||||
#endif // PRODUCT
|
#endif // PRODUCT
|
||||||
|
|
||||||
void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* 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));
|
append(new ProfileCall(method(), bci(), callee, recv, known_holder, obj_args, inlined));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphBuilder::profile_invocation(ciMethod* callee, ValueStack* state) {
|
void GraphBuilder::profile_invocation(ciMethod* callee, ValueStack* state) {
|
||||||
|
@ -374,7 +374,7 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
|
|||||||
|
|
||||||
void print_inlining(ciMethod* callee, const char* msg = NULL, bool success = true);
|
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);
|
void profile_invocation(ciMethod* inlinee, ValueStack* state);
|
||||||
|
|
||||||
// Shortcuts to profiling control.
|
// Shortcuts to profiling control.
|
||||||
@ -386,6 +386,9 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
|
|||||||
bool profile_inlined_calls() { return _compilation->profile_inlined_calls(); }
|
bool profile_inlined_calls() { return _compilation->profile_inlined_calls(); }
|
||||||
bool profile_checkcasts() { return _compilation->profile_checkcasts(); }
|
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:
|
public:
|
||||||
NOT_PRODUCT(void print_stats();)
|
NOT_PRODUCT(void print_stats();)
|
||||||
|
|
||||||
|
@ -104,6 +104,14 @@ void Instruction::state_values_do(ValueVisitor* f) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ciType* Instruction::exact_type() const {
|
||||||
|
ciType* t = declared_type();
|
||||||
|
if (t != NULL && t->is_klass()) {
|
||||||
|
return t->as_klass()->exact_klass();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void Instruction::check_state(ValueStack* state) {
|
void Instruction::check_state(ValueStack* state) {
|
||||||
@ -135,9 +143,7 @@ void Instruction::print(InstructionPrinter& ip) {
|
|||||||
|
|
||||||
// perform constant and interval tests on index value
|
// perform constant and interval tests on index value
|
||||||
bool AccessIndexed::compute_needs_range_check() {
|
bool AccessIndexed::compute_needs_range_check() {
|
||||||
|
|
||||||
if (length()) {
|
if (length()) {
|
||||||
|
|
||||||
Constant* clength = length()->as_Constant();
|
Constant* clength = length()->as_Constant();
|
||||||
Constant* cindex = index()->as_Constant();
|
Constant* cindex = index()->as_Constant();
|
||||||
if (clength && cindex) {
|
if (clength && cindex) {
|
||||||
@ -157,34 +163,8 @@ bool AccessIndexed::compute_needs_range_check() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ciType* Local::exact_type() const {
|
|
||||||
ciType* type = declared_type();
|
|
||||||
|
|
||||||
// for primitive arrays, the declared type is the exact type
|
|
||||||
if (type->is_type_array_klass()) {
|
|
||||||
return type;
|
|
||||||
} else if (type->is_instance_klass()) {
|
|
||||||
ciInstanceKlass* ik = (ciInstanceKlass*)type;
|
|
||||||
if (ik->is_loaded() && ik->is_final() && !ik->is_interface()) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
} else if (type->is_obj_array_klass()) {
|
|
||||||
ciObjArrayKlass* oak = (ciObjArrayKlass*)type;
|
|
||||||
ciType* base = oak->base_element_type();
|
|
||||||
if (base->is_instance_klass()) {
|
|
||||||
ciInstanceKlass* ik = base->as_instance_klass();
|
|
||||||
if (ik->is_loaded() && ik->is_final()) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
} else if (base->is_primitive_type()) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ciType* Constant::exact_type() const {
|
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 type()->as_ObjectType()->exact_type();
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -192,19 +172,18 @@ ciType* Constant::exact_type() const {
|
|||||||
|
|
||||||
ciType* LoadIndexed::exact_type() const {
|
ciType* LoadIndexed::exact_type() const {
|
||||||
ciType* array_type = array()->exact_type();
|
ciType* array_type = array()->exact_type();
|
||||||
if (array_type == NULL) {
|
if (array_type != NULL) {
|
||||||
return NULL;
|
assert(array_type->is_array_klass(), "what else?");
|
||||||
}
|
ciArrayKlass* ak = (ciArrayKlass*)array_type;
|
||||||
assert(array_type->is_array_klass(), "what else?");
|
|
||||||
ciArrayKlass* ak = (ciArrayKlass*)array_type;
|
|
||||||
|
|
||||||
if (ak->element_type()->is_instance_klass()) {
|
if (ak->element_type()->is_instance_klass()) {
|
||||||
ciInstanceKlass* ik = (ciInstanceKlass*)ak->element_type();
|
ciInstanceKlass* ik = (ciInstanceKlass*)ak->element_type();
|
||||||
if (ik->is_loaded() && ik->is_final()) {
|
if (ik->is_loaded() && ik->is_final()) {
|
||||||
return ik;
|
return ik;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return Instruction::exact_type();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -224,22 +203,6 @@ ciType* LoadField::declared_type() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ciType* LoadField::exact_type() const {
|
|
||||||
ciType* type = declared_type();
|
|
||||||
// for primitive arrays, the declared type is the exact type
|
|
||||||
if (type->is_type_array_klass()) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
if (type->is_instance_klass()) {
|
|
||||||
ciInstanceKlass* ik = (ciInstanceKlass*)type;
|
|
||||||
if (ik->is_loaded() && ik->is_final()) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ciType* NewTypeArray::exact_type() const {
|
ciType* NewTypeArray::exact_type() const {
|
||||||
return ciTypeArrayKlass::make(elt_type());
|
return ciTypeArrayKlass::make(elt_type());
|
||||||
}
|
}
|
||||||
@ -264,16 +227,6 @@ ciType* CheckCast::declared_type() const {
|
|||||||
return klass();
|
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
|
// Implementation of ArithmeticOp
|
||||||
|
|
||||||
bool ArithmeticOp::is_commutative() const {
|
bool ArithmeticOp::is_commutative() const {
|
||||||
|
@ -322,6 +322,36 @@ class Instruction: public CompilationResourceObj {
|
|||||||
_type = type;
|
_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:
|
public:
|
||||||
void* operator new(size_t size) throw() {
|
void* operator new(size_t size) throw() {
|
||||||
Compilation* c = Compilation::current();
|
Compilation* c = Compilation::current();
|
||||||
@ -566,7 +596,7 @@ class Instruction: public CompilationResourceObj {
|
|||||||
virtual void other_values_do(ValueVisitor* f) { /* usually no other - override on demand */ }
|
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); }
|
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; }
|
virtual ciType* declared_type() const { return NULL; }
|
||||||
|
|
||||||
// hashing
|
// hashing
|
||||||
@ -689,7 +719,6 @@ LEAF(Local, Instruction)
|
|||||||
int java_index() const { return _java_index; }
|
int java_index() const { return _java_index; }
|
||||||
|
|
||||||
virtual ciType* declared_type() const { return _declared_type; }
|
virtual ciType* declared_type() const { return _declared_type; }
|
||||||
virtual ciType* exact_type() const;
|
|
||||||
|
|
||||||
// generic
|
// generic
|
||||||
virtual void input_values_do(ValueVisitor* f) { /* no values */ }
|
virtual void input_values_do(ValueVisitor* f) { /* no values */ }
|
||||||
@ -806,7 +835,6 @@ LEAF(LoadField, AccessField)
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
ciType* declared_type() const;
|
ciType* declared_type() const;
|
||||||
ciType* exact_type() const;
|
|
||||||
|
|
||||||
// generic
|
// generic
|
||||||
HASHING2(LoadField, !needs_patching() && !field()->is_volatile(), obj()->subst(), offset()) // cannot be eliminated if needs patching or if volatile
|
HASHING2(LoadField, !needs_patching() && !field()->is_volatile(), obj()->subst(), offset()) // cannot be eliminated if needs patching or if volatile
|
||||||
@ -1299,6 +1327,7 @@ BASE(NewArray, StateSplit)
|
|||||||
|
|
||||||
virtual bool needs_exception_state() const { return false; }
|
virtual bool needs_exception_state() const { return false; }
|
||||||
|
|
||||||
|
ciType* exact_type() const { return NULL; }
|
||||||
ciType* declared_type() const;
|
ciType* declared_type() const;
|
||||||
|
|
||||||
// generic
|
// generic
|
||||||
@ -1422,7 +1451,6 @@ LEAF(CheckCast, TypeCheck)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ciType* declared_type() const;
|
ciType* declared_type() const;
|
||||||
ciType* exact_type() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1490,7 +1518,7 @@ LEAF(Intrinsic, StateSplit)
|
|||||||
vmIntrinsics::ID _id;
|
vmIntrinsics::ID _id;
|
||||||
Values* _args;
|
Values* _args;
|
||||||
Value _recv;
|
Value _recv;
|
||||||
int _nonnull_state; // mask identifying which args are nonnull
|
ArgsNonNullState _nonnull_state;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// preserves_state can be set to true for Intrinsics
|
// preserves_state can be set to true for Intrinsics
|
||||||
@ -1511,7 +1539,6 @@ LEAF(Intrinsic, StateSplit)
|
|||||||
, _id(id)
|
, _id(id)
|
||||||
, _args(args)
|
, _args(args)
|
||||||
, _recv(NULL)
|
, _recv(NULL)
|
||||||
, _nonnull_state(AllBits)
|
|
||||||
{
|
{
|
||||||
assert(args != NULL, "args must exist");
|
assert(args != NULL, "args must exist");
|
||||||
ASSERT_VALUES
|
ASSERT_VALUES
|
||||||
@ -1537,21 +1564,12 @@ LEAF(Intrinsic, StateSplit)
|
|||||||
Value receiver() const { assert(has_receiver(), "must have receiver"); return _recv; }
|
Value receiver() const { assert(has_receiver(), "must have receiver"); return _recv; }
|
||||||
bool preserves_state() const { return check_flag(PreservesStateFlag); }
|
bool preserves_state() const { return check_flag(PreservesStateFlag); }
|
||||||
|
|
||||||
bool arg_needs_null_check(int i) {
|
bool arg_needs_null_check(int i) const {
|
||||||
if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
|
return _nonnull_state.arg_needs_null_check(i);
|
||||||
return is_set_nth_bit(_nonnull_state, i);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_arg_needs_null_check(int i, bool check) {
|
void set_arg_needs_null_check(int i, bool check) {
|
||||||
if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
|
_nonnull_state.set_arg_needs_null_check(i, check);
|
||||||
if (check) {
|
|
||||||
_nonnull_state |= nth_bit(i);
|
|
||||||
} else {
|
|
||||||
_nonnull_state &= ~(nth_bit(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generic
|
// generic
|
||||||
@ -2450,35 +2468,56 @@ LEAF(UnsafePrefetchWrite, UnsafePrefetch)
|
|||||||
|
|
||||||
LEAF(ProfileCall, Instruction)
|
LEAF(ProfileCall, Instruction)
|
||||||
private:
|
private:
|
||||||
ciMethod* _method;
|
ciMethod* _method;
|
||||||
int _bci_of_invoke;
|
int _bci_of_invoke;
|
||||||
ciMethod* _callee; // the method that is called at the given bci
|
ciMethod* _callee; // the method that is called at the given bci
|
||||||
Value _recv;
|
Value _recv;
|
||||||
ciKlass* _known_holder;
|
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:
|
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)
|
: Instruction(voidType)
|
||||||
, _method(method)
|
, _method(method)
|
||||||
, _bci_of_invoke(bci)
|
, _bci_of_invoke(bci)
|
||||||
, _callee(callee)
|
, _callee(callee)
|
||||||
, _recv(recv)
|
, _recv(recv)
|
||||||
, _known_holder(known_holder)
|
, _known_holder(known_holder)
|
||||||
|
, _obj_args(obj_args)
|
||||||
|
, _inlined(inlined)
|
||||||
{
|
{
|
||||||
// The ProfileCall has side-effects and must occur precisely where located
|
// The ProfileCall has side-effects and must occur precisely where located
|
||||||
pin();
|
pin();
|
||||||
}
|
}
|
||||||
|
|
||||||
ciMethod* method() { return _method; }
|
ciMethod* method() const { return _method; }
|
||||||
int bci_of_invoke() { return _bci_of_invoke; }
|
int bci_of_invoke() const { return _bci_of_invoke; }
|
||||||
ciMethod* callee() { return _callee; }
|
ciMethod* callee() const { return _callee; }
|
||||||
Value recv() { return _recv; }
|
Value recv() const { return _recv; }
|
||||||
ciKlass* known_holder() { return _known_holder; }
|
ciKlass* known_holder() const { return _known_holder; }
|
||||||
|
int nb_profiled_args() const { return _obj_args == NULL ? 0 : _obj_args->length(); }
|
||||||
|
Value profiled_arg_at(int i) const { return _obj_args->at(i); }
|
||||||
|
bool arg_needs_null_check(int i) const {
|
||||||
|
return _nonnull_state.arg_needs_null_check(i);
|
||||||
|
}
|
||||||
|
bool inlined() const { return _inlined; }
|
||||||
|
|
||||||
virtual void input_values_do(ValueVisitor* f) { if (_recv != NULL) f->visit(&_recv); }
|
void set_arg_needs_null_check(int i, bool check) {
|
||||||
|
_nonnull_state.set_arg_needs_null_check(i, check);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void input_values_do(ValueVisitor* f) {
|
||||||
|
if (_recv != NULL) {
|
||||||
|
f->visit(&_recv);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < nb_profiled_args(); i++) {
|
||||||
|
f->visit(_obj_args->adr_at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Call some C runtime function that doesn't safepoint,
|
// Call some C runtime function that doesn't safepoint,
|
||||||
// optionally passing the current thread as the first argument.
|
// optionally passing the current thread as the first argument.
|
||||||
LEAF(RuntimeCall, Instruction)
|
LEAF(RuntimeCall, Instruction)
|
||||||
|
@ -892,6 +892,14 @@ void InstructionPrinter::do_ProfileCall(ProfileCall* x) {
|
|||||||
if (x->known_holder() != NULL) {
|
if (x->known_holder() != NULL) {
|
||||||
output()->print(", ");
|
output()->print(", ");
|
||||||
print_klass(x->known_holder());
|
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(')');
|
output()->put(')');
|
||||||
}
|
}
|
||||||
|
@ -1001,6 +1001,17 @@ void LIR_OpVisitState::visit(LIR_Op* op) {
|
|||||||
assert(opProfileCall->_tmp1->is_valid(), "used"); do_temp(opProfileCall->_tmp1);
|
assert(opProfileCall->_tmp1->is_valid(), "used"); do_temp(opProfileCall->_tmp1);
|
||||||
break;
|
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:
|
default:
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
@ -1151,6 +1162,10 @@ void LIR_OpProfileCall::emit_code(LIR_Assembler* masm) {
|
|||||||
masm->emit_profile_call(this);
|
masm->emit_profile_call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LIR_OpProfileType::emit_code(LIR_Assembler* masm) {
|
||||||
|
masm->emit_profile_type(this);
|
||||||
|
}
|
||||||
|
|
||||||
// LIR_List
|
// LIR_List
|
||||||
LIR_List::LIR_List(Compilation* compilation, BlockBegin* block)
|
LIR_List::LIR_List(Compilation* compilation, BlockBegin* block)
|
||||||
: _operations(8)
|
: _operations(8)
|
||||||
@ -1803,6 +1818,8 @@ const char * LIR_Op::name() const {
|
|||||||
case lir_cas_int: s = "cas_int"; break;
|
case lir_cas_int: s = "cas_int"; break;
|
||||||
// LIR_OpProfileCall
|
// LIR_OpProfileCall
|
||||||
case lir_profile_call: s = "profile_call"; break;
|
case lir_profile_call: s = "profile_call"; break;
|
||||||
|
// LIR_OpProfileType
|
||||||
|
case lir_profile_type: s = "profile_type"; break;
|
||||||
// LIR_OpAssert
|
// LIR_OpAssert
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
case lir_assert: s = "assert"; break;
|
case lir_assert: s = "assert"; break;
|
||||||
@ -2086,6 +2103,15 @@ void LIR_OpProfileCall::print_instr(outputStream* out) const {
|
|||||||
tmp1()->print(out); out->print(" ");
|
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
|
#endif // PRODUCT
|
||||||
|
|
||||||
// Implementation of LIR_InsertionBuffer
|
// Implementation of LIR_InsertionBuffer
|
||||||
|
@ -882,6 +882,7 @@ class LIR_OpLock;
|
|||||||
class LIR_OpTypeCheck;
|
class LIR_OpTypeCheck;
|
||||||
class LIR_OpCompareAndSwap;
|
class LIR_OpCompareAndSwap;
|
||||||
class LIR_OpProfileCall;
|
class LIR_OpProfileCall;
|
||||||
|
class LIR_OpProfileType;
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
class LIR_OpAssert;
|
class LIR_OpAssert;
|
||||||
#endif
|
#endif
|
||||||
@ -1005,6 +1006,7 @@ enum LIR_Code {
|
|||||||
, end_opCompareAndSwap
|
, end_opCompareAndSwap
|
||||||
, begin_opMDOProfile
|
, begin_opMDOProfile
|
||||||
, lir_profile_call
|
, lir_profile_call
|
||||||
|
, lir_profile_type
|
||||||
, end_opMDOProfile
|
, end_opMDOProfile
|
||||||
, begin_opAssert
|
, begin_opAssert
|
||||||
, lir_assert
|
, lir_assert
|
||||||
@ -1145,6 +1147,7 @@ class LIR_Op: public CompilationResourceObj {
|
|||||||
virtual LIR_OpTypeCheck* as_OpTypeCheck() { return NULL; }
|
virtual LIR_OpTypeCheck* as_OpTypeCheck() { return NULL; }
|
||||||
virtual LIR_OpCompareAndSwap* as_OpCompareAndSwap() { return NULL; }
|
virtual LIR_OpCompareAndSwap* as_OpCompareAndSwap() { return NULL; }
|
||||||
virtual LIR_OpProfileCall* as_OpProfileCall() { return NULL; }
|
virtual LIR_OpProfileCall* as_OpProfileCall() { return NULL; }
|
||||||
|
virtual LIR_OpProfileType* as_OpProfileType() { return NULL; }
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
virtual LIR_OpAssert* as_OpAssert() { return NULL; }
|
virtual LIR_OpAssert* as_OpAssert() { return NULL; }
|
||||||
#endif
|
#endif
|
||||||
@ -1925,8 +1928,8 @@ class LIR_OpProfileCall : public LIR_Op {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Destroys recv
|
// 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_OpProfileCall(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_Op(lir_profile_call, LIR_OprFact::illegalOpr, NULL) // no result, no info
|
||||||
, _profiled_method(profiled_method)
|
, _profiled_method(profiled_method)
|
||||||
, _profiled_bci(profiled_bci)
|
, _profiled_bci(profiled_bci)
|
||||||
, _profiled_callee(profiled_callee)
|
, _profiled_callee(profiled_callee)
|
||||||
@ -1948,6 +1951,45 @@ class LIR_OpProfileCall : public LIR_Op {
|
|||||||
virtual void print_instr(outputStream* out) const PRODUCT_RETURN;
|
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;
|
class LIR_InsertionBuffer;
|
||||||
|
|
||||||
//--------------------------------LIR_List---------------------------------------------------
|
//--------------------------------LIR_List---------------------------------------------------
|
||||||
@ -2247,7 +2289,10 @@ class LIR_List: public CompilationResourceObj {
|
|||||||
ciMethod* profiled_method, int profiled_bci);
|
ciMethod* profiled_method, int profiled_bci);
|
||||||
// MethodData* profiling
|
// MethodData* profiling
|
||||||
void profile_call(ciMethod* method, int bci, ciMethod* callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* cha_klass) {
|
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)); }
|
void xadd(LIR_Opr src, LIR_Opr add, LIR_Opr res, LIR_Opr tmp) { append(new LIR_Op2(lir_xadd, src, add, res, tmp)); }
|
||||||
|
@ -208,6 +208,7 @@ class LIR_Assembler: public CompilationResourceObj {
|
|||||||
void emit_call(LIR_OpJavaCall* op);
|
void emit_call(LIR_OpJavaCall* op);
|
||||||
void emit_rtcall(LIR_OpRTCall* op);
|
void emit_rtcall(LIR_OpRTCall* op);
|
||||||
void emit_profile_call(LIR_OpProfileCall* op);
|
void emit_profile_call(LIR_OpProfileCall* op);
|
||||||
|
void emit_profile_type(LIR_OpProfileType* op);
|
||||||
void emit_delay(LIR_OpDelay* 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);
|
void arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, CodeEmitInfo* info, bool pop_fpu_stack);
|
||||||
|
@ -2571,6 +2571,78 @@ void LIRGenerator::do_Goto(Goto* x) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ciKlass* LIRGenerator::profile_arg_type(ciMethodData* md, int md_base_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_k) {
|
||||||
|
ciKlass* result = NULL;
|
||||||
|
bool do_null = !not_null && !TypeEntries::was_null_seen(profiled_k);
|
||||||
|
bool do_update = !TypeEntries::is_type_unknown(profiled_k);
|
||||||
|
// known not to be null or null bit already set and already set to
|
||||||
|
// unknown: nothing we can do to improve profiling
|
||||||
|
if (!do_null && !do_update) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ciKlass* exact_klass = NULL;
|
||||||
|
Compilation* comp = Compilation::current();
|
||||||
|
if (do_update) {
|
||||||
|
// try to find exact type, using CHA if possible, so that loading
|
||||||
|
// the klass from the object can be avoided
|
||||||
|
ciType* type = arg->exact_type();
|
||||||
|
if (type == NULL) {
|
||||||
|
type = arg->declared_type();
|
||||||
|
type = comp->cha_exact_type(type);
|
||||||
|
}
|
||||||
|
assert(type == NULL || type->is_klass(), "type should be class");
|
||||||
|
exact_klass = (type != NULL && type->is_loaded()) ? (ciKlass*)type : NULL;
|
||||||
|
|
||||||
|
do_update = exact_klass == NULL || ciTypeEntries::valid_ciklass(profiled_k) != exact_klass;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!do_null && !do_update) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ciKlass* exact_signature_k = NULL;
|
||||||
|
if (do_update) {
|
||||||
|
// Is the type from the signature exact (the only one possible)?
|
||||||
|
exact_signature_k = signature_k->exact_klass();
|
||||||
|
if (exact_signature_k == NULL) {
|
||||||
|
exact_signature_k = comp->cha_exact_type(signature_k);
|
||||||
|
} else {
|
||||||
|
result = exact_signature_k;
|
||||||
|
do_update = false;
|
||||||
|
// Known statically. No need to emit any code: prevent
|
||||||
|
// LIR_Assembler::emit_profile_type() from emitting useless code
|
||||||
|
profiled_k = ciTypeEntries::with_status(result, profiled_k);
|
||||||
|
}
|
||||||
|
if (exact_signature_k != NULL && exact_klass != exact_signature_k) {
|
||||||
|
assert(exact_klass == NULL, "arg and signature disagree?");
|
||||||
|
// sometimes the type of the signature is better than the best type
|
||||||
|
// the compiler has
|
||||||
|
exact_klass = exact_signature_k;
|
||||||
|
do_update = exact_klass == NULL || ciTypeEntries::valid_ciklass(profiled_k) != exact_klass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!do_null && !do_update) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mdp == LIR_OprFact::illegalOpr) {
|
||||||
|
mdp = new_register(T_METADATA);
|
||||||
|
__ metadata2reg(md->constant_encoding(), mdp);
|
||||||
|
if (md_base_offset != 0) {
|
||||||
|
LIR_Address* base_type_address = new LIR_Address(mdp, md_base_offset, T_ADDRESS);
|
||||||
|
mdp = new_pointer_register();
|
||||||
|
__ leal(LIR_OprFact::address(base_type_address), mdp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LIRItem value(arg, this);
|
||||||
|
value.load_item();
|
||||||
|
__ profile_type(new LIR_Address(mdp, md_offset, T_METADATA),
|
||||||
|
value.result(), exact_klass, profiled_k, new_pointer_register(), not_null, exact_signature_k != NULL);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void LIRGenerator::do_Base(Base* x) {
|
void LIRGenerator::do_Base(Base* x) {
|
||||||
__ std_entry(LIR_OprFact::illegalOpr);
|
__ std_entry(LIR_OprFact::illegalOpr);
|
||||||
// Emit moves from physical registers / stack slots to virtual registers
|
// Emit moves from physical registers / stack slots to virtual registers
|
||||||
@ -3004,12 +3076,52 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LIRGenerator::profile_arguments(ProfileCall* x) {
|
||||||
|
if (MethodData::profile_arguments()) {
|
||||||
|
int bci = x->bci_of_invoke();
|
||||||
|
ciMethodData* md = x->method()->method_data_or_null();
|
||||||
|
ciProfileData* data = md->bci_to_data(bci);
|
||||||
|
if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) {
|
||||||
|
ByteSize extra = data->is_CallTypeData() ? CallTypeData::args_data_offset() : VirtualCallTypeData::args_data_offset();
|
||||||
|
int base_offset = md->byte_offset_of_slot(data, extra);
|
||||||
|
LIR_Opr mdp = LIR_OprFact::illegalOpr;
|
||||||
|
ciTypeStackSlotEntries* args = data->is_CallTypeData() ? ((ciCallTypeData*)data)->args() : ((ciVirtualCallTypeData*)data)->args();
|
||||||
|
|
||||||
|
Bytecodes::Code bc = x->method()->java_code_at_bci(bci);
|
||||||
|
int start = 0;
|
||||||
|
int stop = args->number_of_arguments();
|
||||||
|
if (x->nb_profiled_args() < stop) {
|
||||||
|
// if called through method handle invoke, some arguments may have been popped
|
||||||
|
stop = x->nb_profiled_args();
|
||||||
|
}
|
||||||
|
ciSignature* sig = x->callee()->signature();
|
||||||
|
// method handle call to virtual method
|
||||||
|
bool has_receiver = x->inlined() && !x->callee()->is_static() && !Bytecodes::has_receiver(bc);
|
||||||
|
ciSignatureStream sig_stream(sig, has_receiver ? x->callee()->holder() : NULL);
|
||||||
|
for (int i = 0; i < stop; i++) {
|
||||||
|
int off = in_bytes(TypeStackSlotEntries::type_offset(i)) - in_bytes(TypeStackSlotEntries::args_data_offset());
|
||||||
|
ciKlass* exact = profile_arg_type(md, base_offset, off,
|
||||||
|
args->type(i), x->profiled_arg_at(i+start), mdp,
|
||||||
|
!x->arg_needs_null_check(i+start), sig_stream.next_klass());
|
||||||
|
if (exact != NULL) {
|
||||||
|
md->set_argument_type(bci, i, exact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LIRGenerator::do_ProfileCall(ProfileCall* x) {
|
void LIRGenerator::do_ProfileCall(ProfileCall* x) {
|
||||||
// Need recv in a temporary register so it interferes with the other temporaries
|
// Need recv in a temporary register so it interferes with the other temporaries
|
||||||
LIR_Opr recv = LIR_OprFact::illegalOpr;
|
LIR_Opr recv = LIR_OprFact::illegalOpr;
|
||||||
LIR_Opr mdo = new_register(T_OBJECT);
|
LIR_Opr mdo = new_register(T_OBJECT);
|
||||||
// tmp is used to hold the counters on SPARC
|
// tmp is used to hold the counters on SPARC
|
||||||
LIR_Opr tmp = new_pointer_register();
|
LIR_Opr tmp = new_pointer_register();
|
||||||
|
|
||||||
|
if (x->nb_profiled_args() > 0) {
|
||||||
|
profile_arguments(x);
|
||||||
|
}
|
||||||
|
|
||||||
if (x->recv() != NULL) {
|
if (x->recv() != NULL) {
|
||||||
LIRItem value(x->recv(), this);
|
LIRItem value(x->recv(), this);
|
||||||
value.load_item();
|
value.load_item();
|
||||||
|
@ -434,6 +434,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
|
|||||||
void do_ThreadIDIntrinsic(Intrinsic* x);
|
void do_ThreadIDIntrinsic(Intrinsic* x);
|
||||||
void do_ClassIDIntrinsic(Intrinsic* x);
|
void do_ClassIDIntrinsic(Intrinsic* x);
|
||||||
#endif
|
#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:
|
public:
|
||||||
Compilation* compilation() const { return _compilation; }
|
Compilation* compilation() const { return _compilation; }
|
||||||
|
@ -657,6 +657,7 @@ class NullCheckEliminator: public ValueVisitor {
|
|||||||
void handle_Intrinsic (Intrinsic* x);
|
void handle_Intrinsic (Intrinsic* x);
|
||||||
void handle_ExceptionObject (ExceptionObject* x);
|
void handle_ExceptionObject (ExceptionObject* x);
|
||||||
void handle_Phi (Phi* x);
|
void handle_Phi (Phi* x);
|
||||||
|
void handle_ProfileCall (ProfileCall* x);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -715,7 +716,8 @@ void NullCheckVisitor::do_UnsafePutObject(UnsafePutObject* x) {}
|
|||||||
void NullCheckVisitor::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {}
|
void NullCheckVisitor::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {}
|
||||||
void NullCheckVisitor::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {}
|
void NullCheckVisitor::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {}
|
||||||
void NullCheckVisitor::do_UnsafePrefetchWrite(UnsafePrefetchWrite* 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_ProfileInvoke (ProfileInvoke* x) {}
|
||||||
void NullCheckVisitor::do_RuntimeCall (RuntimeCall* x) {}
|
void NullCheckVisitor::do_RuntimeCall (RuntimeCall* x) {}
|
||||||
void NullCheckVisitor::do_MemBar (MemBar* x) {}
|
void NullCheckVisitor::do_MemBar (MemBar* x) {}
|
||||||
@ -1134,6 +1136,11 @@ void NullCheckEliminator::handle_Phi(Phi* x) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NullCheckEliminator::handle_ProfileCall(ProfileCall* x) {
|
||||||
|
for (int i = 0; i < x->nb_profiled_args(); i++) {
|
||||||
|
x->set_arg_needs_null_check(i, !set_contains(x->profiled_arg_at(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Optimizer::eliminate_null_checks() {
|
void Optimizer::eliminate_null_checks() {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
|
@ -162,7 +162,7 @@ public:
|
|||||||
void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ };
|
void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ };
|
||||||
void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ };
|
void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ };
|
||||||
void do_ProfileCall (ProfileCall* 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_RuntimeCall (RuntimeCall* x) { /* nothing to do */ };
|
||||||
void do_MemBar (MemBar* x) { /* nothing to do */ };
|
void do_MemBar (MemBar* x) { /* nothing to do */ };
|
||||||
void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ };
|
void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ };
|
||||||
|
@ -102,6 +102,7 @@ friend class ciMethodData; \
|
|||||||
friend class ciMethodHandle; \
|
friend class ciMethodHandle; \
|
||||||
friend class ciMethodType; \
|
friend class ciMethodType; \
|
||||||
friend class ciReceiverTypeData; \
|
friend class ciReceiverTypeData; \
|
||||||
|
friend class ciTypeEntries; \
|
||||||
friend class ciSymbol; \
|
friend class ciSymbol; \
|
||||||
friend class ciArray; \
|
friend class ciArray; \
|
||||||
friend class ciObjArray; \
|
friend class ciObjArray; \
|
||||||
|
@ -235,6 +235,13 @@ public:
|
|||||||
bool is_instance_klass() const { return true; }
|
bool is_instance_klass() const { return true; }
|
||||||
bool is_java_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.
|
// Dump the current state of this klass for compilation replay.
|
||||||
virtual void dump_replay_data(outputStream* out);
|
virtual void dump_replay_data(outputStream* out);
|
||||||
};
|
};
|
||||||
|
@ -41,6 +41,7 @@ class ciKlass : public ciType {
|
|||||||
friend class ciEnv;
|
friend class ciEnv;
|
||||||
friend class ciField;
|
friend class ciField;
|
||||||
friend class ciMethod;
|
friend class ciMethod;
|
||||||
|
friend class ciMethodData;
|
||||||
friend class ciObjArrayKlass;
|
friend class ciObjArrayKlass;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -121,6 +122,8 @@ public:
|
|||||||
// What kind of ciObject is this?
|
// What kind of ciObject is this?
|
||||||
bool is_klass() const { return true; }
|
bool is_klass() const { return true; }
|
||||||
|
|
||||||
|
virtual ciKlass* exact_klass() = 0;
|
||||||
|
|
||||||
void print_name_on(outputStream* st);
|
void print_name_on(outputStream* st);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ void ciMethodData::load_data() {
|
|||||||
#endif
|
#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++) {
|
for (uint row = 0; row < row_limit(); row++) {
|
||||||
Klass* k = data->as_ReceiverTypeData()->receiver(row);
|
Klass* k = data->as_ReceiverTypeData()->receiver(row);
|
||||||
if (k != NULL) {
|
if (k != NULL) {
|
||||||
@ -136,6 +136,13 @@ void ciReceiverTypeData::translate_receiver_data_from(ProfileData* data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ciTypeStackSlotEntries::translate_type_data_from(const TypeStackSlotEntries* entries) {
|
||||||
|
for (int i = 0; i < number_of_arguments(); i++) {
|
||||||
|
intptr_t k = entries->type(i);
|
||||||
|
TypeStackSlotEntries::set_type(i, translate_klass(k));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get the data at an arbitrary (sort of) data index.
|
// Get the data at an arbitrary (sort of) data index.
|
||||||
ciProfileData* ciMethodData::data_at(int data_index) {
|
ciProfileData* ciMethodData::data_at(int data_index) {
|
||||||
if (out_of_bounds(data_index)) {
|
if (out_of_bounds(data_index)) {
|
||||||
@ -166,6 +173,10 @@ ciProfileData* ciMethodData::data_at(int data_index) {
|
|||||||
return new ciMultiBranchData(data_layout);
|
return new ciMultiBranchData(data_layout);
|
||||||
case DataLayout::arg_info_data_tag:
|
case DataLayout::arg_info_data_tag:
|
||||||
return new ciArgInfoData(data_layout);
|
return new ciArgInfoData(data_layout);
|
||||||
|
case DataLayout::call_type_data_tag:
|
||||||
|
return new ciCallTypeData(data_layout);
|
||||||
|
case DataLayout::virtual_call_type_data_tag:
|
||||||
|
return new ciVirtualCallTypeData(data_layout);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,6 +299,20 @@ void ciMethodData::set_would_profile(bool p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ciMethodData::set_argument_type(int bci, int i, ciKlass* k) {
|
||||||
|
VM_ENTRY_MARK;
|
||||||
|
MethodData* mdo = get_MethodData();
|
||||||
|
if (mdo != NULL) {
|
||||||
|
ProfileData* data = mdo->bci_to_data(bci);
|
||||||
|
if (data->is_CallTypeData()) {
|
||||||
|
data->as_CallTypeData()->set_argument_type(i, k->get_Klass());
|
||||||
|
} else {
|
||||||
|
assert(data->is_VirtualCallTypeData(), "no arguments!");
|
||||||
|
data->as_VirtualCallTypeData()->set_argument_type(i, k->get_Klass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ciMethodData::has_escape_info() {
|
bool ciMethodData::has_escape_info() {
|
||||||
return eflag_set(MethodData::estimated);
|
return eflag_set(MethodData::estimated);
|
||||||
}
|
}
|
||||||
@ -478,7 +503,36 @@ void ciMethodData::print_data_on(outputStream* st) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ciReceiverTypeData::print_receiver_data_on(outputStream* st) {
|
void ciTypeEntries::print_ciklass(outputStream* st, intptr_t k) {
|
||||||
|
if (TypeEntries::is_type_none(k)) {
|
||||||
|
st->print("none");
|
||||||
|
} else if (TypeEntries::is_type_unknown(k)) {
|
||||||
|
st->print("unknown");
|
||||||
|
} else {
|
||||||
|
valid_ciklass(k)->print_name_on(st);
|
||||||
|
}
|
||||||
|
if (TypeEntries::was_null_seen(k)) {
|
||||||
|
st->print(" (null seen)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ciTypeStackSlotEntries::print_data_on(outputStream* st) const {
|
||||||
|
_pd->tab(st, true);
|
||||||
|
st->print("argument types");
|
||||||
|
for (int i = 0; i < number_of_arguments(); i++) {
|
||||||
|
_pd->tab(st);
|
||||||
|
st->print("%d: stack (%u) ", i, stack_slot(i));
|
||||||
|
print_ciklass(st, type(i));
|
||||||
|
st->cr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ciCallTypeData::print_data_on(outputStream* st) const {
|
||||||
|
print_shared(st, "ciCallTypeData");
|
||||||
|
args()->print_data_on(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ciReceiverTypeData::print_receiver_data_on(outputStream* st) const {
|
||||||
uint row;
|
uint row;
|
||||||
int entries = 0;
|
int entries = 0;
|
||||||
for (row = 0; row < row_limit(); row++) {
|
for (row = 0; row < row_limit(); row++) {
|
||||||
@ -494,13 +548,19 @@ void ciReceiverTypeData::print_receiver_data_on(outputStream* st) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ciReceiverTypeData::print_data_on(outputStream* st) {
|
void ciReceiverTypeData::print_data_on(outputStream* st) const {
|
||||||
print_shared(st, "ciReceiverTypeData");
|
print_shared(st, "ciReceiverTypeData");
|
||||||
print_receiver_data_on(st);
|
print_receiver_data_on(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ciVirtualCallData::print_data_on(outputStream* st) {
|
void ciVirtualCallData::print_data_on(outputStream* st) const {
|
||||||
print_shared(st, "ciVirtualCallData");
|
print_shared(st, "ciVirtualCallData");
|
||||||
rtd_super()->print_receiver_data_on(st);
|
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
|
#endif
|
||||||
|
@ -41,6 +41,8 @@ class ciBranchData;
|
|||||||
class ciArrayData;
|
class ciArrayData;
|
||||||
class ciMultiBranchData;
|
class ciMultiBranchData;
|
||||||
class ciArgInfoData;
|
class ciArgInfoData;
|
||||||
|
class ciCallTypeData;
|
||||||
|
class ciVirtualCallTypeData;
|
||||||
|
|
||||||
typedef ProfileData ciProfileData;
|
typedef ProfileData ciProfileData;
|
||||||
|
|
||||||
@ -59,6 +61,68 @@ public:
|
|||||||
ciJumpData(DataLayout* layout) : JumpData(layout) {};
|
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 {
|
class ciReceiverTypeData : public ReceiverTypeData {
|
||||||
public:
|
public:
|
||||||
ciReceiverTypeData(DataLayout* layout) : ReceiverTypeData(layout) {};
|
ciReceiverTypeData(DataLayout* layout) : ReceiverTypeData(layout) {};
|
||||||
@ -69,7 +133,7 @@ public:
|
|||||||
(intptr_t) recv);
|
(intptr_t) recv);
|
||||||
}
|
}
|
||||||
|
|
||||||
ciKlass* receiver(uint row) {
|
ciKlass* receiver(uint row) const {
|
||||||
assert((uint)row < row_limit(), "oob");
|
assert((uint)row < row_limit(), "oob");
|
||||||
ciKlass* recv = (ciKlass*)intptr_at(receiver0_offset + row * receiver_type_row_cell_count);
|
ciKlass* recv = (ciKlass*)intptr_at(receiver0_offset + row * receiver_type_row_cell_count);
|
||||||
assert(recv == NULL || recv->is_klass(), "wrong type");
|
assert(recv == NULL || recv->is_klass(), "wrong type");
|
||||||
@ -77,19 +141,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy & translate from oop based ReceiverTypeData
|
// Copy & translate from oop based ReceiverTypeData
|
||||||
virtual void translate_from(ProfileData* data) {
|
virtual void translate_from(const ProfileData* data) {
|
||||||
translate_receiver_data_from(data);
|
translate_receiver_data_from(data);
|
||||||
}
|
}
|
||||||
void translate_receiver_data_from(ProfileData* data);
|
void translate_receiver_data_from(const ProfileData* data);
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void print_data_on(outputStream* st);
|
void print_data_on(outputStream* st) const;
|
||||||
void print_receiver_data_on(outputStream* st);
|
void print_receiver_data_on(outputStream* st) const;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class ciVirtualCallData : public VirtualCallData {
|
class ciVirtualCallData : public VirtualCallData {
|
||||||
// Fake multiple inheritance... It's a ciReceiverTypeData also.
|
// Fake multiple inheritance... It's a ciReceiverTypeData also.
|
||||||
ciReceiverTypeData* rtd_super() { return (ciReceiverTypeData*) this; }
|
ciReceiverTypeData* rtd_super() const { return (ciReceiverTypeData*) this; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ciVirtualCallData(DataLayout* layout) : VirtualCallData(layout) {};
|
ciVirtualCallData(DataLayout* layout) : VirtualCallData(layout) {};
|
||||||
@ -103,11 +167,44 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy & translate from oop based VirtualCallData
|
// 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);
|
rtd_super()->translate_receiver_data_from(data);
|
||||||
}
|
}
|
||||||
#ifndef PRODUCT
|
#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
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -247,6 +344,9 @@ public:
|
|||||||
// Also set the numer of loops and blocks in the method.
|
// Also set the numer of loops and blocks in the method.
|
||||||
// Again, this is used to determine if a method is trivial.
|
// Again, this is used to determine if a method is trivial.
|
||||||
void set_compilation_stats(short loops, short blocks);
|
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();
|
void load_data();
|
||||||
|
|
||||||
|
@ -179,3 +179,16 @@ ciObjArrayKlass* ciObjArrayKlass::make_impl(ciKlass* element_klass) {
|
|||||||
ciObjArrayKlass* ciObjArrayKlass::make(ciKlass* element_klass) {
|
ciObjArrayKlass* ciObjArrayKlass::make(ciKlass* element_klass) {
|
||||||
GUARDED_VM_ENTRY(return make_impl(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;
|
||||||
|
}
|
||||||
|
@ -73,6 +73,8 @@ public:
|
|||||||
bool is_obj_array_klass() const { return true; }
|
bool is_obj_array_klass() const { return true; }
|
||||||
|
|
||||||
static ciObjArrayKlass* make(ciKlass* element_klass);
|
static ciObjArrayKlass* make(ciKlass* element_klass);
|
||||||
|
|
||||||
|
virtual ciKlass* exact_klass();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_CI_CIOBJARRAYKLASS_HPP
|
#endif // SHARE_VM_CI_CIOBJARRAYKLASS_HPP
|
||||||
|
@ -277,11 +277,14 @@ public:
|
|||||||
class ciSignatureStream : public StackObj {
|
class ciSignatureStream : public StackObj {
|
||||||
private:
|
private:
|
||||||
ciSignature* _sig;
|
ciSignature* _sig;
|
||||||
int _pos;
|
int _pos;
|
||||||
|
// holder is a method's holder
|
||||||
|
ciKlass* _holder;
|
||||||
public:
|
public:
|
||||||
ciSignatureStream(ciSignature* signature) {
|
ciSignatureStream(ciSignature* signature, ciKlass* holder = NULL) {
|
||||||
_sig = signature;
|
_sig = signature;
|
||||||
_pos = 0;
|
_pos = 0;
|
||||||
|
_holder = holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool at_return_type() { return _pos == _sig->count(); }
|
bool at_return_type() { return _pos == _sig->count(); }
|
||||||
@ -301,6 +304,23 @@ public:
|
|||||||
return _sig->type_at(_pos);
|
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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,6 +57,10 @@ public:
|
|||||||
|
|
||||||
// Make an array klass corresponding to the specified primitive type.
|
// Make an array klass corresponding to the specified primitive type.
|
||||||
static ciTypeArrayKlass* make(BasicType type);
|
static ciTypeArrayKlass* make(BasicType type);
|
||||||
|
|
||||||
|
virtual ciKlass* exact_klass() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_CI_CITYPEARRAYKLASS_HPP
|
#endif // SHARE_VM_CI_CITYPEARRAYKLASS_HPP
|
||||||
|
@ -56,6 +56,11 @@ void DataLayout::initialize(u1 tag, u2 bci, int cell_count) {
|
|||||||
if (needs_array_len(tag)) {
|
if (needs_array_len(tag)) {
|
||||||
set_cell_at(ArrayData::array_len_off_set, cell_count - 1); // -1 for header.
|
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) {
|
void DataLayout::clean_weak_klass_links(BoolObjectClosure* cl) {
|
||||||
@ -76,7 +81,7 @@ ProfileData::ProfileData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#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->print("bci: %d", bci());
|
||||||
st->fill_to(tab_width_one);
|
st->fill_to(tab_width_one);
|
||||||
st->print("%s", name);
|
st->print("%s", name);
|
||||||
@ -91,8 +96,8 @@ void ProfileData::print_shared(outputStream* st, const char* name) {
|
|||||||
st->print("flags(%d) ", flags);
|
st->print("flags(%d) ", flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileData::tab(outputStream* st) {
|
void ProfileData::tab(outputStream* st, bool first) const {
|
||||||
st->fill_to(tab_width_two);
|
st->fill_to(first ? tab_width_one : tab_width_two);
|
||||||
}
|
}
|
||||||
#endif // !PRODUCT
|
#endif // !PRODUCT
|
||||||
|
|
||||||
@ -104,7 +109,7 @@ void ProfileData::tab(outputStream* st) {
|
|||||||
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void BitData::print_data_on(outputStream* st) {
|
void BitData::print_data_on(outputStream* st) const {
|
||||||
print_shared(st, "BitData");
|
print_shared(st, "BitData");
|
||||||
}
|
}
|
||||||
#endif // !PRODUCT
|
#endif // !PRODUCT
|
||||||
@ -115,7 +120,7 @@ void BitData::print_data_on(outputStream* st) {
|
|||||||
// A CounterData corresponds to a simple counter.
|
// A CounterData corresponds to a simple counter.
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void CounterData::print_data_on(outputStream* st) {
|
void CounterData::print_data_on(outputStream* st) const {
|
||||||
print_shared(st, "CounterData");
|
print_shared(st, "CounterData");
|
||||||
st->print_cr("count(%u)", count());
|
st->print_cr("count(%u)", count());
|
||||||
}
|
}
|
||||||
@ -145,12 +150,130 @@ void JumpData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void JumpData::print_data_on(outputStream* st) {
|
void JumpData::print_data_on(outputStream* st) const {
|
||||||
print_shared(st, "JumpData");
|
print_shared(st, "JumpData");
|
||||||
st->print_cr("taken(%u) displacement(%d)", taken(), displacement());
|
st->print_cr("taken(%u) displacement(%d)", taken(), displacement());
|
||||||
}
|
}
|
||||||
#endif // !PRODUCT
|
#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
|
// ReceiverTypeData
|
||||||
//
|
//
|
||||||
@ -169,7 +292,7 @@ void ReceiverTypeData::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void ReceiverTypeData::print_receiver_data_on(outputStream* st) {
|
void ReceiverTypeData::print_receiver_data_on(outputStream* st) const {
|
||||||
uint row;
|
uint row;
|
||||||
int entries = 0;
|
int entries = 0;
|
||||||
for (row = 0; row < row_limit(); row++) {
|
for (row = 0; row < row_limit(); row++) {
|
||||||
@ -190,11 +313,11 @@ void ReceiverTypeData::print_receiver_data_on(outputStream* st) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void ReceiverTypeData::print_data_on(outputStream* st) {
|
void ReceiverTypeData::print_data_on(outputStream* st) const {
|
||||||
print_shared(st, "ReceiverTypeData");
|
print_shared(st, "ReceiverTypeData");
|
||||||
print_receiver_data_on(st);
|
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_shared(st, "VirtualCallData");
|
||||||
print_receiver_data_on(st);
|
print_receiver_data_on(st);
|
||||||
}
|
}
|
||||||
@ -246,7 +369,7 @@ address RetData::fixup_ret(int return_bci, MethodData* h_mdo) {
|
|||||||
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void RetData::print_data_on(outputStream* st) {
|
void RetData::print_data_on(outputStream* st) const {
|
||||||
print_shared(st, "RetData");
|
print_shared(st, "RetData");
|
||||||
uint row;
|
uint row;
|
||||||
int entries = 0;
|
int entries = 0;
|
||||||
@ -281,7 +404,7 @@ void BranchData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void BranchData::print_data_on(outputStream* st) {
|
void BranchData::print_data_on(outputStream* st) const {
|
||||||
print_shared(st, "BranchData");
|
print_shared(st, "BranchData");
|
||||||
st->print_cr("taken(%u) displacement(%d)",
|
st->print_cr("taken(%u) displacement(%d)",
|
||||||
taken(), displacement());
|
taken(), displacement());
|
||||||
@ -355,7 +478,7 @@ void MultiBranchData::post_initialize(BytecodeStream* stream,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void MultiBranchData::print_data_on(outputStream* st) {
|
void MultiBranchData::print_data_on(outputStream* st) const {
|
||||||
print_shared(st, "MultiBranchData");
|
print_shared(st, "MultiBranchData");
|
||||||
st->print_cr("default_count(%u) displacement(%d)",
|
st->print_cr("default_count(%u) displacement(%d)",
|
||||||
default_count(), default_displacement());
|
default_count(), default_displacement());
|
||||||
@ -369,7 +492,7 @@ void MultiBranchData::print_data_on(outputStream* st) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void ArgInfoData::print_data_on(outputStream* st) {
|
void ArgInfoData::print_data_on(outputStream* st) const {
|
||||||
print_shared(st, "ArgInfoData");
|
print_shared(st, "ArgInfoData");
|
||||||
int nargs = number_of_args();
|
int nargs = number_of_args();
|
||||||
for (int i = 0; i < nargs; i++) {
|
for (int i = 0; i < nargs; i++) {
|
||||||
@ -407,7 +530,11 @@ int MethodData::bytecode_cell_count(Bytecodes::Code code) {
|
|||||||
}
|
}
|
||||||
case Bytecodes::_invokespecial:
|
case Bytecodes::_invokespecial:
|
||||||
case Bytecodes::_invokestatic:
|
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:
|
||||||
case Bytecodes::_goto_w:
|
case Bytecodes::_goto_w:
|
||||||
case Bytecodes::_jsr:
|
case Bytecodes::_jsr:
|
||||||
@ -415,9 +542,17 @@ int MethodData::bytecode_cell_count(Bytecodes::Code code) {
|
|||||||
return JumpData::static_cell_count();
|
return JumpData::static_cell_count();
|
||||||
case Bytecodes::_invokevirtual:
|
case Bytecodes::_invokevirtual:
|
||||||
case Bytecodes::_invokeinterface:
|
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:
|
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:
|
case Bytecodes::_ret:
|
||||||
return RetData::static_cell_count();
|
return RetData::static_cell_count();
|
||||||
case Bytecodes::_ifeq:
|
case Bytecodes::_ifeq:
|
||||||
@ -453,7 +588,34 @@ int MethodData::compute_data_size(BytecodeStream* stream) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (cell_count == variable_cell_count) {
|
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
|
// Note: cell_count might be zero, meaning that there is just
|
||||||
// a DataLayout header, with no extra cells.
|
// a DataLayout header, with no extra cells.
|
||||||
@ -499,6 +661,7 @@ int MethodData::compute_allocation_size_in_bytes(methodHandle method) {
|
|||||||
// Add a cell to record information about modified arguments.
|
// Add a cell to record information about modified arguments.
|
||||||
int arg_size = method->size_of_parameters();
|
int arg_size = method->size_of_parameters();
|
||||||
object_size += DataLayout::compute_size_in_bytes(arg_size+1);
|
object_size += DataLayout::compute_size_in_bytes(arg_size+1);
|
||||||
|
|
||||||
return object_size;
|
return object_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,10 +697,20 @@ int MethodData::initialize_data(BytecodeStream* stream,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Bytecodes::_invokespecial:
|
case Bytecodes::_invokespecial:
|
||||||
case Bytecodes::_invokestatic:
|
case Bytecodes::_invokestatic: {
|
||||||
cell_count = CounterData::static_cell_count();
|
int counter_data_cell_count = CounterData::static_cell_count();
|
||||||
tag = DataLayout::counter_data_tag;
|
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;
|
break;
|
||||||
|
}
|
||||||
case Bytecodes::_goto:
|
case Bytecodes::_goto:
|
||||||
case Bytecodes::_goto_w:
|
case Bytecodes::_goto_w:
|
||||||
case Bytecodes::_jsr:
|
case Bytecodes::_jsr:
|
||||||
@ -546,15 +719,35 @@ int MethodData::initialize_data(BytecodeStream* stream,
|
|||||||
tag = DataLayout::jump_data_tag;
|
tag = DataLayout::jump_data_tag;
|
||||||
break;
|
break;
|
||||||
case Bytecodes::_invokevirtual:
|
case Bytecodes::_invokevirtual:
|
||||||
case Bytecodes::_invokeinterface:
|
case Bytecodes::_invokeinterface: {
|
||||||
cell_count = VirtualCallData::static_cell_count();
|
int virtual_call_data_cell_count = VirtualCallData::static_cell_count();
|
||||||
tag = DataLayout::virtual_call_data_tag;
|
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;
|
break;
|
||||||
case Bytecodes::_invokedynamic:
|
}
|
||||||
|
case Bytecodes::_invokedynamic: {
|
||||||
// %%% should make a type profile for any invokedynamic that takes a ref argument
|
// %%% should make a type profile for any invokedynamic that takes a ref argument
|
||||||
cell_count = CounterData::static_cell_count();
|
int counter_data_cell_count = CounterData::static_cell_count();
|
||||||
tag = DataLayout::counter_data_tag;
|
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;
|
break;
|
||||||
|
}
|
||||||
case Bytecodes::_ret:
|
case Bytecodes::_ret:
|
||||||
cell_count = RetData::static_cell_count();
|
cell_count = RetData::static_cell_count();
|
||||||
tag = DataLayout::ret_data_tag;
|
tag = DataLayout::ret_data_tag;
|
||||||
@ -585,6 +778,11 @@ int MethodData::initialize_data(BytecodeStream* stream,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert(tag == DataLayout::multi_branch_data_tag ||
|
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");
|
cell_count == bytecode_cell_count(c), "cell counts must agree");
|
||||||
if (cell_count >= 0) {
|
if (cell_count >= 0) {
|
||||||
assert(tag != DataLayout::no_tag, "bad tag");
|
assert(tag != DataLayout::no_tag, "bad tag");
|
||||||
@ -631,6 +829,10 @@ ProfileData* DataLayout::data_in() {
|
|||||||
return new MultiBranchData(this);
|
return new MultiBranchData(this);
|
||||||
case DataLayout::arg_info_data_tag:
|
case DataLayout::arg_info_data_tag:
|
||||||
return new ArgInfoData(this);
|
return new ArgInfoData(this);
|
||||||
|
case DataLayout::call_type_data_tag:
|
||||||
|
return new CallTypeData(this);
|
||||||
|
case DataLayout::virtual_call_type_data_tag:
|
||||||
|
return new VirtualCallTypeData(this);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -898,3 +1100,42 @@ void MethodData::verify_data_on(outputStream* st) {
|
|||||||
NEEDS_CLEANUP;
|
NEEDS_CLEANUP;
|
||||||
// not yet implemented.
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2648,6 +2648,13 @@ class CommandLineFlags {
|
|||||||
product(bool, AggressiveOpts, false, \
|
product(bool, AggressiveOpts, false, \
|
||||||
"Enable aggressive optimizations - see arguments.cpp") \
|
"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 */ \
|
/* statistics */ \
|
||||||
develop(bool, CountCompiledCalls, false, \
|
develop(bool, CountCompiledCalls, false, \
|
||||||
"counts method invocations") \
|
"counts method invocations") \
|
||||||
@ -3760,7 +3767,6 @@ class CommandLineFlags {
|
|||||||
product(bool, UseLockedTracing, false, \
|
product(bool, UseLockedTracing, false, \
|
||||||
"Use locked-tracing when doing event-based tracing")
|
"Use locked-tracing when doing event-based tracing")
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Macros for factoring of globals
|
* Macros for factoring of globals
|
||||||
*/
|
*/
|
||||||
|
@ -183,6 +183,7 @@ void print_method_profiling_data() {
|
|||||||
collected_profiled_methods->sort(&compare_methods);
|
collected_profiled_methods->sort(&compare_methods);
|
||||||
|
|
||||||
int count = collected_profiled_methods->length();
|
int count = collected_profiled_methods->length();
|
||||||
|
int total_size = 0;
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
for (int index = 0; index < count; index++) {
|
for (int index = 0; index < count; index++) {
|
||||||
Method* m = collected_profiled_methods->at(index);
|
Method* m = collected_profiled_methods->at(index);
|
||||||
@ -190,10 +191,13 @@ void print_method_profiling_data() {
|
|||||||
tty->print_cr("------------------------------------------------------------------------");
|
tty->print_cr("------------------------------------------------------------------------");
|
||||||
//m->print_name(tty);
|
//m->print_name(tty);
|
||||||
m->print_invocation_count();
|
m->print_invocation_count();
|
||||||
|
tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes());
|
||||||
tty->cr();
|
tty->cr();
|
||||||
m->print_codes();
|
m->print_codes();
|
||||||
|
total_size += m->method_data()->size_in_bytes();
|
||||||
}
|
}
|
||||||
tty->print_cr("------------------------------------------------------------------------");
|
tty->print_cr("------------------------------------------------------------------------");
|
||||||
|
tty->print_cr("Total MDO size: %d bytes", total_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,6 +378,16 @@ Symbol* SignatureStream::as_symbol_or_null() {
|
|||||||
return result;
|
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) {
|
bool SignatureVerifier::is_valid_signature(Symbol* sig) {
|
||||||
const char* signature = (const char*)sig->bytes();
|
const char* signature = (const char*)sig->bytes();
|
||||||
ssize_t len = sig->utf8_length();
|
ssize_t len = sig->utf8_length();
|
||||||
|
@ -401,6 +401,9 @@ class SignatureStream : public StackObj {
|
|||||||
|
|
||||||
// return same as_symbol except allocation of new symbols is avoided.
|
// return same as_symbol except allocation of new symbols is avoided.
|
||||||
Symbol* as_symbol_or_null();
|
Symbol* as_symbol_or_null();
|
||||||
|
|
||||||
|
// count the number of references in the signature
|
||||||
|
int reference_parameter_count();
|
||||||
};
|
};
|
||||||
|
|
||||||
class SignatureVerifier : public StackObj {
|
class SignatureVerifier : public StackObj {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user