This commit is contained in:
Igor Veresov 2013-10-13 13:22:24 -07:00
commit db9a439624
90 changed files with 2972 additions and 635 deletions

View File

@ -3100,6 +3100,10 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
}
}
void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
fatal("Type profiling not implemented on this platform");
}
void LIR_Assembler::align_backward_branch_target() {
__ align(OptoLoopAlignment);
}

View File

@ -1076,6 +1076,25 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) {
__ verify_not_null_oop(Oexception);
#ifdef ASSERT
// check that fields in JavaThread for exception oop and issuing pc are
// empty before writing to them
Label oop_empty;
Register scratch = I7; // We can use I7 here because it's overwritten later anyway.
__ ld_ptr(Address(G2_thread, JavaThread::exception_oop_offset()), scratch);
__ br_null(scratch, false, Assembler::pt, oop_empty);
__ delayed()->nop();
__ stop("exception oop already set");
__ bind(oop_empty);
Label pc_empty;
__ ld_ptr(Address(G2_thread, JavaThread::exception_pc_offset()), scratch);
__ br_null(scratch, false, Assembler::pt, pc_empty);
__ delayed()->nop();
__ stop("exception pc already set");
__ bind(pc_empty);
#endif
// save the exception and issuing pc in the thread
__ st_ptr(Oexception, G2_thread, in_bytes(JavaThread::exception_oop_offset()));
__ st_ptr(Oissuing_pc, G2_thread, in_bytes(JavaThread::exception_pc_offset()));

View File

@ -76,6 +76,8 @@ define_pd_global(bool, UseMembar, false);
// GC Ergo Flags
define_pd_global(uintx, CMSYoungGenPerWorker, 16*M); // default max size of CMS young gen, per GC worker thread
define_pd_global(uintx, TypeProfileLevel, 0);
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
\
product(intx, UseVIS, 99, \

View File

@ -3632,6 +3632,161 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
}
}
void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
Register obj = op->obj()->as_register();
Register tmp = op->tmp()->as_pointer_register();
Address mdo_addr = as_Address(op->mdp()->as_address_ptr());
ciKlass* exact_klass = op->exact_klass();
intptr_t current_klass = op->current_klass();
bool not_null = op->not_null();
bool no_conflict = op->no_conflict();
Label update, next, none;
bool do_null = !not_null;
bool exact_klass_set = exact_klass != NULL && ciTypeEntries::valid_ciklass(current_klass) == exact_klass;
bool do_update = !TypeEntries::is_type_unknown(current_klass) && !exact_klass_set;
assert(do_null || do_update, "why are we here?");
assert(!TypeEntries::was_null_seen(current_klass) || do_update, "why are we here?");
__ verify_oop(obj);
if (tmp != obj) {
__ mov(tmp, obj);
}
if (do_null) {
__ testptr(tmp, tmp);
__ jccb(Assembler::notZero, update);
if (!TypeEntries::was_null_seen(current_klass)) {
__ orptr(mdo_addr, TypeEntries::null_seen);
}
if (do_update) {
#ifndef ASSERT
__ jmpb(next);
}
#else
__ jmp(next);
}
} else {
__ testptr(tmp, tmp);
__ jccb(Assembler::notZero, update);
__ stop("unexpect null obj");
#endif
}
__ bind(update);
if (do_update) {
#ifdef ASSERT
if (exact_klass != NULL) {
Label ok;
__ load_klass(tmp, tmp);
__ push(tmp);
__ mov_metadata(tmp, exact_klass->constant_encoding());
__ cmpptr(tmp, Address(rsp, 0));
__ jccb(Assembler::equal, ok);
__ stop("exact klass and actual klass differ");
__ bind(ok);
__ pop(tmp);
}
#endif
if (!no_conflict) {
if (exact_klass == NULL || TypeEntries::is_type_none(current_klass)) {
if (exact_klass != NULL) {
__ mov_metadata(tmp, exact_klass->constant_encoding());
} else {
__ load_klass(tmp, tmp);
}
__ xorptr(tmp, mdo_addr);
__ testptr(tmp, TypeEntries::type_klass_mask);
// klass seen before, nothing to do. The unknown bit may have been
// set already but no need to check.
__ jccb(Assembler::zero, next);
__ testptr(tmp, TypeEntries::type_unknown);
__ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
if (TypeEntries::is_type_none(current_klass)) {
__ cmpptr(mdo_addr, 0);
__ jccb(Assembler::equal, none);
__ cmpptr(mdo_addr, TypeEntries::null_seen);
__ jccb(Assembler::equal, none);
// There is a chance that the checks above (re-reading profiling
// data from memory) fail if another thread has just set the
// profiling to this obj's klass
__ xorptr(tmp, mdo_addr);
__ testptr(tmp, TypeEntries::type_klass_mask);
__ jccb(Assembler::zero, next);
}
} else {
assert(ciTypeEntries::valid_ciklass(current_klass) != NULL &&
ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only");
__ movptr(tmp, mdo_addr);
__ testptr(tmp, TypeEntries::type_unknown);
__ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
}
// different than before. Cannot keep accurate profile.
__ orptr(mdo_addr, TypeEntries::type_unknown);
if (TypeEntries::is_type_none(current_klass)) {
__ jmpb(next);
__ bind(none);
// first time here. Set profile type.
__ movptr(mdo_addr, tmp);
}
} else {
// There's a single possible klass at this profile point
assert(exact_klass != NULL, "should be");
if (TypeEntries::is_type_none(current_klass)) {
__ mov_metadata(tmp, exact_klass->constant_encoding());
__ xorptr(tmp, mdo_addr);
__ testptr(tmp, TypeEntries::type_klass_mask);
#ifdef ASSERT
__ jcc(Assembler::zero, next);
{
Label ok;
__ push(tmp);
__ cmpptr(mdo_addr, 0);
__ jcc(Assembler::equal, ok);
__ cmpptr(mdo_addr, TypeEntries::null_seen);
__ jcc(Assembler::equal, ok);
// may have been set by another thread
__ mov_metadata(tmp, exact_klass->constant_encoding());
__ xorptr(tmp, mdo_addr);
__ testptr(tmp, TypeEntries::type_mask);
__ jcc(Assembler::zero, ok);
__ stop("unexpected profiling mismatch");
__ bind(ok);
__ pop(tmp);
}
#else
__ jccb(Assembler::zero, next);
#endif
// first time here. Set profile type.
__ movptr(mdo_addr, tmp);
} else {
assert(ciTypeEntries::valid_ciklass(current_klass) != NULL &&
ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent");
__ movptr(tmp, mdo_addr);
__ testptr(tmp, TypeEntries::type_unknown);
__ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
__ orptr(mdo_addr, TypeEntries::type_unknown);
}
}
__ bind(next);
}
}
void LIR_Assembler::emit_delay(LIR_OpDelay*) {
Unimplemented();
}

View File

@ -79,6 +79,8 @@ define_pd_global(bool, UseMembar, false);
// GC Ergo Flags
define_pd_global(uintx, CMSYoungGenPerWorker, 64*M); // default max size of CMS young gen, per GC worker thread
define_pd_global(uintx, TypeProfileLevel, 11);
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
\
develop(bool, IEEEPrecision, true, \

View File

@ -1046,6 +1046,158 @@ 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() || MethodData::profile_return()) {
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);
if (MethodData::profile_arguments()) {
Label done;
int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset());
addptr(mdp, off_to_args);
for (int i = 0; i < TypeProfileArgsLimit; i++) {
if (i > 0 || MethodData::profile_return()) {
// If return value type is profiled we may have no argument to profile
movl(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::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()));
// stack offset o (zero based) from the start of the argument
// list, for n arguments translates into offset n - o - 1 from
// the end of the argument list
subl(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::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(TypeEntriesAtCall::argument_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;
}
if (MethodData::profile_return()) {
movl(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args));
subl(tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count());
}
bind(done);
if (MethodData::profile_return()) {
// We're right after the type profile for the last
// argument. tmp is the number of cell left in the
// CallTypeData/VirtualCallTypeData to reach its end. Non null
// if there's a return to profile.
assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type");
shll(tmp, exact_log2(DataLayout::cell_size));
addptr(mdp, tmp);
}
movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp);
} else {
assert(MethodData::profile_return(), "either profile call args or call ret");
update_mdp_by_constant(mdp, in_bytes(ReturnTypeEntry::size()));
}
// mdp points right after the end of the
// CallTypeData/VirtualCallTypeData, right after the cells for the
// return value type if there's one
bind(profile_continue);
}
}
void InterpreterMacroAssembler::profile_return_type(Register mdp, Register ret, Register tmp) {
assert_different_registers(mdp, ret, tmp, rsi);
if (ProfileInterpreter && MethodData::profile_return()) {
Label profile_continue, done;
test_method_data_pointer(mdp, profile_continue);
if (MethodData::profile_return_jsr292_only()) {
// If we don't profile all invoke bytecodes we must make sure
// it's a bytecode we indeed profile. We can't go back to the
// begining of the ProfileData we intend to update to check its
// type because we're right after it and we don't known its
// length
Label do_profile;
cmpb(Address(rsi, 0), Bytecodes::_invokedynamic);
jcc(Assembler::equal, do_profile);
cmpb(Address(rsi, 0), Bytecodes::_invokehandle);
jcc(Assembler::equal, do_profile);
get_method(tmp);
cmpb(Address(tmp, Method::intrinsic_id_offset_in_bytes()), vmIntrinsics::_compiledLambdaForm);
jcc(Assembler::notEqual, profile_continue);
bind(do_profile);
}
Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size()));
mov(tmp, ret);
profile_obj_type(tmp, mdo_ret_addr);
bind(profile_continue);
}
}
void InterpreterMacroAssembler::profile_call(Register mdp) {
if (ProfileInterpreter) {

View File

@ -215,6 +215,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
void profile_taken_branch(Register mdp, Register bumped_count);
void profile_not_taken_branch(Register mdp);
void profile_obj_type(Register obj, const Address& mdo_addr);
void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual);
void profile_return_type(Register mdp, Register ret, Register tmp);
void profile_call(Register mdp);
void profile_final_call(Register mdp);
void profile_virtual_call(Register receiver, Register mdp, Register scratch2,

View File

@ -1067,6 +1067,159 @@ 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() || MethodData::profile_return()) {
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);
if (MethodData::profile_arguments()) {
Label done;
int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset());
addptr(mdp, off_to_args);
for (int i = 0; i < TypeProfileArgsLimit; i++) {
if (i > 0 || MethodData::profile_return()) {
// If return value type is profiled we may have no argument to profile
movq(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::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(TypeEntriesAtCall::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(TypeEntriesAtCall::argument_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;
}
if (MethodData::profile_return()) {
movq(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args));
subl(tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count());
}
bind(done);
if (MethodData::profile_return()) {
// We're right after the type profile for the last
// argument. tmp is the number of cell left in the
// CallTypeData/VirtualCallTypeData to reach its end. Non null
// if there's a return to profile.
assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type");
shll(tmp, exact_log2(DataLayout::cell_size));
addptr(mdp, tmp);
}
movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp);
} else {
assert(MethodData::profile_return(), "either profile call args or call ret");
update_mdp_by_constant(mdp, in_bytes(ReturnTypeEntry::size()));
}
// mdp points right after the end of the
// CallTypeData/VirtualCallTypeData, right after the cells for the
// return value type if there's one
bind(profile_continue);
}
}
void InterpreterMacroAssembler::profile_return_type(Register mdp, Register ret, Register tmp) {
assert_different_registers(mdp, ret, tmp, r13);
if (ProfileInterpreter && MethodData::profile_return()) {
Label profile_continue, done;
test_method_data_pointer(mdp, profile_continue);
if (MethodData::profile_return_jsr292_only()) {
// If we don't profile all invoke bytecodes we must make sure
// it's a bytecode we indeed profile. We can't go back to the
// begining of the ProfileData we intend to update to check its
// type because we're right after it and we don't known its
// length
Label do_profile;
cmpb(Address(r13, 0), Bytecodes::_invokedynamic);
jcc(Assembler::equal, do_profile);
cmpb(Address(r13, 0), Bytecodes::_invokehandle);
jcc(Assembler::equal, do_profile);
get_method(tmp);
cmpb(Address(tmp, Method::intrinsic_id_offset_in_bytes()), vmIntrinsics::_compiledLambdaForm);
jcc(Assembler::notEqual, profile_continue);
bind(do_profile);
}
Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size()));
mov(tmp, ret);
profile_obj_type(tmp, mdo_ret_addr);
bind(profile_continue);
}
}
void InterpreterMacroAssembler::profile_call(Register mdp) {
if (ProfileInterpreter) {

View File

@ -224,6 +224,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
void profile_taken_branch(Register mdp, Register bumped_count);
void profile_not_taken_branch(Register mdp);
void profile_obj_type(Register obj, const Address& mdo_addr);
void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual);
void profile_return_type(Register mdp, Register ret, Register tmp);
void profile_call(Register mdp);
void profile_final_call(Register mdp);
void profile_virtual_call(Register receiver, Register mdp,

View File

@ -773,6 +773,7 @@ class MacroAssembler: public Assembler {
void orptr(Register dst, Address src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); }
void orptr(Register dst, Register src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); }
void orptr(Register dst, int32_t src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); }
void orptr(Address dst, int32_t imm32) { LP64_ONLY(orq(dst, imm32)) NOT_LP64(orl(dst, imm32)); }
void testptr(Register src, int32_t imm32) { LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); }
void testptr(Register src1, Register src2);

View File

@ -194,6 +194,12 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
__ restore_bcp();
__ restore_locals();
if (incoming_state == atos) {
Register mdp = rbx;
Register tmp = rcx;
__ profile_return_type(mdp, rax, tmp);
}
Label L_got_cache, L_giant_index;
if (EnableInvokeDynamic) {
__ cmpb(Address(rsi, 0), Bytecodes::_invokedynamic);

View File

@ -177,6 +177,12 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state,
__ restore_bcp();
__ restore_locals();
if (state == atos) {
Register mdp = rbx;
Register tmp = rcx;
__ profile_return_type(mdp, rax, tmp);
}
Label L_got_cache, L_giant_index;
if (EnableInvokeDynamic) {
__ cmpb(Address(r13, 0), Bytecodes::_invokedynamic);

View File

@ -2970,6 +2970,7 @@ void TemplateTable::invokevirtual_helper(Register index,
// profile this call
__ profile_final_call(rax);
__ profile_arguments_type(rax, method, rsi, true);
__ jump_from_interpreted(method, rax);
@ -2984,6 +2985,7 @@ void TemplateTable::invokevirtual_helper(Register index,
// get target Method* & entry point
__ lookup_virtual_method(rax, index, method);
__ profile_arguments_type(rdx, method, rsi, true);
__ jump_from_interpreted(method, rdx);
}
@ -3013,6 +3015,7 @@ void TemplateTable::invokespecial(int byte_no) {
__ null_check(rcx);
// do the call
__ profile_call(rax);
__ profile_arguments_type(rax, rbx, rsi, false);
__ jump_from_interpreted(rbx, rax);
}
@ -3023,6 +3026,7 @@ void TemplateTable::invokestatic(int byte_no) {
prepare_invoke(byte_no, rbx); // get f1 Method*
// do the call
__ profile_call(rax);
__ profile_arguments_type(rax, rbx, rsi, false);
__ jump_from_interpreted(rbx, rax);
}
@ -3082,6 +3086,8 @@ void TemplateTable::invokeinterface(int byte_no) {
__ testptr(rbx, rbx);
__ jcc(Assembler::zero, no_such_method);
__ profile_arguments_type(rdx, rbx, rsi, true);
// do the call
// rcx: receiver
// rbx,: Method*
@ -3138,6 +3144,7 @@ void TemplateTable::invokehandle(int byte_no) {
// FIXME: profile the LambdaForm also
__ profile_final_call(rax);
__ profile_arguments_type(rdx, rbx_method, rsi, true);
__ jump_from_interpreted(rbx_method, rdx);
}
@ -3171,6 +3178,7 @@ void TemplateTable::invokedynamic(int byte_no) {
// %%% should make a type profile for any invokedynamic that takes a ref argument
// profile this call
__ profile_call(rsi);
__ profile_arguments_type(rdx, rbx, rsi, false);
__ verify_oop(rax_callsite);

View File

@ -3026,6 +3026,7 @@ void TemplateTable::invokevirtual_helper(Register index,
// profile this call
__ profile_final_call(rax);
__ profile_arguments_type(rax, method, r13, true);
__ jump_from_interpreted(method, rax);
@ -3040,6 +3041,7 @@ void TemplateTable::invokevirtual_helper(Register index,
// get target Method* & entry point
__ lookup_virtual_method(rax, index, method);
__ profile_arguments_type(rdx, method, r13, true);
__ jump_from_interpreted(method, rdx);
}
@ -3069,6 +3071,7 @@ void TemplateTable::invokespecial(int byte_no) {
__ null_check(rcx);
// do the call
__ profile_call(rax);
__ profile_arguments_type(rax, rbx, r13, false);
__ jump_from_interpreted(rbx, rax);
}
@ -3079,6 +3082,7 @@ void TemplateTable::invokestatic(int byte_no) {
prepare_invoke(byte_no, rbx); // get f1 Method*
// do the call
__ profile_call(rax);
__ profile_arguments_type(rax, rbx, r13, false);
__ jump_from_interpreted(rbx, rax);
}
@ -3136,6 +3140,8 @@ void TemplateTable::invokeinterface(int byte_no) {
__ testptr(rbx, rbx);
__ jcc(Assembler::zero, no_such_method);
__ profile_arguments_type(rdx, rbx, r13, true);
// do the call
// rcx: receiver
// rbx,: Method*
@ -3193,6 +3199,7 @@ void TemplateTable::invokehandle(int byte_no) {
// FIXME: profile the LambdaForm also
__ profile_final_call(rax);
__ profile_arguments_type(rdx, rbx_method, r13, true);
__ jump_from_interpreted(rbx_method, rdx);
}
@ -3226,6 +3233,7 @@ void TemplateTable::invokedynamic(int byte_no) {
// %%% should make a type profile for any invokedynamic that takes a ref argument
// profile this call
__ profile_call(r13);
__ profile_arguments_type(rdx, rbx_method, r13, false);
__ verify_oop(rax_callsite);

View File

@ -935,6 +935,7 @@ void Canonicalizer::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {}
void Canonicalizer::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {}
void Canonicalizer::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) {}
void Canonicalizer::do_ProfileCall(ProfileCall* x) {}
void Canonicalizer::do_ProfileReturnType(ProfileReturnType* x) {}
void Canonicalizer::do_ProfileInvoke(ProfileInvoke* x) {}
void Canonicalizer::do_RuntimeCall(RuntimeCall* x) {}
void Canonicalizer::do_RangeCheckPredicate(RangeCheckPredicate* x) {}

View File

@ -104,6 +104,7 @@ class Canonicalizer: InstructionVisitor {
virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x);
virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x);
virtual void do_ProfileCall (ProfileCall* x);
virtual void do_ProfileReturnType (ProfileReturnType* x);
virtual void do_ProfileInvoke (ProfileInvoke* x);
virtual void do_RuntimeCall (RuntimeCall* x);
virtual void do_MemBar (MemBar* x);

View File

@ -601,6 +601,17 @@ void Compilation::bailout(const char* msg) {
}
}
ciKlass* Compilation::cha_exact_type(ciType* type) {
if (type != NULL && type->is_loaded() && type->is_instance_klass()) {
ciInstanceKlass* ik = type->as_instance_klass();
assert(ik->exact_klass() == NULL, "no cha for final klass");
if (DeoptC1 && UseCHA && !(ik->has_subklass() || ik->is_interface())) {
dependency_recorder()->assert_leaf_type(ik);
return ik;
}
}
return NULL;
}
void Compilation::print_timers() {
// tty->print_cr(" Native methods : %6.3f s, Average : %2.3f", CompileBroker::_t_native_compilation.seconds(), CompileBroker::_t_native_compilation.seconds() / CompileBroker::_total_native_compile_count);

View File

@ -246,6 +246,8 @@ class Compilation: public StackObj {
(RangeCheckElimination || UseLoopInvariantCodeMotion) &&
method()->method_data()->trap_count(Deoptimization::Reason_none) == 0;
}
ciKlass* cha_exact_type(ciType* type);
};

View File

@ -42,26 +42,16 @@
#include "runtime/interfaceSupport.hpp"
#include "runtime/sharedRuntime.hpp"
volatile int Compiler::_runtimes = uninitialized;
Compiler::Compiler() {
}
Compiler::Compiler () {}
Compiler::~Compiler() {
Unimplemented();
}
void Compiler::initialize_all() {
void Compiler::init_c1_runtime() {
BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob();
Arena* arena = new (mtCompiler) Arena();
Runtime1::initialize(buffer_blob);
FrameMap::initialize();
// initialize data structures
ValueType::initialize(arena);
// Instruction::initialize();
// BlockBegin::initialize();
GraphBuilder::initialize();
// note: to use more than one instance of LinearScan at a time this function call has to
// be moved somewhere outside of this constructor:
@ -70,32 +60,33 @@ void Compiler::initialize_all() {
void Compiler::initialize() {
if (_runtimes != initialized) {
initialize_runtimes( initialize_all, &_runtimes);
// Buffer blob must be allocated per C1 compiler thread at startup
BufferBlob* buffer_blob = init_buffer_blob();
if (should_perform_init()) {
if (buffer_blob == NULL) {
// When we come here we are in state 'initializing'; entire C1 compilation
// can be shut down.
set_state(failed);
} else {
init_c1_runtime();
set_state(initialized);
}
}
mark_initialized();
}
BufferBlob* Compiler::get_buffer_blob(ciEnv* env) {
BufferBlob* Compiler::init_buffer_blob() {
// Allocate buffer blob once at startup since allocation for each
// compilation seems to be too expensive (at least on Intel win32).
BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob();
if (buffer_blob != NULL) {
return buffer_blob;
}
assert (CompilerThread::current()->get_buffer_blob() == NULL, "Should initialize only once");
// setup CodeBuffer. Preallocate a BufferBlob of size
// NMethodSizeLimit plus some extra space for constants.
int code_buffer_size = Compilation::desired_max_code_buffer_size() +
Compilation::desired_max_constant_size();
buffer_blob = BufferBlob::create("Compiler1 temporary CodeBuffer",
code_buffer_size);
if (buffer_blob == NULL) {
CompileBroker::handle_full_code_cache();
env->record_failure("CodeCache is full");
} else {
BufferBlob* buffer_blob = BufferBlob::create("C1 temporary CodeBuffer", code_buffer_size);
if (buffer_blob != NULL) {
CompilerThread::current()->set_buffer_blob(buffer_blob);
}
@ -104,15 +95,8 @@ BufferBlob* Compiler::get_buffer_blob(ciEnv* env) {
void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) {
BufferBlob* buffer_blob = Compiler::get_buffer_blob(env);
if (buffer_blob == NULL) {
return;
}
if (!is_initialized()) {
initialize();
}
BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob();
assert(buffer_blob != NULL, "Must exist");
// invoke compilation
{
// We are nested here because we need for the destructor

View File

@ -30,11 +30,9 @@
// There is one instance of the Compiler per CompilerThread.
class Compiler: public AbstractCompiler {
private:
// Tracks whether runtime has been initialized
static volatile int _runtimes;
static void init_c1_runtime();
BufferBlob* init_buffer_blob();
public:
// Creation
@ -46,19 +44,12 @@ class Compiler: public AbstractCompiler {
virtual bool is_c1() { return true; };
BufferBlob* get_buffer_blob(ciEnv* env);
// Missing feature tests
virtual bool supports_native() { return true; }
virtual bool supports_osr () { return true; }
// Customization
virtual bool needs_adapters () { return false; }
virtual bool needs_stubs () { return false; }
// Initialization
virtual void initialize();
static void initialize_all();
// Compilation entry point for methods
virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci);

View File

@ -1466,9 +1466,22 @@ void GraphBuilder::method_return(Value x) {
// State at end of inlined method is the state of the caller
// without the method parameters on stack, including the
// return value, if any, of the inlined method on operand stack.
int invoke_bci = state()->caller_state()->bci();
set_state(state()->caller_state()->copy_for_parsing());
if (x != NULL) {
state()->push(x->type(), x);
if (profile_calls() && MethodData::profile_return() && x->type()->is_object_kind()) {
ciMethod* caller = state()->scope()->method();
ciMethodData* md = caller->method_data_or_null();
ciProfileData* data = md->bci_to_data(invoke_bci);
if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) {
bool has_return = data->is_CallTypeData() ? ((ciCallTypeData*)data)->has_return() : ((ciVirtualCallTypeData*)data)->has_return();
// May not be true in case of an inlined call through a method handle intrinsic.
if (has_return) {
profile_return_type(x, method(), caller, invoke_bci);
}
}
}
}
Goto* goto_callee = new Goto(continuation(), false);
@ -1658,6 +1671,42 @@ Dependencies* GraphBuilder::dependency_recorder() const {
return compilation()->dependency_recorder();
}
// How many arguments do we want to profile?
Values* GraphBuilder::args_list_for_profiling(int& start, bool may_have_receiver) {
int n = 0;
assert(start == 0, "should be initialized");
if (MethodData::profile_arguments()) {
ciProfileData* data = method()->method_data()->bci_to_data(bci());
if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) {
n = data->is_CallTypeData() ? data->as_CallTypeData()->number_of_arguments() : data->as_VirtualCallTypeData()->number_of_arguments();
bool has_receiver = may_have_receiver && Bytecodes::has_receiver(method()->java_code_at_bci(bci()));
start = has_receiver ? 1 : 0;
}
}
if (n > 0) {
return new Values(n);
}
return NULL;
}
// Collect arguments that we want to profile in a list
Values* GraphBuilder::collect_args_for_profiling(Values* args, bool may_have_receiver) {
int start = 0;
Values* obj_args = args_list_for_profiling(start, may_have_receiver);
if (obj_args == NULL) {
return NULL;
}
int s = obj_args->size();
for (int i = start, j = 0; j < s; i++) {
if (args->at(i)->type()->is_object_kind()) {
obj_args->push(args->at(i));
j++;
}
}
assert(s == obj_args->length(), "missed on arg?");
return obj_args;
}
void GraphBuilder::invoke(Bytecodes::Code code) {
bool will_link;
@ -1957,7 +2006,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
} else if (exact_target != NULL) {
target_klass = exact_target->holder();
}
profile_call(target, recv, target_klass);
profile_call(target, recv, target_klass, collect_args_for_profiling(args, false), false);
}
}
@ -1972,6 +2021,9 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
push(result_type, result);
}
}
if (profile_calls() && MethodData::profile_return() && result_type->is_object_kind()) {
profile_return_type(result, target);
}
}
@ -3509,7 +3561,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
recv = args->at(0);
null_check(recv);
}
profile_call(callee, recv, NULL);
profile_call(callee, recv, NULL, collect_args_for_profiling(args, true), true);
}
}
}
@ -3520,6 +3572,10 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
Value value = append_split(result);
if (result_type != voidType) push(result_type, value);
if (callee != method() && profile_calls() && MethodData::profile_return() && result_type->is_object_kind()) {
profile_return_type(result, callee);
}
// done
return true;
}
@ -3763,7 +3819,28 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
compilation()->set_would_profile(true);
if (profile_calls()) {
profile_call(callee, recv, holder_known ? callee->holder() : NULL);
int start = 0;
Values* obj_args = args_list_for_profiling(start, has_receiver);
if (obj_args != NULL) {
int s = obj_args->size();
// if called through method handle invoke, some arguments may have been popped
for (int i = args_base+start, j = 0; j < obj_args->size() && i < state()->stack_size(); ) {
Value v = state()->stack_at_inc(i);
if (v->type()->is_object_kind()) {
obj_args->push(v);
j++;
}
}
#ifdef ASSERT
{
bool ignored_will_link;
ciSignature* declared_signature = NULL;
ciMethod* real_target = method()->get_method_at_bci(bci(), ignored_will_link, &declared_signature);
assert(s == obj_args->length() || real_target->is_method_handle_intrinsic(), "missed on arg?");
}
#endif
}
profile_call(callee, recv, holder_known ? callee->holder() : NULL, obj_args, true);
}
}
@ -4251,8 +4328,23 @@ void GraphBuilder::print_stats() {
}
#endif // PRODUCT
void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder) {
append(new ProfileCall(method(), bci(), callee, recv, known_holder));
void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined) {
append(new ProfileCall(method(), bci(), callee, recv, known_holder, obj_args, inlined));
}
void GraphBuilder::profile_return_type(Value ret, ciMethod* callee, ciMethod* m, int invoke_bci) {
assert((m == NULL) == (invoke_bci < 0), "invalid method and invalid bci together");
if (m == NULL) {
m = method();
}
if (invoke_bci < 0) {
invoke_bci = bci();
}
ciMethodData* md = m->method_data_or_null();
ciProfileData* data = md->bci_to_data(invoke_bci);
if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) {
append(new ProfileReturnType(m , invoke_bci, callee, ret));
}
}
void GraphBuilder::profile_invocation(ciMethod* callee, ValueStack* state) {

View File

@ -374,7 +374,8 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
void print_inlining(ciMethod* callee, const char* msg = NULL, bool success = true);
void profile_call(ciMethod* callee, Value recv, ciKlass* predicted_holder);
void profile_call(ciMethod* callee, Value recv, ciKlass* predicted_holder, Values* obj_args, bool inlined);
void profile_return_type(Value ret, ciMethod* callee, ciMethod* m = NULL, int bci = -1);
void profile_invocation(ciMethod* inlinee, ValueStack* state);
// Shortcuts to profiling control.
@ -386,6 +387,9 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
bool profile_inlined_calls() { return _compilation->profile_inlined_calls(); }
bool profile_checkcasts() { return _compilation->profile_checkcasts(); }
Values* args_list_for_profiling(int& start, bool may_have_receiver);
Values* collect_args_for_profiling(Values* args, bool may_have_receiver);
public:
NOT_PRODUCT(void print_stats();)

View File

@ -104,6 +104,14 @@ void Instruction::state_values_do(ValueVisitor* f) {
}
}
ciType* Instruction::exact_type() const {
ciType* t = declared_type();
if (t != NULL && t->is_klass()) {
return t->as_klass()->exact_klass();
}
return NULL;
}
#ifndef PRODUCT
void Instruction::check_state(ValueStack* state) {
@ -135,9 +143,7 @@ void Instruction::print(InstructionPrinter& ip) {
// perform constant and interval tests on index value
bool AccessIndexed::compute_needs_range_check() {
if (length()) {
Constant* clength = length()->as_Constant();
Constant* cindex = index()->as_Constant();
if (clength && cindex) {
@ -157,34 +163,8 @@ bool AccessIndexed::compute_needs_range_check() {
}
ciType* Local::exact_type() const {
ciType* type = declared_type();
// for primitive arrays, the declared type is the exact type
if (type->is_type_array_klass()) {
return type;
} else if (type->is_instance_klass()) {
ciInstanceKlass* ik = (ciInstanceKlass*)type;
if (ik->is_loaded() && ik->is_final() && !ik->is_interface()) {
return type;
}
} else if (type->is_obj_array_klass()) {
ciObjArrayKlass* oak = (ciObjArrayKlass*)type;
ciType* base = oak->base_element_type();
if (base->is_instance_klass()) {
ciInstanceKlass* ik = base->as_instance_klass();
if (ik->is_loaded() && ik->is_final()) {
return type;
}
} else if (base->is_primitive_type()) {
return type;
}
}
return NULL;
}
ciType* Constant::exact_type() const {
if (type()->is_object()) {
if (type()->is_object() && type()->as_ObjectType()->is_loaded()) {
return type()->as_ObjectType()->exact_type();
}
return NULL;
@ -192,19 +172,18 @@ ciType* Constant::exact_type() const {
ciType* LoadIndexed::exact_type() const {
ciType* array_type = array()->exact_type();
if (array_type == NULL) {
return NULL;
}
assert(array_type->is_array_klass(), "what else?");
ciArrayKlass* ak = (ciArrayKlass*)array_type;
if (array_type != NULL) {
assert(array_type->is_array_klass(), "what else?");
ciArrayKlass* ak = (ciArrayKlass*)array_type;
if (ak->element_type()->is_instance_klass()) {
ciInstanceKlass* ik = (ciInstanceKlass*)ak->element_type();
if (ik->is_loaded() && ik->is_final()) {
return ik;
if (ak->element_type()->is_instance_klass()) {
ciInstanceKlass* ik = (ciInstanceKlass*)ak->element_type();
if (ik->is_loaded() && ik->is_final()) {
return ik;
}
}
}
return NULL;
return Instruction::exact_type();
}
@ -224,22 +203,6 @@ ciType* LoadField::declared_type() const {
}
ciType* LoadField::exact_type() const {
ciType* type = declared_type();
// for primitive arrays, the declared type is the exact type
if (type->is_type_array_klass()) {
return type;
}
if (type->is_instance_klass()) {
ciInstanceKlass* ik = (ciInstanceKlass*)type;
if (ik->is_loaded() && ik->is_final()) {
return type;
}
}
return NULL;
}
ciType* NewTypeArray::exact_type() const {
return ciTypeArrayKlass::make(elt_type());
}
@ -264,16 +227,6 @@ ciType* CheckCast::declared_type() const {
return klass();
}
ciType* CheckCast::exact_type() const {
if (klass()->is_instance_klass()) {
ciInstanceKlass* ik = (ciInstanceKlass*)klass();
if (ik->is_loaded() && ik->is_final()) {
return ik;
}
}
return NULL;
}
// Implementation of ArithmeticOp
bool ArithmeticOp::is_commutative() const {

View File

@ -107,6 +107,7 @@ class UnsafePrefetch;
class UnsafePrefetchRead;
class UnsafePrefetchWrite;
class ProfileCall;
class ProfileReturnType;
class ProfileInvoke;
class RuntimeCall;
class MemBar;
@ -211,6 +212,7 @@ class InstructionVisitor: public StackObj {
virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x) = 0;
virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) = 0;
virtual void do_ProfileCall (ProfileCall* x) = 0;
virtual void do_ProfileReturnType (ProfileReturnType* x) = 0;
virtual void do_ProfileInvoke (ProfileInvoke* x) = 0;
virtual void do_RuntimeCall (RuntimeCall* x) = 0;
virtual void do_MemBar (MemBar* x) = 0;
@ -322,6 +324,36 @@ class Instruction: public CompilationResourceObj {
_type = type;
}
// Helper class to keep track of which arguments need a null check
class ArgsNonNullState {
private:
int _nonnull_state; // mask identifying which args are nonnull
public:
ArgsNonNullState()
: _nonnull_state(AllBits) {}
// Does argument number i needs a null check?
bool arg_needs_null_check(int i) const {
// No data is kept for arguments starting at position 33 so
// conservatively assume that they need a null check.
if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
return is_set_nth_bit(_nonnull_state, i);
}
return true;
}
// Set whether argument number i needs a null check or not
void set_arg_needs_null_check(int i, bool check) {
if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
if (check) {
_nonnull_state |= nth_bit(i);
} else {
_nonnull_state &= ~(nth_bit(i));
}
}
}
};
public:
void* operator new(size_t size) throw() {
Compilation* c = Compilation::current();
@ -566,7 +598,7 @@ class Instruction: public CompilationResourceObj {
virtual void other_values_do(ValueVisitor* f) { /* usually no other - override on demand */ }
void values_do(ValueVisitor* f) { input_values_do(f); state_values_do(f); other_values_do(f); }
virtual ciType* exact_type() const { return NULL; }
virtual ciType* exact_type() const;
virtual ciType* declared_type() const { return NULL; }
// hashing
@ -689,7 +721,6 @@ LEAF(Local, Instruction)
int java_index() const { return _java_index; }
virtual ciType* declared_type() const { return _declared_type; }
virtual ciType* exact_type() const;
// generic
virtual void input_values_do(ValueVisitor* f) { /* no values */ }
@ -806,7 +837,6 @@ LEAF(LoadField, AccessField)
{}
ciType* declared_type() const;
ciType* exact_type() const;
// generic
HASHING2(LoadField, !needs_patching() && !field()->is_volatile(), obj()->subst(), offset()) // cannot be eliminated if needs patching or if volatile
@ -1299,6 +1329,7 @@ BASE(NewArray, StateSplit)
virtual bool needs_exception_state() const { return false; }
ciType* exact_type() const { return NULL; }
ciType* declared_type() const;
// generic
@ -1422,7 +1453,6 @@ LEAF(CheckCast, TypeCheck)
}
ciType* declared_type() const;
ciType* exact_type() const;
};
@ -1490,7 +1520,7 @@ LEAF(Intrinsic, StateSplit)
vmIntrinsics::ID _id;
Values* _args;
Value _recv;
int _nonnull_state; // mask identifying which args are nonnull
ArgsNonNullState _nonnull_state;
public:
// preserves_state can be set to true for Intrinsics
@ -1511,7 +1541,6 @@ LEAF(Intrinsic, StateSplit)
, _id(id)
, _args(args)
, _recv(NULL)
, _nonnull_state(AllBits)
{
assert(args != NULL, "args must exist");
ASSERT_VALUES
@ -1537,21 +1566,12 @@ LEAF(Intrinsic, StateSplit)
Value receiver() const { assert(has_receiver(), "must have receiver"); return _recv; }
bool preserves_state() const { return check_flag(PreservesStateFlag); }
bool arg_needs_null_check(int i) {
if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
return is_set_nth_bit(_nonnull_state, i);
}
return true;
bool arg_needs_null_check(int i) const {
return _nonnull_state.arg_needs_null_check(i);
}
void set_arg_needs_null_check(int i, bool check) {
if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
if (check) {
_nonnull_state |= nth_bit(i);
} else {
_nonnull_state &= ~(nth_bit(i));
}
}
_nonnull_state.set_arg_needs_null_check(i, check);
}
// generic
@ -2450,34 +2470,87 @@ LEAF(UnsafePrefetchWrite, UnsafePrefetch)
LEAF(ProfileCall, Instruction)
private:
ciMethod* _method;
int _bci_of_invoke;
ciMethod* _callee; // the method that is called at the given bci
Value _recv;
ciKlass* _known_holder;
ciMethod* _method;
int _bci_of_invoke;
ciMethod* _callee; // the method that is called at the given bci
Value _recv;
ciKlass* _known_holder;
Values* _obj_args; // arguments for type profiling
ArgsNonNullState _nonnull_state; // Do we know whether some arguments are never null?
bool _inlined; // Are we profiling a call that is inlined
public:
ProfileCall(ciMethod* method, int bci, ciMethod* callee, Value recv, ciKlass* known_holder)
ProfileCall(ciMethod* method, int bci, ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined)
: Instruction(voidType)
, _method(method)
, _bci_of_invoke(bci)
, _callee(callee)
, _recv(recv)
, _known_holder(known_holder)
, _obj_args(obj_args)
, _inlined(inlined)
{
// The ProfileCall has side-effects and must occur precisely where located
pin();
}
ciMethod* method() { return _method; }
int bci_of_invoke() { return _bci_of_invoke; }
ciMethod* callee() { return _callee; }
Value recv() { return _recv; }
ciKlass* known_holder() { return _known_holder; }
ciMethod* method() const { return _method; }
int bci_of_invoke() const { return _bci_of_invoke; }
ciMethod* callee() const { return _callee; }
Value recv() const { return _recv; }
ciKlass* known_holder() const { return _known_holder; }
int nb_profiled_args() const { return _obj_args == NULL ? 0 : _obj_args->length(); }
Value profiled_arg_at(int i) const { return _obj_args->at(i); }
bool arg_needs_null_check(int i) const {
return _nonnull_state.arg_needs_null_check(i);
}
bool inlined() const { return _inlined; }
virtual void input_values_do(ValueVisitor* f) { if (_recv != NULL) f->visit(&_recv); }
void set_arg_needs_null_check(int i, bool check) {
_nonnull_state.set_arg_needs_null_check(i, check);
}
virtual void input_values_do(ValueVisitor* f) {
if (_recv != NULL) {
f->visit(&_recv);
}
for (int i = 0; i < nb_profiled_args(); i++) {
f->visit(_obj_args->adr_at(i));
}
}
};
LEAF(ProfileReturnType, Instruction)
private:
ciMethod* _method;
ciMethod* _callee;
int _bci_of_invoke;
Value _ret;
public:
ProfileReturnType(ciMethod* method, int bci, ciMethod* callee, Value ret)
: Instruction(voidType)
, _method(method)
, _callee(callee)
, _bci_of_invoke(bci)
, _ret(ret)
{
set_needs_null_check(true);
// The ProfileType has side-effects and must occur precisely where located
pin();
}
ciMethod* method() const { return _method; }
ciMethod* callee() const { return _callee; }
int bci_of_invoke() const { return _bci_of_invoke; }
Value ret() const { return _ret; }
virtual void input_values_do(ValueVisitor* f) {
if (_ret != NULL) {
f->visit(&_ret);
}
}
};
// Call some C runtime function that doesn't safepoint,
// optionally passing the current thread as the first argument.

View File

@ -892,10 +892,24 @@ void InstructionPrinter::do_ProfileCall(ProfileCall* x) {
if (x->known_holder() != NULL) {
output()->print(", ");
print_klass(x->known_holder());
output()->print(" ");
}
for (int i = 0; i < x->nb_profiled_args(); i++) {
if (i > 0) output()->print(", ");
print_value(x->profiled_arg_at(i));
if (x->arg_needs_null_check(i)) {
output()->print(" [NC]");
}
}
output()->put(')');
}
void InstructionPrinter::do_ProfileReturnType(ProfileReturnType* x) {
output()->print("profile ret type ");
print_value(x->ret());
output()->print(" %s.%s", x->method()->holder()->name()->as_utf8(), x->method()->name()->as_utf8());
output()->put(')');
}
void InstructionPrinter::do_ProfileInvoke(ProfileInvoke* x) {
output()->print("profile_invoke ");
output()->print(" %s.%s", x->inlinee()->holder()->name()->as_utf8(), x->inlinee()->name()->as_utf8());

View File

@ -132,6 +132,7 @@ class InstructionPrinter: public InstructionVisitor {
virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x);
virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x);
virtual void do_ProfileCall (ProfileCall* x);
virtual void do_ProfileReturnType (ProfileReturnType* x);
virtual void do_ProfileInvoke (ProfileInvoke* x);
virtual void do_RuntimeCall (RuntimeCall* x);
virtual void do_MemBar (MemBar* x);

View File

@ -1001,6 +1001,17 @@ void LIR_OpVisitState::visit(LIR_Op* op) {
assert(opProfileCall->_tmp1->is_valid(), "used"); do_temp(opProfileCall->_tmp1);
break;
}
// LIR_OpProfileType:
case lir_profile_type: {
assert(op->as_OpProfileType() != NULL, "must be");
LIR_OpProfileType* opProfileType = (LIR_OpProfileType*)op;
do_input(opProfileType->_mdp); do_temp(opProfileType->_mdp);
do_input(opProfileType->_obj);
do_temp(opProfileType->_tmp);
break;
}
default:
ShouldNotReachHere();
}
@ -1151,6 +1162,10 @@ void LIR_OpProfileCall::emit_code(LIR_Assembler* masm) {
masm->emit_profile_call(this);
}
void LIR_OpProfileType::emit_code(LIR_Assembler* masm) {
masm->emit_profile_type(this);
}
// LIR_List
LIR_List::LIR_List(Compilation* compilation, BlockBegin* block)
: _operations(8)
@ -1803,6 +1818,8 @@ const char * LIR_Op::name() const {
case lir_cas_int: s = "cas_int"; break;
// LIR_OpProfileCall
case lir_profile_call: s = "profile_call"; break;
// LIR_OpProfileType
case lir_profile_type: s = "profile_type"; break;
// LIR_OpAssert
#ifdef ASSERT
case lir_assert: s = "assert"; break;
@ -2086,6 +2103,15 @@ void LIR_OpProfileCall::print_instr(outputStream* out) const {
tmp1()->print(out); out->print(" ");
}
// LIR_OpProfileType
void LIR_OpProfileType::print_instr(outputStream* out) const {
out->print("exact = "); exact_klass()->print_name_on(out);
out->print("current = "); ciTypeEntries::print_ciklass(out, current_klass());
mdp()->print(out); out->print(" ");
obj()->print(out); out->print(" ");
tmp()->print(out); out->print(" ");
}
#endif // PRODUCT
// Implementation of LIR_InsertionBuffer

View File

@ -882,6 +882,7 @@ class LIR_OpLock;
class LIR_OpTypeCheck;
class LIR_OpCompareAndSwap;
class LIR_OpProfileCall;
class LIR_OpProfileType;
#ifdef ASSERT
class LIR_OpAssert;
#endif
@ -1005,6 +1006,7 @@ enum LIR_Code {
, end_opCompareAndSwap
, begin_opMDOProfile
, lir_profile_call
, lir_profile_type
, end_opMDOProfile
, begin_opAssert
, lir_assert
@ -1145,6 +1147,7 @@ class LIR_Op: public CompilationResourceObj {
virtual LIR_OpTypeCheck* as_OpTypeCheck() { return NULL; }
virtual LIR_OpCompareAndSwap* as_OpCompareAndSwap() { return NULL; }
virtual LIR_OpProfileCall* as_OpProfileCall() { return NULL; }
virtual LIR_OpProfileType* as_OpProfileType() { return NULL; }
#ifdef ASSERT
virtual LIR_OpAssert* as_OpAssert() { return NULL; }
#endif
@ -1925,8 +1928,8 @@ class LIR_OpProfileCall : public LIR_Op {
public:
// Destroys recv
LIR_OpProfileCall(LIR_Code code, ciMethod* profiled_method, int profiled_bci, ciMethod* profiled_callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* known_holder)
: LIR_Op(code, LIR_OprFact::illegalOpr, NULL) // no result, no info
LIR_OpProfileCall(ciMethod* profiled_method, int profiled_bci, ciMethod* profiled_callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* known_holder)
: LIR_Op(lir_profile_call, LIR_OprFact::illegalOpr, NULL) // no result, no info
, _profiled_method(profiled_method)
, _profiled_bci(profiled_bci)
, _profiled_callee(profiled_callee)
@ -1948,6 +1951,45 @@ class LIR_OpProfileCall : public LIR_Op {
virtual void print_instr(outputStream* out) const PRODUCT_RETURN;
};
// LIR_OpProfileType
class LIR_OpProfileType : public LIR_Op {
friend class LIR_OpVisitState;
private:
LIR_Opr _mdp;
LIR_Opr _obj;
LIR_Opr _tmp;
ciKlass* _exact_klass; // non NULL if we know the klass statically (no need to load it from _obj)
intptr_t _current_klass; // what the profiling currently reports
bool _not_null; // true if we know statically that _obj cannot be null
bool _no_conflict; // true if we're profling parameters, _exact_klass is not NULL and we know
// _exact_klass it the only possible type for this parameter in any context.
public:
// Destroys recv
LIR_OpProfileType(LIR_Opr mdp, LIR_Opr obj, ciKlass* exact_klass, intptr_t current_klass, LIR_Opr tmp, bool not_null, bool no_conflict)
: LIR_Op(lir_profile_type, LIR_OprFact::illegalOpr, NULL) // no result, no info
, _mdp(mdp)
, _obj(obj)
, _exact_klass(exact_klass)
, _current_klass(current_klass)
, _tmp(tmp)
, _not_null(not_null)
, _no_conflict(no_conflict) { }
LIR_Opr mdp() const { return _mdp; }
LIR_Opr obj() const { return _obj; }
LIR_Opr tmp() const { return _tmp; }
ciKlass* exact_klass() const { return _exact_klass; }
intptr_t current_klass() const { return _current_klass; }
bool not_null() const { return _not_null; }
bool no_conflict() const { return _no_conflict; }
virtual void emit_code(LIR_Assembler* masm);
virtual LIR_OpProfileType* as_OpProfileType() { return this; }
virtual void print_instr(outputStream* out) const PRODUCT_RETURN;
};
class LIR_InsertionBuffer;
//--------------------------------LIR_List---------------------------------------------------
@ -2247,7 +2289,10 @@ class LIR_List: public CompilationResourceObj {
ciMethod* profiled_method, int profiled_bci);
// MethodData* profiling
void profile_call(ciMethod* method, int bci, ciMethod* callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* cha_klass) {
append(new LIR_OpProfileCall(lir_profile_call, method, bci, callee, mdo, recv, t1, cha_klass));
append(new LIR_OpProfileCall(method, bci, callee, mdo, recv, t1, cha_klass));
}
void profile_type(LIR_Address* mdp, LIR_Opr obj, ciKlass* exact_klass, intptr_t current_klass, LIR_Opr tmp, bool not_null, bool no_conflict) {
append(new LIR_OpProfileType(LIR_OprFact::address(mdp), obj, exact_klass, current_klass, tmp, not_null, no_conflict));
}
void xadd(LIR_Opr src, LIR_Opr add, LIR_Opr res, LIR_Opr tmp) { append(new LIR_Op2(lir_xadd, src, add, res, tmp)); }

View File

@ -208,6 +208,7 @@ class LIR_Assembler: public CompilationResourceObj {
void emit_call(LIR_OpJavaCall* op);
void emit_rtcall(LIR_OpRTCall* op);
void emit_profile_call(LIR_OpProfileCall* op);
void emit_profile_type(LIR_OpProfileType* op);
void emit_delay(LIR_OpDelay* op);
void arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, CodeEmitInfo* info, bool pop_fpu_stack);

View File

@ -2571,6 +2571,78 @@ void LIRGenerator::do_Goto(Goto* x) {
}
ciKlass* LIRGenerator::profile_arg_type(ciMethodData* md, int md_base_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_k) {
ciKlass* result = NULL;
bool do_null = !not_null && !TypeEntries::was_null_seen(profiled_k);
bool do_update = !TypeEntries::is_type_unknown(profiled_k);
// known not to be null or null bit already set and already set to
// unknown: nothing we can do to improve profiling
if (!do_null && !do_update) {
return result;
}
ciKlass* exact_klass = NULL;
Compilation* comp = Compilation::current();
if (do_update) {
// try to find exact type, using CHA if possible, so that loading
// the klass from the object can be avoided
ciType* type = arg->exact_type();
if (type == NULL) {
type = arg->declared_type();
type = comp->cha_exact_type(type);
}
assert(type == NULL || type->is_klass(), "type should be class");
exact_klass = (type != NULL && type->is_loaded()) ? (ciKlass*)type : NULL;
do_update = exact_klass == NULL || ciTypeEntries::valid_ciklass(profiled_k) != exact_klass;
}
if (!do_null && !do_update) {
return result;
}
ciKlass* exact_signature_k = NULL;
if (do_update) {
// Is the type from the signature exact (the only one possible)?
exact_signature_k = signature_k->exact_klass();
if (exact_signature_k == NULL) {
exact_signature_k = comp->cha_exact_type(signature_k);
} else {
result = exact_signature_k;
do_update = false;
// Known statically. No need to emit any code: prevent
// LIR_Assembler::emit_profile_type() from emitting useless code
profiled_k = ciTypeEntries::with_status(result, profiled_k);
}
if (exact_signature_k != NULL && exact_klass != exact_signature_k) {
assert(exact_klass == NULL, "arg and signature disagree?");
// sometimes the type of the signature is better than the best type
// the compiler has
exact_klass = exact_signature_k;
do_update = exact_klass == NULL || ciTypeEntries::valid_ciklass(profiled_k) != exact_klass;
}
}
if (!do_null && !do_update) {
return result;
}
if (mdp == LIR_OprFact::illegalOpr) {
mdp = new_register(T_METADATA);
__ metadata2reg(md->constant_encoding(), mdp);
if (md_base_offset != 0) {
LIR_Address* base_type_address = new LIR_Address(mdp, md_base_offset, T_ADDRESS);
mdp = new_pointer_register();
__ leal(LIR_OprFact::address(base_type_address), mdp);
}
}
LIRItem value(arg, this);
value.load_item();
__ profile_type(new LIR_Address(mdp, md_offset, T_METADATA),
value.result(), exact_klass, profiled_k, new_pointer_register(), not_null, exact_signature_k != NULL);
return result;
}
void LIRGenerator::do_Base(Base* x) {
__ std_entry(LIR_OprFact::illegalOpr);
// Emit moves from physical registers / stack slots to virtual registers
@ -3004,12 +3076,52 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
}
}
void LIRGenerator::profile_arguments(ProfileCall* x) {
if (MethodData::profile_arguments()) {
int bci = x->bci_of_invoke();
ciMethodData* md = x->method()->method_data_or_null();
ciProfileData* data = md->bci_to_data(bci);
if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) {
ByteSize extra = data->is_CallTypeData() ? CallTypeData::args_data_offset() : VirtualCallTypeData::args_data_offset();
int base_offset = md->byte_offset_of_slot(data, extra);
LIR_Opr mdp = LIR_OprFact::illegalOpr;
ciTypeStackSlotEntries* args = data->is_CallTypeData() ? ((ciCallTypeData*)data)->args() : ((ciVirtualCallTypeData*)data)->args();
Bytecodes::Code bc = x->method()->java_code_at_bci(bci);
int start = 0;
int stop = data->is_CallTypeData() ? ((ciCallTypeData*)data)->number_of_arguments() : ((ciVirtualCallTypeData*)data)->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(TypeEntriesAtCall::argument_type_offset(i)) - in_bytes(TypeEntriesAtCall::args_data_offset());
ciKlass* exact = profile_arg_type(md, base_offset, off,
args->type(i), x->profiled_arg_at(i+start), mdp,
!x->arg_needs_null_check(i+start), sig_stream.next_klass());
if (exact != NULL) {
md->set_argument_type(bci, i, exact);
}
}
}
}
}
void LIRGenerator::do_ProfileCall(ProfileCall* x) {
// Need recv in a temporary register so it interferes with the other temporaries
LIR_Opr recv = LIR_OprFact::illegalOpr;
LIR_Opr mdo = new_register(T_OBJECT);
// tmp is used to hold the counters on SPARC
LIR_Opr tmp = new_pointer_register();
if (x->nb_profiled_args() > 0) {
profile_arguments(x);
}
if (x->recv() != NULL) {
LIRItem value(x->recv(), this);
value.load_item();
@ -3019,6 +3131,21 @@ void LIRGenerator::do_ProfileCall(ProfileCall* x) {
__ profile_call(x->method(), x->bci_of_invoke(), x->callee(), mdo, recv, tmp, x->known_holder());
}
void LIRGenerator::do_ProfileReturnType(ProfileReturnType* x) {
int bci = x->bci_of_invoke();
ciMethodData* md = x->method()->method_data_or_null();
ciProfileData* data = md->bci_to_data(bci);
assert(data->is_CallTypeData() || data->is_VirtualCallTypeData(), "wrong profile data type");
ciReturnTypeEntry* ret = data->is_CallTypeData() ? ((ciCallTypeData*)data)->ret() : ((ciVirtualCallTypeData*)data)->ret();
LIR_Opr mdp = LIR_OprFact::illegalOpr;
ciKlass* exact = profile_arg_type(md, 0, md->byte_offset_of_slot(data, ret->type_offset()),
ret->type(), x->ret(), mdp,
!x->needs_null_check(), x->callee()->signature()->return_type()->as_klass());
if (exact != NULL) {
md->set_return_type(bci, exact);
}
}
void LIRGenerator::do_ProfileInvoke(ProfileInvoke* x) {
// We can safely ignore accessors here, since c2 will inline them anyway,
// accessors are also always mature.
@ -3053,7 +3180,11 @@ void LIRGenerator::increment_event_counter_impl(CodeEmitInfo* info,
int offset = -1;
LIR_Opr counter_holder;
if (level == CompLevel_limited_profile) {
address counters_adr = method->ensure_method_counters();
MethodCounters* counters_adr = method->ensure_method_counters();
if (counters_adr == NULL) {
bailout("method counters allocation failed");
return;
}
counter_holder = new_pointer_register();
__ move(LIR_OprFact::intptrConst(counters_adr), counter_holder);
offset = in_bytes(backedge ? MethodCounters::backedge_counter_offset() :

View File

@ -434,6 +434,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
void do_ThreadIDIntrinsic(Intrinsic* x);
void do_ClassIDIntrinsic(Intrinsic* x);
#endif
ciKlass* profile_arg_type(ciMethodData* md, int md_first_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_k);
void profile_arguments(ProfileCall* x);
public:
Compilation* compilation() const { return _compilation; }
@ -534,6 +536,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x);
virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x);
virtual void do_ProfileCall (ProfileCall* x);
virtual void do_ProfileReturnType (ProfileReturnType* x);
virtual void do_ProfileInvoke (ProfileInvoke* x);
virtual void do_RuntimeCall (RuntimeCall* x);
virtual void do_MemBar (MemBar* x);

View File

@ -531,6 +531,7 @@ public:
void do_UnsafePrefetchRead (UnsafePrefetchRead* x);
void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x);
void do_ProfileCall (ProfileCall* x);
void do_ProfileReturnType (ProfileReturnType* x);
void do_ProfileInvoke (ProfileInvoke* x);
void do_RuntimeCall (RuntimeCall* x);
void do_MemBar (MemBar* x);
@ -657,6 +658,8 @@ class NullCheckEliminator: public ValueVisitor {
void handle_Intrinsic (Intrinsic* x);
void handle_ExceptionObject (ExceptionObject* x);
void handle_Phi (Phi* x);
void handle_ProfileCall (ProfileCall* x);
void handle_ProfileReturnType (ProfileReturnType* x);
};
@ -715,7 +718,9 @@ void NullCheckVisitor::do_UnsafePutObject(UnsafePutObject* x) {}
void NullCheckVisitor::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {}
void NullCheckVisitor::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {}
void NullCheckVisitor::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) {}
void NullCheckVisitor::do_ProfileCall (ProfileCall* x) { nce()->clear_last_explicit_null_check(); }
void NullCheckVisitor::do_ProfileCall (ProfileCall* x) { nce()->clear_last_explicit_null_check();
nce()->handle_ProfileCall(x); }
void NullCheckVisitor::do_ProfileReturnType (ProfileReturnType* x) { nce()->handle_ProfileReturnType(x); }
void NullCheckVisitor::do_ProfileInvoke (ProfileInvoke* x) {}
void NullCheckVisitor::do_RuntimeCall (RuntimeCall* x) {}
void NullCheckVisitor::do_MemBar (MemBar* x) {}
@ -1134,6 +1139,15 @@ 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 NullCheckEliminator::handle_ProfileReturnType(ProfileReturnType* x) {
x->set_needs_null_check(!set_contains(x->ret()));
}
void Optimizer::eliminate_null_checks() {
ResourceMark rm;

View File

@ -162,7 +162,8 @@ public:
void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ };
void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ };
void do_ProfileCall (ProfileCall* x) { /* nothing to do */ };
void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ };
void do_ProfileReturnType (ProfileReturnType* x) { /* nothing to do */ };
void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ };
void do_RuntimeCall (RuntimeCall* x) { /* nothing to do */ };
void do_MemBar (MemBar* x) { /* nothing to do */ };
void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ };

View File

@ -542,8 +542,7 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
// exception handler can cause class loading, which might throw an
// exception and those fields are expected to be clear during
// normal bytecode execution.
thread->set_exception_oop(NULL);
thread->set_exception_pc(NULL);
thread->clear_exception_oop_and_pc();
continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false);
// If an exception was thrown during exception dispatch, the exception oop may have changed

View File

@ -203,6 +203,7 @@ class ValueNumberingVisitor: public InstructionVisitor {
void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ }
void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ }
void do_ProfileCall (ProfileCall* x) { /* nothing to do */ }
void do_ProfileReturnType (ProfileReturnType* x) { /* nothing to do */ }
void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ };
void do_RuntimeCall (RuntimeCall* x) { /* nothing to do */ };
void do_MemBar (MemBar* x) { /* nothing to do */ };

View File

@ -102,6 +102,7 @@ friend class ciMethodData; \
friend class ciMethodHandle; \
friend class ciMethodType; \
friend class ciReceiverTypeData; \
friend class ciTypeEntries; \
friend class ciSymbol; \
friend class ciArray; \
friend class ciObjArray; \

View File

@ -1154,9 +1154,12 @@ ciInstance* ciEnv::unloaded_ciinstance() {
GUARDED_VM_ENTRY(return _factory->get_unloaded_object_constant();)
}
void ciEnv::dump_replay_data(outputStream* out) {
VM_ENTRY_MARK;
MutexLocker ml(Compile_lock);
// ------------------------------------------------------------------
// ciEnv::dump_replay_data*
// Don't change thread state and acquire any locks.
// Safe to call from VM error reporter.
void ciEnv::dump_replay_data_unsafe(outputStream* out) {
ResourceMark rm;
#if INCLUDE_JVMTI
out->print_cr("JvmtiExport can_access_local_variables %d", _jvmti_can_access_local_variables);
@ -1181,3 +1184,10 @@ void ciEnv::dump_replay_data(outputStream* out) {
entry_bci, comp_level);
out->flush();
}
void ciEnv::dump_replay_data(outputStream* out) {
GUARDED_VM_ENTRY(
MutexLocker ml(Compile_lock);
dump_replay_data_unsafe(out);
)
}

View File

@ -452,6 +452,7 @@ public:
// Dump the compilation replay data for the ciEnv to the stream.
void dump_replay_data(outputStream* out);
void dump_replay_data_unsafe(outputStream* out);
};
#endif // SHARE_VM_CI_CIENV_HPP

View File

@ -671,7 +671,6 @@ class StaticFinalFieldPrinter : public FieldClosure {
void ciInstanceKlass::dump_replay_data(outputStream* out) {
ASSERT_IN_VM;
ResourceMark rm;
InstanceKlass* ik = get_instanceKlass();

View File

@ -235,6 +235,13 @@ public:
bool is_instance_klass() const { return true; }
bool is_java_klass() const { return true; }
virtual ciKlass* exact_klass() {
if (is_loaded() && is_final() && !is_interface()) {
return this;
}
return NULL;
}
// Dump the current state of this klass for compilation replay.
virtual void dump_replay_data(outputStream* out);
};

View File

@ -66,7 +66,9 @@ ciKlass::ciKlass(ciSymbol* name, BasicType bt) : ciType(bt) {
// ------------------------------------------------------------------
// ciKlass::is_subtype_of
bool ciKlass::is_subtype_of(ciKlass* that) {
assert(is_loaded() && that->is_loaded(), "must be loaded");
assert(this->is_loaded(), err_msg("must be loaded: %s", this->name()->as_quoted_ascii()));
assert(that->is_loaded(), err_msg("must be loaded: %s", that->name()->as_quoted_ascii()));
// Check to see if the klasses are identical.
if (this == that) {
return true;
@ -83,8 +85,8 @@ bool ciKlass::is_subtype_of(ciKlass* that) {
// ------------------------------------------------------------------
// ciKlass::is_subclass_of
bool ciKlass::is_subclass_of(ciKlass* that) {
assert(is_loaded() && that->is_loaded(), "must be loaded");
// Check to see if the klasses are identical.
assert(this->is_loaded(), err_msg("must be loaded: %s", this->name()->as_quoted_ascii()));
assert(that->is_loaded(), err_msg("must be loaded: %s", that->name()->as_quoted_ascii()));
VM_ENTRY_MARK;
Klass* this_klass = get_Klass();

View File

@ -41,6 +41,7 @@ class ciKlass : public ciType {
friend class ciEnv;
friend class ciField;
friend class ciMethod;
friend class ciMethodData;
friend class ciObjArrayKlass;
private:
@ -121,6 +122,8 @@ public:
// What kind of ciObject is this?
bool is_klass() const { return true; }
virtual ciKlass* exact_klass() = 0;
void print_name_on(outputStream* st);
};

View File

@ -846,7 +846,9 @@ bool ciMethod::has_member_arg() const {
// Return true if allocation was successful or no MDO is required.
bool ciMethod::ensure_method_data(methodHandle h_m) {
EXCEPTION_CONTEXT;
if (is_native() || is_abstract() || h_m()->is_accessor()) return true;
if (is_native() || is_abstract() || h_m()->is_accessor()) {
return true;
}
if (h_m()->method_data() == NULL) {
Method::build_interpreter_method_data(h_m, THREAD);
if (HAS_PENDING_EXCEPTION) {
@ -903,22 +905,21 @@ ciMethodData* ciMethod::method_data() {
// NULL otherwise.
ciMethodData* ciMethod::method_data_or_null() {
ciMethodData *md = method_data();
if (md->is_empty()) return NULL;
if (md->is_empty()) {
return NULL;
}
return md;
}
// ------------------------------------------------------------------
// ciMethod::ensure_method_counters
//
address ciMethod::ensure_method_counters() {
MethodCounters* ciMethod::ensure_method_counters() {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
MethodCounters *counter = mh->method_counters();
if (counter == NULL) {
counter = Method::build_method_counters(mh(), CHECK_AND_CLEAR_NULL);
}
return (address)counter;
MethodCounters* method_counters = mh->get_method_counters(CHECK_NULL);
return method_counters;
}
// ------------------------------------------------------------------
@ -1247,7 +1248,6 @@ ciMethodBlocks *ciMethod::get_method_blocks() {
#undef FETCH_FLAG_FROM_VM
void ciMethod::dump_replay_data(outputStream* st) {
ASSERT_IN_VM;
ResourceMark rm;
Method* method = get_Method();
MethodCounters* mcs = method->method_counters();

View File

@ -265,7 +265,7 @@ class ciMethod : public ciMetadata {
bool is_klass_loaded(int refinfo_index, bool must_be_resolved) const;
bool check_call(int refinfo_index, bool is_static) const;
bool ensure_method_data(); // make sure it exists in the VM also
address ensure_method_counters();
MethodCounters* ensure_method_counters();
int instructions_size();
int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC

View File

@ -78,7 +78,9 @@ ciMethodData::ciMethodData() : ciMetadata(NULL) {
void ciMethodData::load_data() {
MethodData* mdo = get_MethodData();
if (mdo == NULL) return;
if (mdo == NULL) {
return;
}
// To do: don't copy the data if it is not "ripe" -- require a minimum #
// of invocations.
@ -123,7 +125,7 @@ void ciMethodData::load_data() {
#endif
}
void ciReceiverTypeData::translate_receiver_data_from(ProfileData* data) {
void ciReceiverTypeData::translate_receiver_data_from(const ProfileData* data) {
for (uint row = 0; row < row_limit(); row++) {
Klass* k = data->as_ReceiverTypeData()->receiver(row);
if (k != NULL) {
@ -134,6 +136,18 @@ void ciReceiverTypeData::translate_receiver_data_from(ProfileData* data) {
}
void ciTypeStackSlotEntries::translate_type_data_from(const TypeStackSlotEntries* entries) {
for (int i = 0; i < _number_of_entries; i++) {
intptr_t k = entries->type(i);
TypeStackSlotEntries::set_type(i, translate_klass(k));
}
}
void ciReturnTypeEntry::translate_type_data_from(const ReturnTypeEntry* ret) {
intptr_t k = ret->type();
set_type(translate_klass(k));
}
// Get the data at an arbitrary (sort of) data index.
ciProfileData* ciMethodData::data_at(int data_index) {
if (out_of_bounds(data_index)) {
@ -164,6 +178,10 @@ ciProfileData* ciMethodData::data_at(int data_index) {
return new ciMultiBranchData(data_layout);
case DataLayout::arg_info_data_tag:
return new ciArgInfoData(data_layout);
case DataLayout::call_type_data_tag:
return new ciCallTypeData(data_layout);
case DataLayout::virtual_call_type_data_tag:
return new ciVirtualCallTypeData(data_layout);
};
}
@ -286,6 +304,34 @@ 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());
}
}
}
void ciMethodData::set_return_type(int bci, 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_return_type(k->get_Klass());
} else {
assert(data->is_VirtualCallTypeData(), "no arguments!");
data->as_VirtualCallTypeData()->set_return_type(k->get_Klass());
}
}
}
bool ciMethodData::has_escape_info() {
return eflag_set(MethodData::estimated);
}
@ -373,7 +419,6 @@ void ciMethodData::print_impl(outputStream* st) {
}
void ciMethodData::dump_replay_data(outputStream* out) {
ASSERT_IN_VM;
ResourceMark rm;
MethodData* mdo = get_MethodData();
Method* method = mdo->method();
@ -477,7 +522,50 @@ 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 {
for (int i = 0; i < _number_of_entries; i++) {
_pd->tab(st);
st->print("%d: stack (%u) ", i, stack_slot(i));
print_ciklass(st, type(i));
st->cr();
}
}
void ciReturnTypeEntry::print_data_on(outputStream* st) const {
_pd->tab(st);
st->print("ret ");
print_ciklass(st, type());
st->cr();
}
void ciCallTypeData::print_data_on(outputStream* st) const {
print_shared(st, "ciCallTypeData");
if (has_arguments()) {
tab(st, true);
st->print("argument types");
args()->print_data_on(st);
}
if (has_return()) {
tab(st, true);
st->print("return type");
ret()->print_data_on(st);
}
}
void ciReceiverTypeData::print_receiver_data_on(outputStream* st) const {
uint row;
int entries = 0;
for (row = 0; row < row_limit(); row++) {
@ -493,13 +581,28 @@ void ciReceiverTypeData::print_receiver_data_on(outputStream* st) {
}
}
void ciReceiverTypeData::print_data_on(outputStream* st) {
void ciReceiverTypeData::print_data_on(outputStream* st) const {
print_shared(st, "ciReceiverTypeData");
print_receiver_data_on(st);
}
void ciVirtualCallData::print_data_on(outputStream* st) {
void ciVirtualCallData::print_data_on(outputStream* st) const {
print_shared(st, "ciVirtualCallData");
rtd_super()->print_receiver_data_on(st);
}
void ciVirtualCallTypeData::print_data_on(outputStream* st) const {
print_shared(st, "ciVirtualCallTypeData");
rtd_super()->print_receiver_data_on(st);
if (has_arguments()) {
tab(st, true);
st->print("argument types");
args()->print_data_on(st);
}
if (has_return()) {
tab(st, true);
st->print("return type");
ret()->print_data_on(st);
}
}
#endif

View File

@ -41,6 +41,8 @@ class ciBranchData;
class ciArrayData;
class ciMultiBranchData;
class ciArgInfoData;
class ciCallTypeData;
class ciVirtualCallTypeData;
typedef ProfileData ciProfileData;
@ -59,6 +61,103 @@ public:
ciJumpData(DataLayout* layout) : JumpData(layout) {};
};
class ciTypeEntries {
protected:
static intptr_t translate_klass(intptr_t k) {
Klass* v = TypeEntries::valid_klass(k);
if (v != NULL) {
ciKlass* klass = CURRENT_ENV->get_klass(v);
return with_status(klass, k);
}
return with_status(NULL, k);
}
public:
static ciKlass* valid_ciklass(intptr_t k) {
if (!TypeEntries::is_type_none(k) &&
!TypeEntries::is_type_unknown(k)) {
return (ciKlass*)TypeEntries::klass_part(k);
} else {
return NULL;
}
}
static intptr_t with_status(ciKlass* k, intptr_t in) {
return TypeEntries::with_status((intptr_t)k, in);
}
#ifndef PRODUCT
static void print_ciklass(outputStream* st, intptr_t k);
#endif
};
class ciTypeStackSlotEntries : public TypeStackSlotEntries, ciTypeEntries {
public:
void translate_type_data_from(const TypeStackSlotEntries* args);
ciKlass* valid_type(int i) const {
return valid_ciklass(type(i));
}
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
#endif
};
class ciReturnTypeEntry : public ReturnTypeEntry, ciTypeEntries {
public:
void translate_type_data_from(const ReturnTypeEntry* ret);
ciKlass* valid_type() const {
return valid_ciklass(type());
}
#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(); }
ciReturnTypeEntry* ret() const { return (ciReturnTypeEntry*)CallTypeData::ret(); }
void translate_type_data_from(const ProfileData* data) {
if (has_arguments()) {
args()->translate_type_data_from(data->as_CallTypeData()->args());
}
if (has_return()) {
ret()->translate_type_data_from(data->as_CallTypeData()->ret());
}
}
intptr_t argument_type(int i) const {
assert(has_arguments(), "no arg type profiling data");
return args()->type(i);
}
ciKlass* valid_argument_type(int i) const {
assert(has_arguments(), "no arg type profiling data");
return args()->valid_type(i);
}
intptr_t return_type() const {
assert(has_return(), "no ret type profiling data");
return ret()->type();
}
ciKlass* valid_return_type() const {
assert(has_return(), "no ret type profiling data");
return ret()->valid_type();
}
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
#endif
};
class ciReceiverTypeData : public ReceiverTypeData {
public:
ciReceiverTypeData(DataLayout* layout) : ReceiverTypeData(layout) {};
@ -69,7 +168,7 @@ public:
(intptr_t) recv);
}
ciKlass* receiver(uint row) {
ciKlass* receiver(uint row) const {
assert((uint)row < row_limit(), "oob");
ciKlass* recv = (ciKlass*)intptr_at(receiver0_offset + row * receiver_type_row_cell_count);
assert(recv == NULL || recv->is_klass(), "wrong type");
@ -77,19 +176,19 @@ public:
}
// Copy & translate from oop based ReceiverTypeData
virtual void translate_from(ProfileData* data) {
virtual void translate_from(const ProfileData* data) {
translate_receiver_data_from(data);
}
void translate_receiver_data_from(ProfileData* data);
void translate_receiver_data_from(const ProfileData* data);
#ifndef PRODUCT
void print_data_on(outputStream* st);
void print_receiver_data_on(outputStream* st);
void print_data_on(outputStream* st) const;
void print_receiver_data_on(outputStream* st) const;
#endif
};
class ciVirtualCallData : public VirtualCallData {
// Fake multiple inheritance... It's a ciReceiverTypeData also.
ciReceiverTypeData* rtd_super() { return (ciReceiverTypeData*) this; }
ciReceiverTypeData* rtd_super() const { return (ciReceiverTypeData*) this; }
public:
ciVirtualCallData(DataLayout* layout) : VirtualCallData(layout) {};
@ -103,11 +202,65 @@ public:
}
// Copy & translate from oop based VirtualCallData
virtual void translate_from(ProfileData* data) {
virtual void translate_from(const ProfileData* data) {
rtd_super()->translate_receiver_data_from(data);
}
#ifndef PRODUCT
void print_data_on(outputStream* st);
void print_data_on(outputStream* st) const;
#endif
};
class ciVirtualCallTypeData : public VirtualCallTypeData {
private:
// Fake multiple inheritance... It's a ciReceiverTypeData also.
ciReceiverTypeData* rtd_super() const { return (ciReceiverTypeData*) this; }
public:
ciVirtualCallTypeData(DataLayout* layout) : VirtualCallTypeData(layout) {}
void set_receiver(uint row, ciKlass* recv) {
rtd_super()->set_receiver(row, recv);
}
ciKlass* receiver(uint row) const {
return rtd_super()->receiver(row);
}
ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)VirtualCallTypeData::args(); }
ciReturnTypeEntry* ret() const { return (ciReturnTypeEntry*)VirtualCallTypeData::ret(); }
// Copy & translate from oop based VirtualCallData
virtual void translate_from(const ProfileData* data) {
rtd_super()->translate_receiver_data_from(data);
if (has_arguments()) {
args()->translate_type_data_from(data->as_VirtualCallTypeData()->args());
}
if (has_return()) {
ret()->translate_type_data_from(data->as_VirtualCallTypeData()->ret());
}
}
intptr_t argument_type(int i) const {
assert(has_arguments(), "no arg type profiling data");
return args()->type(i);
}
ciKlass* valid_argument_type(int i) const {
assert(has_arguments(), "no arg type profiling data");
return args()->valid_type(i);
}
intptr_t return_type() const {
assert(has_return(), "no ret type profiling data");
return ret()->type();
}
ciKlass* valid_return_type() const {
assert(has_return(), "no ret type profiling data");
return ret()->valid_type();
}
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
#endif
};
@ -232,8 +385,6 @@ private:
public:
bool is_method_data() const { return true; }
void set_mature() { _state = mature_state; }
bool is_empty() { return _state == empty_state; }
bool is_mature() { return _state == mature_state; }
@ -249,6 +400,10 @@ public:
// Also set the numer of loops and blocks in the method.
// Again, this is used to determine if a method is trivial.
void set_compilation_stats(short loops, short blocks);
// If the compiler finds a profiled type that is known statically
// for sure, set it in the MethodData
void set_argument_type(int bci, int i, ciKlass* k);
void set_return_type(int bci, ciKlass* k);
void load_data();

View File

@ -179,3 +179,16 @@ ciObjArrayKlass* ciObjArrayKlass::make_impl(ciKlass* element_klass) {
ciObjArrayKlass* ciObjArrayKlass::make(ciKlass* element_klass) {
GUARDED_VM_ENTRY(return make_impl(element_klass);)
}
ciKlass* ciObjArrayKlass::exact_klass() {
ciType* base = base_element_type();
if (base->is_instance_klass()) {
ciInstanceKlass* ik = base->as_instance_klass();
if (ik->exact_klass() != NULL) {
return this;
}
} else if (base->is_primitive_type()) {
return this;
}
return NULL;
}

View File

@ -73,6 +73,8 @@ public:
bool is_obj_array_klass() const { return true; }
static ciObjArrayKlass* make(ciKlass* element_klass);
virtual ciKlass* exact_klass();
};
#endif // SHARE_VM_CI_CIOBJARRAYKLASS_HPP

View File

@ -965,14 +965,12 @@ void ciReplay::initialize(ciMethod* m) {
tty->cr();
} else {
EXCEPTION_CONTEXT;
MethodCounters* mcs = method->method_counters();
// m->_instructions_size = rec->instructions_size;
m->_instructions_size = -1;
m->_interpreter_invocation_count = rec->interpreter_invocation_count;
m->_interpreter_throwout_count = rec->interpreter_throwout_count;
if (mcs == NULL) {
mcs = Method::build_method_counters(method, CHECK_AND_CLEAR);
}
MethodCounters* mcs = method->get_method_counters(CHECK_AND_CLEAR);
guarantee(mcs != NULL, "method counters allocation failed");
mcs->invocation_counter()->_counter = rec->invocation_counter;
mcs->backedge_counter()->_counter = rec->backedge_counter;
}

View File

@ -277,11 +277,14 @@ public:
class ciSignatureStream : public StackObj {
private:
ciSignature* _sig;
int _pos;
int _pos;
// holder is a method's holder
ciKlass* _holder;
public:
ciSignatureStream(ciSignature* signature) {
ciSignatureStream(ciSignature* signature, ciKlass* holder = NULL) {
_sig = signature;
_pos = 0;
_holder = holder;
}
bool at_return_type() { return _pos == _sig->count(); }
@ -301,6 +304,23 @@ public:
return _sig->type_at(_pos);
}
}
// next klass in the signature
ciKlass* next_klass() {
ciKlass* sig_k;
if (_holder != NULL) {
sig_k = _holder;
_holder = NULL;
} else {
while (!type()->is_klass()) {
next();
}
assert(!at_return_type(), "passed end of signature");
sig_k = type()->as_klass();
next();
}
return sig_k;
}
};

View File

@ -57,6 +57,10 @@ public:
// Make an array klass corresponding to the specified primitive type.
static ciTypeArrayKlass* make(BasicType type);
virtual ciKlass* exact_klass() {
return this;
}
};
#endif // SHARE_VM_CI_CITYPEARRAYKLASS_HPP

View File

@ -857,7 +857,6 @@ static Method* new_method(
m->set_max_locals(params);
m->constMethod()->set_stackmap_data(NULL);
m->set_code(code_start);
m->set_force_inline(true);
return m;
}

View File

@ -245,8 +245,8 @@ BufferBlob* BufferBlob::create(const char* name, CodeBuffer* cb) {
}
void* BufferBlob::operator new(size_t s, unsigned size) throw() {
void* p = CodeCache::allocate(size);
void* BufferBlob::operator new(size_t s, unsigned size, bool is_critical) throw() {
void* p = CodeCache::allocate(size, is_critical);
return p;
}
@ -277,7 +277,10 @@ AdapterBlob* AdapterBlob::create(CodeBuffer* cb) {
unsigned int size = allocation_size(cb, sizeof(AdapterBlob));
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
blob = new (size) AdapterBlob(size, cb);
// The parameter 'true' indicates a critical memory allocation.
// This means that CodeCacheMinimumFreeSpace is used, if necessary
const bool is_critical = true;
blob = new (size, is_critical) AdapterBlob(size, cb);
}
// Track memory usage statistic after releasing CodeCache_lock
MemoryService::track_code_cache_memory_usage();
@ -299,7 +302,10 @@ MethodHandlesAdapterBlob* MethodHandlesAdapterBlob::create(int buffer_size) {
size += round_to(buffer_size, oopSize);
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
blob = new (size) MethodHandlesAdapterBlob(size);
// The parameter 'true' indicates a critical memory allocation.
// This means that CodeCacheMinimumFreeSpace is used, if necessary
const bool is_critical = true;
blob = new (size, is_critical) MethodHandlesAdapterBlob(size);
}
// Track memory usage statistic after releasing CodeCache_lock
MemoryService::track_code_cache_memory_usage();

View File

@ -209,7 +209,7 @@ class BufferBlob: public CodeBlob {
BufferBlob(const char* name, int size);
BufferBlob(const char* name, int size, CodeBuffer* cb);
void* operator new(size_t s, unsigned size) throw();
void* operator new(size_t s, unsigned size, bool is_critical = false) throw();
public:
// Creation
@ -253,7 +253,6 @@ public:
class MethodHandlesAdapterBlob: public BufferBlob {
private:
MethodHandlesAdapterBlob(int size) : BufferBlob("MethodHandles adapters", size) {}
MethodHandlesAdapterBlob(int size, CodeBuffer* cb) : BufferBlob("MethodHandles adapters", size, cb) {}
public:
// Creation

View File

@ -24,41 +24,42 @@
#include "precompiled.hpp"
#include "compiler/abstractCompiler.hpp"
#include "compiler/compileBroker.hpp"
#include "runtime/mutexLocker.hpp"
void AbstractCompiler::initialize_runtimes(initializer f, volatile int* state) {
if (*state != initialized) {
// We are thread in native here...
CompilerThread* thread = CompilerThread::current();
bool do_initialization = false;
{
ThreadInVMfromNative tv(thread);
ResetNoHandleMark rnhm;
MutexLocker only_one(CompileThread_lock, thread);
if ( *state == uninitialized) {
do_initialization = true;
*state = initializing;
} else {
while (*state == initializing ) {
CompileThread_lock->wait();
}
bool AbstractCompiler::should_perform_init() {
if (_compiler_state != initialized) {
MutexLocker only_one(CompileThread_lock);
if (_compiler_state == uninitialized) {
_compiler_state = initializing;
return true;
} else {
while (_compiler_state == initializing) {
CompileThread_lock->wait();
}
}
if (do_initialization) {
// We can not hold any locks here since JVMTI events may call agents
// Compiler(s) run as native
(*f)();
// To in_vm so we can use the lock
ThreadInVMfromNative tv(thread);
ResetNoHandleMark rnhm;
MutexLocker only_one(CompileThread_lock, thread);
assert(*state == initializing, "wrong state");
*state = initialized;
CompileThread_lock->notify_all();
}
}
return false;
}
bool AbstractCompiler::should_perform_shutdown() {
// Since this method can be called by multiple threads, the lock ensures atomicity of
// decrementing '_num_compiler_threads' and the following operations.
MutexLocker only_one(CompileThread_lock);
_num_compiler_threads--;
assert (CompileBroker::is_compilation_disabled_forever(), "Must be set, otherwise thread waits forever");
// Only the last thread will perform shutdown operations
if (_num_compiler_threads == 0) {
return true;
}
return false;
}
void AbstractCompiler::set_state(int state) {
// Ensure that ste is only set by one thread at a time
MutexLocker only_one(CompileThread_lock);
_compiler_state = state;
CompileThread_lock->notify_all();
}

View File

@ -27,22 +27,25 @@
#include "ci/compilerInterface.hpp"
typedef void (*initializer)(void);
class AbstractCompiler : public CHeapObj<mtCompiler> {
private:
bool _is_initialized; // Mark whether compiler object is initialized
volatile int _num_compiler_threads;
protected:
volatile int _compiler_state;
// Used for tracking global state of compiler runtime initialization
enum { uninitialized, initializing, initialized };
enum { uninitialized, initializing, initialized, failed, shut_down };
// This method will call the initialization method "f" once (per compiler class/subclass)
// and do so without holding any locks
void initialize_runtimes(initializer f, volatile int* state);
// This method returns true for the first compiler thread that reaches that methods.
// This thread will initialize the compiler runtime.
bool should_perform_init();
public:
AbstractCompiler() : _is_initialized(false) {}
AbstractCompiler() : _compiler_state(uninitialized), _num_compiler_threads(0) {}
// This function determines the compiler thread that will perform the
// shutdown of the corresponding compiler runtime.
bool should_perform_shutdown();
// Name of this compiler
virtual const char* name() = 0;
@ -74,17 +77,18 @@ class AbstractCompiler : public CHeapObj<mtCompiler> {
#endif // TIERED
// Customization
virtual bool needs_stubs () = 0;
virtual void initialize () = 0;
void mark_initialized() { _is_initialized = true; }
bool is_initialized() { return _is_initialized; }
virtual void initialize() = 0;
void set_num_compiler_threads(int num) { _num_compiler_threads = num; }
int num_compiler_threads() { return _num_compiler_threads; }
// Get/set state of compiler objects
bool is_initialized() { return _compiler_state == initialized; }
bool is_failed () { return _compiler_state == failed;}
void set_state (int state);
void set_shut_down () { set_state(shut_down); }
// Compilation entry point for methods
virtual void compile_method(ciEnv* env,
ciMethod* target,
int entry_bci) {
virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci) {
ShouldNotReachHere();
}

View File

@ -186,7 +186,7 @@ CompileQueue* CompileBroker::_c2_method_queue = NULL;
CompileQueue* CompileBroker::_c1_method_queue = NULL;
CompileTask* CompileBroker::_task_free_list = NULL;
GrowableArray<CompilerThread*>* CompileBroker::_method_threads = NULL;
GrowableArray<CompilerThread*>* CompileBroker::_compiler_threads = NULL;
class CompilationLog : public StringEventLog {
@ -587,9 +587,6 @@ void CompileTask::log_task_done(CompileLog* log) {
// ------------------------------------------------------------------
// CompileQueue::add
//
// Add a CompileTask to a CompileQueue
void CompileQueue::add(CompileTask* task) {
assert(lock()->owned_by_self(), "must own lock");
@ -626,6 +623,16 @@ void CompileQueue::add(CompileTask* task) {
lock()->notify_all();
}
void CompileQueue::delete_all() {
assert(lock()->owned_by_self(), "must own lock");
if (_first != NULL) {
for (CompileTask* task = _first; task != NULL; task = task->next()) {
delete task;
}
_first = NULL;
}
}
// ------------------------------------------------------------------
// CompileQueue::get
//
@ -640,6 +647,11 @@ CompileTask* CompileQueue::get() {
// case we perform code cache sweeps to free memory such that we can re-enable
// compilation.
while (_first == NULL) {
// Exit loop if compilation is disabled forever
if (CompileBroker::is_compilation_disabled_forever()) {
return NULL;
}
if (UseCodeCacheFlushing && !CompileBroker::should_compile_new_jobs()) {
// Wait a certain amount of time to possibly do another sweep.
// We must wait until stack scanning has happened so that we can
@ -664,9 +676,17 @@ CompileTask* CompileQueue::get() {
// remains unchanged. This behavior is desired, since we want to keep
// the stable state, i.e., we do not want to evict methods from the
// code cache if it is unnecessary.
lock()->wait();
// We need a timed wait here, since compiler threads can exit if compilation
// is disabled forever. We use 5 seconds wait time; the exiting of compiler threads
// is not critical and we do not want idle compiler threads to wake up too often.
lock()->wait(!Mutex::_no_safepoint_check_flag, 5*1000);
}
}
if (CompileBroker::is_compilation_disabled_forever()) {
return NULL;
}
CompileTask* task = CompilationPolicy::policy()->select_task(this);
remove(task);
return task;
@ -891,10 +911,8 @@ void CompileBroker::compilation_init() {
}
// ------------------------------------------------------------------
// CompileBroker::make_compiler_thread
CompilerThread* CompileBroker::make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, TRAPS) {
CompilerThread* CompileBroker::make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters,
AbstractCompiler* comp, TRAPS) {
CompilerThread* compiler_thread = NULL;
Klass* k =
@ -961,6 +979,7 @@ CompilerThread* CompileBroker::make_compiler_thread(const char* name, CompileQue
java_lang_Thread::set_daemon(thread_oop());
compiler_thread->set_threadObj(thread_oop());
compiler_thread->set_compiler(comp);
Threads::add(compiler_thread);
Thread::start(compiler_thread);
}
@ -972,25 +991,24 @@ CompilerThread* CompileBroker::make_compiler_thread(const char* name, CompileQue
}
// ------------------------------------------------------------------
// CompileBroker::init_compiler_threads
//
// Initialize the compilation queue
void CompileBroker::init_compiler_threads(int c1_compiler_count, int c2_compiler_count) {
EXCEPTION_MARK;
#if !defined(ZERO) && !defined(SHARK)
assert(c2_compiler_count > 0 || c1_compiler_count > 0, "No compilers?");
#endif // !ZERO && !SHARK
// Initialize the compilation queue
if (c2_compiler_count > 0) {
_c2_method_queue = new CompileQueue("C2MethodQueue", MethodCompileQueue_lock);
_compilers[1]->set_num_compiler_threads(c2_compiler_count);
}
if (c1_compiler_count > 0) {
_c1_method_queue = new CompileQueue("C1MethodQueue", MethodCompileQueue_lock);
_compilers[0]->set_num_compiler_threads(c1_compiler_count);
}
int compiler_count = c1_compiler_count + c2_compiler_count;
_method_threads =
_compiler_threads =
new (ResourceObj::C_HEAP, mtCompiler) GrowableArray<CompilerThread*>(compiler_count, true);
char name_buffer[256];
@ -998,21 +1016,22 @@ void CompileBroker::init_compiler_threads(int c1_compiler_count, int c2_compiler
// Create a name for our thread.
sprintf(name_buffer, "C2 CompilerThread%d", i);
CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK);
CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_method_queue, counters, CHECK);
_method_threads->append(new_thread);
// Shark and C2
CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_method_queue, counters, _compilers[1], CHECK);
_compiler_threads->append(new_thread);
}
for (int i = c2_compiler_count; i < compiler_count; i++) {
// Create a name for our thread.
sprintf(name_buffer, "C1 CompilerThread%d", i);
CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK);
CompilerThread* new_thread = make_compiler_thread(name_buffer, _c1_method_queue, counters, CHECK);
_method_threads->append(new_thread);
// C1
CompilerThread* new_thread = make_compiler_thread(name_buffer, _c1_method_queue, counters, _compilers[0], CHECK);
_compiler_threads->append(new_thread);
}
if (UsePerfData) {
PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes,
compiler_count, CHECK);
PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes, compiler_count, CHECK);
}
}
@ -1028,27 +1047,6 @@ void CompileBroker::mark_on_stack() {
}
}
// ------------------------------------------------------------------
// CompileBroker::is_idle
bool CompileBroker::is_idle() {
if (_c2_method_queue != NULL && !_c2_method_queue->is_empty()) {
return false;
} else if (_c1_method_queue != NULL && !_c1_method_queue->is_empty()) {
return false;
} else {
int num_threads = _method_threads->length();
for (int i=0; i<num_threads; i++) {
if (_method_threads->at(i)->task() != NULL) {
return false;
}
}
// No pending or active compilations.
return true;
}
}
// ------------------------------------------------------------------
// CompileBroker::compile_method
//
@ -1551,6 +1549,101 @@ void CompileBroker::wait_for_completion(CompileTask* task) {
free_task(task);
}
// Initialize compiler thread(s) + compiler object(s). The postcondition
// of this function is that the compiler runtimes are initialized and that
//compiler threads can start compiling.
bool CompileBroker::init_compiler_runtime() {
CompilerThread* thread = CompilerThread::current();
AbstractCompiler* comp = thread->compiler();
// Final sanity check - the compiler object must exist
guarantee(comp != NULL, "Compiler object must exist");
int system_dictionary_modification_counter;
{
MutexLocker locker(Compile_lock, thread);
system_dictionary_modification_counter = SystemDictionary::number_of_modifications();
}
{
// Must switch to native to allocate ci_env
ThreadToNativeFromVM ttn(thread);
ciEnv ci_env(NULL, system_dictionary_modification_counter);
// Cache Jvmti state
ci_env.cache_jvmti_state();
// Cache DTrace flags
ci_env.cache_dtrace_flags();
// Switch back to VM state to do compiler initialization
ThreadInVMfromNative tv(thread);
ResetNoHandleMark rnhm;
if (!comp->is_shark()) {
// Perform per-thread and global initializations
comp->initialize();
}
}
if (comp->is_failed()) {
disable_compilation_forever();
// If compiler initialization failed, no compiler thread that is specific to a
// particular compiler runtime will ever start to compile methods.
shutdown_compiler_runtime(comp, thread);
return false;
}
// C1 specific check
if (comp->is_c1() && (thread->get_buffer_blob() == NULL)) {
warning("Initialization of %s thread failed (no space to run compilers)", thread->name());
return false;
}
return true;
}
// If C1 and/or C2 initialization failed, we shut down all compilation.
// We do this to keep things simple. This can be changed if it ever turns out to be
// a problem.
void CompileBroker::shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread) {
// Free buffer blob, if allocated
if (thread->get_buffer_blob() != NULL) {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
CodeCache::free(thread->get_buffer_blob());
}
if (comp->should_perform_shutdown()) {
// There are two reasons for shutting down the compiler
// 1) compiler runtime initialization failed
// 2) The code cache is full and the following flag is set: -XX:-UseCodeCacheFlushing
warning("Shutting down compiler %s (no space to run compilers)", comp->name());
// Only one thread per compiler runtime object enters here
// Set state to shut down
comp->set_shut_down();
MutexLocker mu(MethodCompileQueue_lock, thread);
CompileQueue* queue;
if (_c1_method_queue != NULL) {
_c1_method_queue->delete_all();
queue = _c1_method_queue;
_c1_method_queue = NULL;
delete _c1_method_queue;
}
if (_c2_method_queue != NULL) {
_c2_method_queue->delete_all();
queue = _c2_method_queue;
_c2_method_queue = NULL;
delete _c2_method_queue;
}
// We could delete compiler runtimes also. However, there are references to
// the compiler runtime(s) (e.g., nmethod::is_compiled_by_c1()) which then
// fail. This can be done later if necessary.
}
}
// ------------------------------------------------------------------
// CompileBroker::compiler_thread_loop
//
@ -1558,7 +1651,6 @@ void CompileBroker::wait_for_completion(CompileTask* task) {
void CompileBroker::compiler_thread_loop() {
CompilerThread* thread = CompilerThread::current();
CompileQueue* queue = thread->queue();
// For the thread that initializes the ciObjectFactory
// this resource mark holds all the shared objects
ResourceMark rm;
@ -1587,64 +1679,77 @@ void CompileBroker::compiler_thread_loop() {
log->end_elem();
}
while (true) {
{
// We need this HandleMark to avoid leaking VM handles.
HandleMark hm(thread);
// If compiler thread/runtime initialization fails, exit the compiler thread
if (!init_compiler_runtime()) {
return;
}
if (CodeCache::unallocated_capacity() < CodeCacheMinimumFreeSpace) {
// the code cache is really full
handle_full_code_cache();
}
// Poll for new compilation tasks as long as the JVM runs. Compilation
// should only be disabled if something went wrong while initializing the
// compiler runtimes. This, in turn, should not happen. The only known case
// when compiler runtime initialization fails is if there is not enough free
// space in the code cache to generate the necessary stubs, etc.
while (!is_compilation_disabled_forever()) {
// We need this HandleMark to avoid leaking VM handles.
HandleMark hm(thread);
CompileTask* task = queue->get();
if (CodeCache::unallocated_capacity() < CodeCacheMinimumFreeSpace) {
// the code cache is really full
handle_full_code_cache();
}
// Give compiler threads an extra quanta. They tend to be bursty and
// this helps the compiler to finish up the job.
if( CompilerThreadHintNoPreempt )
os::hint_no_preempt();
CompileTask* task = queue->get();
if (task == NULL) {
continue;
}
// trace per thread time and compile statistics
CompilerCounters* counters = ((CompilerThread*)thread)->counters();
PerfTraceTimedEvent(counters->time_counter(), counters->compile_counter());
// Give compiler threads an extra quanta. They tend to be bursty and
// this helps the compiler to finish up the job.
if( CompilerThreadHintNoPreempt )
os::hint_no_preempt();
// Assign the task to the current thread. Mark this compilation
// thread as active for the profiler.
CompileTaskWrapper ctw(task);
nmethodLocker result_handle; // (handle for the nmethod produced by this task)
task->set_code_handle(&result_handle);
methodHandle method(thread, task->method());
// trace per thread time and compile statistics
CompilerCounters* counters = ((CompilerThread*)thread)->counters();
PerfTraceTimedEvent(counters->time_counter(), counters->compile_counter());
// Never compile a method if breakpoints are present in it
if (method()->number_of_breakpoints() == 0) {
// Compile the method.
if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) {
// Assign the task to the current thread. Mark this compilation
// thread as active for the profiler.
CompileTaskWrapper ctw(task);
nmethodLocker result_handle; // (handle for the nmethod produced by this task)
task->set_code_handle(&result_handle);
methodHandle method(thread, task->method());
// Never compile a method if breakpoints are present in it
if (method()->number_of_breakpoints() == 0) {
// Compile the method.
if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) {
#ifdef COMPILER1
// Allow repeating compilations for the purpose of benchmarking
// compile speed. This is not useful for customers.
if (CompilationRepeat != 0) {
int compile_count = CompilationRepeat;
while (compile_count > 0) {
invoke_compiler_on_method(task);
nmethod* nm = method->code();
if (nm != NULL) {
nm->make_zombie();
method->clear_code();
}
compile_count--;
// Allow repeating compilations for the purpose of benchmarking
// compile speed. This is not useful for customers.
if (CompilationRepeat != 0) {
int compile_count = CompilationRepeat;
while (compile_count > 0) {
invoke_compiler_on_method(task);
nmethod* nm = method->code();
if (nm != NULL) {
nm->make_zombie();
method->clear_code();
}
compile_count--;
}
#endif /* COMPILER1 */
invoke_compiler_on_method(task);
} else {
// After compilation is disabled, remove remaining methods from queue
method->clear_queued_for_compilation();
}
#endif /* COMPILER1 */
invoke_compiler_on_method(task);
} else {
// After compilation is disabled, remove remaining methods from queue
method->clear_queued_for_compilation();
}
}
}
}
// Shut down compiler runtime
shutdown_compiler_runtime(thread->compiler(), thread);
}
// ------------------------------------------------------------------
// CompileBroker::init_compiler_thread_log
@ -1953,11 +2058,14 @@ void CompileBroker::handle_full_code_cache() {
// Since code cache is full, immediately stop new compiles
if (CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation)) {
NMethodSweeper::log_sweep("disable_compiler");
// Switch to 'vm_state'. This ensures that possibly_sweep() can be called
// without having to consider the state in which the current thread is.
ThreadInVMfromUnknown in_vm;
NMethodSweeper::possibly_sweep();
}
} else {
UseCompiler = false;
AlwaysCompileLoopMethods = false;
disable_compilation_forever();
}
}
codecache_print(/* detailed= */ true);

View File

@ -213,8 +213,12 @@ class CompileQueue : public CHeapObj<mtCompiler> {
// Redefine Classes support
void mark_on_stack();
void delete_all();
void print();
~CompileQueue() {
assert (is_empty(), " Compile Queue must be empty");
}
};
// CompileTaskWrapper
@ -266,7 +270,7 @@ class CompileBroker: AllStatic {
static CompileQueue* _c1_method_queue;
static CompileTask* _task_free_list;
static GrowableArray<CompilerThread*>* _method_threads;
static GrowableArray<CompilerThread*>* _compiler_threads;
// performance counters
static PerfCounter* _perf_total_compilation;
@ -311,7 +315,7 @@ class CompileBroker: AllStatic {
static int _sum_nmethod_code_size;
static long _peak_compilation_time;
static CompilerThread* make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, TRAPS);
static CompilerThread* make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, AbstractCompiler* comp, TRAPS);
static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count);
static bool compilation_is_complete (methodHandle method, int osr_bci, int comp_level);
static bool compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level);
@ -351,6 +355,9 @@ class CompileBroker: AllStatic {
if (is_c1_compile(comp_level)) return _c1_method_queue;
return NULL;
}
static bool init_compiler_runtime();
static void shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread);
public:
enum {
// The entry bci used for non-OSR compilations.
@ -378,9 +385,7 @@ class CompileBroker: AllStatic {
const char* comment, Thread* thread);
static void compiler_thread_loop();
static uint get_compilation_id() { return _compilation_id; }
static bool is_idle();
// Set _should_block.
// Call this from the VM, with Threads_lock held and a safepoint requested.
@ -391,8 +396,9 @@ class CompileBroker: AllStatic {
enum {
// Flags for toggling compiler activity
stop_compilation = 0,
run_compilation = 1
stop_compilation = 0,
run_compilation = 1,
shutdown_compilaton = 2
};
static bool should_compile_new_jobs() { return UseCompiler && (_should_compile_new_jobs == run_compilation); }
@ -401,6 +407,16 @@ class CompileBroker: AllStatic {
jint old = Atomic::cmpxchg(new_state, &_should_compile_new_jobs, 1-new_state);
return (old == (1-new_state));
}
static void disable_compilation_forever() {
UseCompiler = false;
AlwaysCompileLoopMethods = false;
Atomic::xchg(shutdown_compilaton, &_should_compile_new_jobs);
}
static bool is_compilation_disabled_forever() {
return _should_compile_new_jobs == shutdown_compilaton;
}
static void handle_full_code_cache();
// Return total compilation ticks

View File

@ -805,6 +805,7 @@ class Method : public Metadata {
private:
void print_made_not_compilable(int comp_level, bool is_osr, bool report, const char* reason);
public:
MethodCounters* get_method_counters(TRAPS) {
if (_method_counters == NULL) {
build_method_counters(this, CHECK_AND_CLEAR_NULL);
@ -812,7 +813,6 @@ class Method : public Metadata {
return _method_counters;
}
public:
bool is_not_c1_compilable() const { return access_flags().is_not_c1_compilable(); }
void set_not_c1_compilable() { _access_flags.set_not_c1_compilable(); }
void clear_not_c1_compilable() { _access_flags.clear_not_c1_compilable(); }

View File

@ -56,6 +56,11 @@ void DataLayout::initialize(u1 tag, u2 bci, int cell_count) {
if (needs_array_len(tag)) {
set_cell_at(ArrayData::array_len_off_set, cell_count - 1); // -1 for header.
}
if (tag == call_type_data_tag) {
CallTypeData::initialize(this, cell_count);
} else if (tag == virtual_call_type_data_tag) {
VirtualCallTypeData::initialize(this, cell_count);
}
}
void DataLayout::clean_weak_klass_links(BoolObjectClosure* cl) {
@ -76,7 +81,7 @@ ProfileData::ProfileData() {
}
#ifndef PRODUCT
void ProfileData::print_shared(outputStream* st, const char* name) {
void ProfileData::print_shared(outputStream* st, const char* name) const {
st->print("bci: %d", bci());
st->fill_to(tab_width_one);
st->print("%s", name);
@ -91,8 +96,8 @@ void ProfileData::print_shared(outputStream* st, const char* name) {
st->print("flags(%d) ", flags);
}
void ProfileData::tab(outputStream* st) {
st->fill_to(tab_width_two);
void ProfileData::tab(outputStream* st, bool first) const {
st->fill_to(first ? tab_width_one : tab_width_two);
}
#endif // !PRODUCT
@ -104,7 +109,7 @@ void ProfileData::tab(outputStream* st) {
#ifndef PRODUCT
void BitData::print_data_on(outputStream* st) {
void BitData::print_data_on(outputStream* st) const {
print_shared(st, "BitData");
}
#endif // !PRODUCT
@ -115,7 +120,7 @@ void BitData::print_data_on(outputStream* st) {
// A CounterData corresponds to a simple counter.
#ifndef PRODUCT
void CounterData::print_data_on(outputStream* st) {
void CounterData::print_data_on(outputStream* st) const {
print_shared(st, "CounterData");
st->print_cr("count(%u)", count());
}
@ -145,12 +150,207 @@ void JumpData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
}
#ifndef PRODUCT
void JumpData::print_data_on(outputStream* st) {
void JumpData::print_data_on(outputStream* st) const {
print_shared(st, "JumpData");
st->print_cr("taken(%u) displacement(%d)", taken(), displacement());
}
#endif // !PRODUCT
int TypeStackSlotEntries::compute_cell_count(Symbol* signature, int max) {
ResourceMark rm;
SignatureStream ss(signature);
int args_count = MIN2(ss.reference_parameter_count(), max);
return args_count * per_arg_cell_count;
}
int TypeEntriesAtCall::compute_cell_count(BytecodeStream* stream) {
assert(Bytecodes::is_invoke(stream->code()), "should be invoke");
assert(TypeStackSlotEntries::per_arg_count() > ReturnTypeEntry::static_cell_count(), "code to test for arguments/results broken");
Bytecode_invoke inv(stream->method(), stream->bci());
int args_cell = 0;
if (arguments_profiling_enabled()) {
args_cell = TypeStackSlotEntries::compute_cell_count(inv.signature(), TypeProfileArgsLimit);
}
int ret_cell = 0;
if (return_profiling_enabled() && (inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY)) {
ret_cell = ReturnTypeEntry::static_cell_count();
}
int header_cell = 0;
if (args_cell + ret_cell > 0) {
header_cell = header_cell_count();
}
return header_cell + args_cell + ret_cell;
}
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(Symbol* signature, bool has_receiver) {
ResourceMark rm;
ArgumentOffsetComputer aos(signature, _number_of_entries);
aos.total();
for (int i = 0; i < _number_of_entries; i++) {
set_stack_slot(i, aos.off_at(i) + (has_receiver ? 1 : 0));
set_type(i, type_none());
}
}
void CallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
assert(Bytecodes::is_invoke(stream->code()), "should be invoke");
Bytecode_invoke inv(stream->method(), stream->bci());
SignatureStream ss(inv.signature());
if (has_arguments()) {
#ifdef ASSERT
ResourceMark rm;
int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit);
assert(count > 0, "room for args type but none found?");
check_number_of_arguments(count);
#endif
_args.post_initialize(inv.signature(), inv.has_receiver());
}
if (has_return()) {
assert(inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY, "room for a ret type but doesn't return obj?");
_ret.post_initialize();
}
}
void VirtualCallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
assert(Bytecodes::is_invoke(stream->code()), "should be invoke");
Bytecode_invoke inv(stream->method(), stream->bci());
if (has_arguments()) {
#ifdef ASSERT
ResourceMark rm;
SignatureStream ss(inv.signature());
int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit);
assert(count > 0, "room for args type but none found?");
check_number_of_arguments(count);
#endif
_args.post_initialize(inv.signature(), inv.has_receiver());
}
if (has_return()) {
assert(inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY, "room for a ret type but doesn't return obj?");
_ret.post_initialize();
}
}
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_entries; i++) {
intptr_t p = type(i);
if (is_loader_alive(is_alive_cl, p)) {
set_type(i, type_none());
}
}
}
void ReturnTypeEntry::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) {
intptr_t p = type();
if (is_loader_alive(is_alive_cl, p)) {
set_type(type_none());
}
}
bool TypeEntriesAtCall::return_profiling_enabled() {
return MethodData::profile_return();
}
bool TypeEntriesAtCall::arguments_profiling_enabled() {
return MethodData::profile_arguments();
}
#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 {
for (int i = 0; i < _number_of_entries; i++) {
_pd->tab(st);
st->print("%d: stack(%u) ", i, stack_slot(i));
print_klass(st, type(i));
st->cr();
}
}
void ReturnTypeEntry::print_data_on(outputStream* st) const {
_pd->tab(st);
print_klass(st, type());
st->cr();
}
void CallTypeData::print_data_on(outputStream* st) const {
CounterData::print_data_on(st);
if (has_arguments()) {
tab(st, true);
st->print("argument types");
_args.print_data_on(st);
}
if (has_return()) {
tab(st, true);
st->print("return type");
_ret.print_data_on(st);
}
}
void VirtualCallTypeData::print_data_on(outputStream* st) const {
VirtualCallData::print_data_on(st);
if (has_arguments()) {
tab(st, true);
st->print("argument types");
_args.print_data_on(st);
}
if (has_return()) {
tab(st, true);
st->print("return type");
_ret.print_data_on(st);
}
}
#endif
// ==================================================================
// ReceiverTypeData
//
@ -169,7 +369,7 @@ void ReceiverTypeData::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) {
}
#ifndef PRODUCT
void ReceiverTypeData::print_receiver_data_on(outputStream* st) {
void ReceiverTypeData::print_receiver_data_on(outputStream* st) const {
uint row;
int entries = 0;
for (row = 0; row < row_limit(); row++) {
@ -190,11 +390,11 @@ void ReceiverTypeData::print_receiver_data_on(outputStream* st) {
}
}
}
void ReceiverTypeData::print_data_on(outputStream* st) {
void ReceiverTypeData::print_data_on(outputStream* st) const {
print_shared(st, "ReceiverTypeData");
print_receiver_data_on(st);
}
void VirtualCallData::print_data_on(outputStream* st) {
void VirtualCallData::print_data_on(outputStream* st) const {
print_shared(st, "VirtualCallData");
print_receiver_data_on(st);
}
@ -246,7 +446,7 @@ address RetData::fixup_ret(int return_bci, MethodData* h_mdo) {
#ifndef PRODUCT
void RetData::print_data_on(outputStream* st) {
void RetData::print_data_on(outputStream* st) const {
print_shared(st, "RetData");
uint row;
int entries = 0;
@ -281,7 +481,7 @@ void BranchData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
}
#ifndef PRODUCT
void BranchData::print_data_on(outputStream* st) {
void BranchData::print_data_on(outputStream* st) const {
print_shared(st, "BranchData");
st->print_cr("taken(%u) displacement(%d)",
taken(), displacement());
@ -355,7 +555,7 @@ void MultiBranchData::post_initialize(BytecodeStream* stream,
}
#ifndef PRODUCT
void MultiBranchData::print_data_on(outputStream* st) {
void MultiBranchData::print_data_on(outputStream* st) const {
print_shared(st, "MultiBranchData");
st->print_cr("default_count(%u) displacement(%d)",
default_count(), default_displacement());
@ -369,7 +569,7 @@ void MultiBranchData::print_data_on(outputStream* st) {
#endif
#ifndef PRODUCT
void ArgInfoData::print_data_on(outputStream* st) {
void ArgInfoData::print_data_on(outputStream* st) const {
print_shared(st, "ArgInfoData");
int nargs = number_of_args();
for (int i = 0; i < nargs; i++) {
@ -407,7 +607,11 @@ int MethodData::bytecode_cell_count(Bytecodes::Code code) {
}
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
return CounterData::static_cell_count();
if (MethodData::profile_arguments() || MethodData::profile_return()) {
return variable_cell_count;
} else {
return CounterData::static_cell_count();
}
case Bytecodes::_goto:
case Bytecodes::_goto_w:
case Bytecodes::_jsr:
@ -415,9 +619,17 @@ int MethodData::bytecode_cell_count(Bytecodes::Code code) {
return JumpData::static_cell_count();
case Bytecodes::_invokevirtual:
case Bytecodes::_invokeinterface:
return VirtualCallData::static_cell_count();
if (MethodData::profile_arguments() || MethodData::profile_return()) {
return variable_cell_count;
} else {
return VirtualCallData::static_cell_count();
}
case Bytecodes::_invokedynamic:
return CounterData::static_cell_count();
if (MethodData::profile_arguments() || MethodData::profile_return()) {
return variable_cell_count;
} else {
return CounterData::static_cell_count();
}
case Bytecodes::_ret:
return RetData::static_cell_count();
case Bytecodes::_ifeq:
@ -453,7 +665,36 @@ int MethodData::compute_data_size(BytecodeStream* stream) {
return 0;
}
if (cell_count == variable_cell_count) {
cell_count = MultiBranchData::compute_cell_count(stream);
switch (stream->code()) {
case Bytecodes::_lookupswitch:
case Bytecodes::_tableswitch:
cell_count = MultiBranchData::compute_cell_count(stream);
break;
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
case Bytecodes::_invokedynamic:
assert(MethodData::profile_arguments() || MethodData::profile_return(), "should be collecting args profile");
if (profile_arguments_for_invoke(stream->method(), stream->bci()) ||
profile_return_for_invoke(stream->method(), stream->bci())) {
cell_count = CallTypeData::compute_cell_count(stream);
} else {
cell_count = CounterData::static_cell_count();
}
break;
case Bytecodes::_invokevirtual:
case Bytecodes::_invokeinterface: {
assert(MethodData::profile_arguments() || MethodData::profile_return(), "should be collecting args profile");
if (profile_arguments_for_invoke(stream->method(), stream->bci()) ||
profile_return_for_invoke(stream->method(), stream->bci())) {
cell_count = VirtualCallTypeData::compute_cell_count(stream);
} else {
cell_count = VirtualCallData::static_cell_count();
}
break;
}
default:
fatal("unexpected bytecode for var length profile data");
}
}
// Note: cell_count might be zero, meaning that there is just
// a DataLayout header, with no extra cells.
@ -499,6 +740,7 @@ int MethodData::compute_allocation_size_in_bytes(methodHandle method) {
// Add a cell to record information about modified arguments.
int arg_size = method->size_of_parameters();
object_size += DataLayout::compute_size_in_bytes(arg_size+1);
return object_size;
}
@ -534,10 +776,21 @@ int MethodData::initialize_data(BytecodeStream* stream,
}
break;
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
cell_count = CounterData::static_cell_count();
tag = DataLayout::counter_data_tag;
case Bytecodes::_invokestatic: {
int counter_data_cell_count = CounterData::static_cell_count();
if (profile_arguments_for_invoke(stream->method(), stream->bci()) ||
profile_return_for_invoke(stream->method(), stream->bci())) {
cell_count = CallTypeData::compute_cell_count(stream);
} else {
cell_count = counter_data_cell_count;
}
if (cell_count > counter_data_cell_count) {
tag = DataLayout::call_type_data_tag;
} else {
tag = DataLayout::counter_data_tag;
}
break;
}
case Bytecodes::_goto:
case Bytecodes::_goto_w:
case Bytecodes::_jsr:
@ -546,15 +799,37 @@ int MethodData::initialize_data(BytecodeStream* stream,
tag = DataLayout::jump_data_tag;
break;
case Bytecodes::_invokevirtual:
case Bytecodes::_invokeinterface:
cell_count = VirtualCallData::static_cell_count();
tag = DataLayout::virtual_call_data_tag;
case Bytecodes::_invokeinterface: {
int virtual_call_data_cell_count = VirtualCallData::static_cell_count();
if (profile_arguments_for_invoke(stream->method(), stream->bci()) ||
profile_return_for_invoke(stream->method(), stream->bci())) {
cell_count = VirtualCallTypeData::compute_cell_count(stream);
} else {
cell_count = virtual_call_data_cell_count;
}
if (cell_count > virtual_call_data_cell_count) {
tag = DataLayout::virtual_call_type_data_tag;
} else {
tag = DataLayout::virtual_call_data_tag;
}
break;
case Bytecodes::_invokedynamic:
}
case Bytecodes::_invokedynamic: {
// %%% should make a type profile for any invokedynamic that takes a ref argument
cell_count = CounterData::static_cell_count();
tag = DataLayout::counter_data_tag;
int counter_data_cell_count = CounterData::static_cell_count();
if (profile_arguments_for_invoke(stream->method(), stream->bci()) ||
profile_return_for_invoke(stream->method(), stream->bci())) {
cell_count = CallTypeData::compute_cell_count(stream);
} else {
cell_count = counter_data_cell_count;
}
if (cell_count > counter_data_cell_count) {
tag = DataLayout::call_type_data_tag;
} else {
tag = DataLayout::counter_data_tag;
}
break;
}
case Bytecodes::_ret:
cell_count = RetData::static_cell_count();
tag = DataLayout::ret_data_tag;
@ -585,6 +860,11 @@ int MethodData::initialize_data(BytecodeStream* stream,
break;
}
assert(tag == DataLayout::multi_branch_data_tag ||
((MethodData::profile_arguments() || MethodData::profile_return()) &&
(tag == DataLayout::call_type_data_tag ||
tag == DataLayout::counter_data_tag ||
tag == DataLayout::virtual_call_type_data_tag ||
tag == DataLayout::virtual_call_data_tag)) ||
cell_count == bytecode_cell_count(c), "cell counts must agree");
if (cell_count >= 0) {
assert(tag != DataLayout::no_tag, "bad tag");
@ -631,6 +911,10 @@ ProfileData* DataLayout::data_in() {
return new MultiBranchData(this);
case DataLayout::arg_info_data_tag:
return new ArgInfoData(this);
case DataLayout::call_type_data_tag:
return new CallTypeData(this);
case DataLayout::virtual_call_type_data_tag:
return new VirtualCallTypeData(this);
};
}
@ -898,3 +1182,70 @@ void MethodData::verify_data_on(outputStream* st) {
NEEDS_CLEANUP;
// not yet implemented.
}
bool MethodData::profile_jsr292(methodHandle m, int bci) {
if (m->is_compiled_lambda_form()) {
return true;
}
Bytecode_invoke inv(m , bci);
return inv.is_invokedynamic() || inv.is_invokehandle();
}
int MethodData::profile_arguments_flag() {
return TypeProfileLevel % 10;
}
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);
}
int MethodData::profile_return_flag() {
return TypeProfileLevel / 10;
}
bool MethodData::profile_return() {
return profile_return_flag() > no_type_profile && profile_return_flag() <= type_profile_all;
}
bool MethodData::profile_return_jsr292_only() {
return profile_return_flag() == type_profile_jsr292;
}
bool MethodData::profile_all_return() {
return profile_return_flag() == type_profile_all;
}
bool MethodData::profile_return_for_invoke(methodHandle m, int bci) {
if (!profile_return()) {
return false;
}
if (profile_all_return()) {
return true;
}
assert(profile_return_jsr292_only(), "inconsistent");
return profile_jsr292(m, bci);
}

File diff suppressed because it is too large Load Diff

View File

@ -197,6 +197,7 @@ bool InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method,
// negative filter: should callee NOT be inlined?
bool InlineTree::should_not_inline(ciMethod *callee_method,
ciMethod* caller_method,
JVMState* jvms,
WarmCallInfo* wci_result) {
const char* fail_msg = NULL;
@ -226,7 +227,7 @@ bool InlineTree::should_not_inline(ciMethod *callee_method,
// don't inline exception code unless the top method belongs to an
// exception class
if (callee_method->holder()->is_subclass_of(C->env()->Throwable_klass())) {
ciMethod* top_method = caller_jvms() ? caller_jvms()->of_depth(1)->method() : method();
ciMethod* top_method = jvms->caller() != NULL ? jvms->caller()->of_depth(1)->method() : method();
if (!top_method->holder()->is_subclass_of(C->env()->Throwable_klass())) {
wci_result->set_profit(wci_result->profit() * 0.1);
}
@ -328,7 +329,7 @@ bool InlineTree::should_not_inline(ciMethod *callee_method,
// return true if ok
// Relocated from "InliningClosure::try_to_inline"
bool InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_method,
int caller_bci, ciCallProfile& profile,
int caller_bci, JVMState* jvms, ciCallProfile& profile,
WarmCallInfo* wci_result, bool& should_delay) {
// Old algorithm had funny accumulating BC-size counters
@ -346,7 +347,7 @@ bool InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_method,
wci_result)) {
return false;
}
if (should_not_inline(callee_method, caller_method, wci_result)) {
if (should_not_inline(callee_method, caller_method, jvms, wci_result)) {
return false;
}
@ -397,24 +398,35 @@ bool InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_method,
}
// detect direct and indirect recursive inlining
if (!callee_method->is_compiled_lambda_form()) {
{
// count the current method and the callee
int inline_level = (method() == callee_method) ? 1 : 0;
if (inline_level > MaxRecursiveInlineLevel) {
set_msg("recursively inlining too deep");
return false;
const bool is_compiled_lambda_form = callee_method->is_compiled_lambda_form();
int inline_level = 0;
if (!is_compiled_lambda_form) {
if (method() == callee_method) {
inline_level++;
}
}
// count callers of current method and callee
JVMState* jvms = caller_jvms();
while (jvms != NULL && jvms->has_method()) {
if (jvms->method() == callee_method) {
inline_level++;
if (inline_level > MaxRecursiveInlineLevel) {
set_msg("recursively inlining too deep");
return false;
Node* callee_argument0 = is_compiled_lambda_form ? jvms->map()->argument(jvms, 0)->uncast() : NULL;
for (JVMState* j = jvms->caller(); j != NULL && j->has_method(); j = j->caller()) {
if (j->method() == callee_method) {
if (is_compiled_lambda_form) {
// Since compiled lambda forms are heavily reused we allow recursive inlining. If it is truly
// a recursion (using the same "receiver") we limit inlining otherwise we can easily blow the
// compiler stack.
Node* caller_argument0 = j->map()->argument(j, 0)->uncast();
if (caller_argument0 == callee_argument0) {
inline_level++;
}
} else {
inline_level++;
}
}
jvms = jvms->caller();
}
if (inline_level > MaxRecursiveInlineLevel) {
set_msg("recursive inlining is too deep");
return false;
}
}
@ -536,7 +548,7 @@ WarmCallInfo* InlineTree::ok_to_inline(ciMethod* callee_method, JVMState* jvms,
// Check if inlining policy says no.
WarmCallInfo wci = *(initial_wci);
bool success = try_to_inline(callee_method, caller_method, caller_bci,
profile, &wci, should_delay);
jvms, profile, &wci, should_delay);
#ifndef PRODUCT
if (UseOldInlining && InlineWarmCalls

View File

@ -44,9 +44,6 @@
# include "adfiles/ad_ppc.hpp"
#endif
volatile int C2Compiler::_runtimes = uninitialized;
// register information defined by ADLC
extern const char register_save_policy[];
extern const int register_save_type[];
@ -57,7 +54,7 @@ const char* C2Compiler::retry_no_subsuming_loads() {
const char* C2Compiler::retry_no_escape_analysis() {
return "retry without escape analysis";
}
void C2Compiler::initialize_runtime() {
bool C2Compiler::init_c2_runtime() {
// Check assumptions used while running ADLC
Compile::adlc_verification();
@ -90,41 +87,31 @@ void C2Compiler::initialize_runtime() {
CompilerThread* thread = CompilerThread::current();
HandleMark handle_mark(thread);
OptoRuntime::generate(thread->env());
HandleMark handle_mark(thread);
return OptoRuntime::generate(thread->env());
}
void C2Compiler::initialize() {
// This method can only be called once per C2Compiler object
// The first compiler thread that gets here will initialize the
// small amount of global state (and runtime stubs) that c2 needs.
// small amount of global state (and runtime stubs) that C2 needs.
// There is a race possible once at startup and then we're fine
// Note that this is being called from a compiler thread not the
// main startup thread.
if (_runtimes != initialized) {
initialize_runtimes( initialize_runtime, &_runtimes);
if (should_perform_init()) {
bool successful = C2Compiler::init_c2_runtime();
int new_state = (successful) ? initialized : failed;
set_state(new_state);
}
// Mark this compiler object as ready to roll
mark_initialized();
}
void C2Compiler::compile_method(ciEnv* env,
ciMethod* target,
int entry_bci) {
if (!is_initialized()) {
initialize();
}
void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) {
assert(is_initialized(), "Compiler thread must be initialized");
bool subsume_loads = SubsumeLoads;
bool do_escape_analysis = DoEscapeAnalysis &&
!env->jvmti_can_access_local_variables();
bool do_escape_analysis = DoEscapeAnalysis && !env->jvmti_can_access_local_variables();
bool eliminate_boxing = EliminateAutoBox;
while (!env->failing()) {
// Attempt to compile while subsuming loads into machine instructions.

View File

@ -28,24 +28,17 @@
#include "compiler/abstractCompiler.hpp"
class C2Compiler : public AbstractCompiler {
private:
static void initialize_runtime();
private:
static bool init_c2_runtime();
public:
// Name
const char *name() { return "C2"; }
static volatile int _runtimes;
#ifdef TIERED
virtual bool is_c2() { return true; };
#endif // TIERED
// Customization
bool needs_adapters () { return true; }
bool needs_stubs () { return true; }
void initialize();
// Compilation entry point for methods

View File

@ -52,6 +52,7 @@ class PhaseChaitin;
class LRG : public ResourceObj {
friend class VMStructs;
public:
static const uint AllStack_size = 0xFFFFF; // This mask size is used to tell that the mask of this LRG supports stack positions
enum { SPILL_REG=29999 }; // Register number of a spilled LRG
double _cost; // 2 for loads/1 for stores times block freq
@ -80,14 +81,21 @@ public:
private:
uint _eff_degree; // Effective degree: Sum of neighbors _num_regs
public:
int degree() const { assert( _degree_valid, "" ); return _eff_degree; }
int degree() const { assert( _degree_valid , "" ); return _eff_degree; }
// Degree starts not valid and any change to the IFG neighbor
// set makes it not valid.
void set_degree( uint degree ) { _eff_degree = degree; debug_only(_degree_valid = 1;) }
void set_degree( uint degree ) {
_eff_degree = degree;
debug_only(_degree_valid = 1;)
assert(!_mask.is_AllStack() || (_mask.is_AllStack() && lo_degree()), "_eff_degree can't be bigger than AllStack_size - _num_regs if the mask supports stack registers");
}
// Made a change that hammered degree
void invalid_degree() { debug_only(_degree_valid=0;) }
// Incrementally modify degree. If it was correct, it should remain correct
void inc_degree( uint mod ) { _eff_degree += mod; }
void inc_degree( uint mod ) {
_eff_degree += mod;
assert(!_mask.is_AllStack() || (_mask.is_AllStack() && lo_degree()), "_eff_degree can't be bigger than AllStack_size - _num_regs if the mask supports stack registers");
}
// Compute the degree between 2 live ranges
int compute_degree( LRG &l ) const;
@ -95,9 +103,9 @@ private:
RegMask _mask; // Allowed registers for this LRG
uint _mask_size; // cache of _mask.Size();
public:
int compute_mask_size() const { return _mask.is_AllStack() ? 65535 : _mask.Size(); }
int compute_mask_size() const { return _mask.is_AllStack() ? AllStack_size : _mask.Size(); }
void set_mask_size( int size ) {
assert((size == 65535) || (size == (int)_mask.Size()), "");
assert((size == (int)AllStack_size) || (size == (int)_mask.Size()), "");
_mask_size = size;
#ifdef ASSERT
_msize_valid=1;

View File

@ -780,6 +780,7 @@ void ConnectionGraph::add_call_node(CallNode* call) {
}
} else { // Allocate instance
if (cik->is_subclass_of(_compile->env()->Thread_klass()) ||
cik->is_subclass_of(_compile->env()->Reference_klass()) ||
!cik->is_instance_klass() || // StressReflectiveCode
cik->as_instance_klass()->has_finalizer()) {
es = PointsToNode::GlobalEscape;

View File

@ -2122,7 +2122,7 @@ Node* GraphKit::dstore_rounding(Node* n) {
// Null check oop. Set null-path control into Region in slot 3.
// Make a cast-not-nullness use the other not-null control. Return cast.
Node* GraphKit::null_check_oop(Node* value, Node* *null_control,
bool never_see_null) {
bool never_see_null, bool safe_for_replace) {
// Initial NULL check taken path
(*null_control) = top();
Node* cast = null_check_common(value, T_OBJECT, false, null_control);
@ -2140,6 +2140,9 @@ Node* GraphKit::null_check_oop(Node* value, Node* *null_control,
Deoptimization::Action_make_not_entrant);
(*null_control) = top(); // NULL path is dead
}
if ((*null_control) == top() && safe_for_replace) {
replace_in_map(value, cast);
}
// Cast away null-ness on the result
return cast;
@ -2634,15 +2637,17 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass) {
C->set_has_split_ifs(true); // Has chance for split-if optimization
ciProfileData* data = NULL;
bool safe_for_replace = false;
if (java_bc() == Bytecodes::_instanceof) { // Only for the bytecode
data = method()->method_data()->bci_to_data(bci());
safe_for_replace = true;
}
bool never_see_null = (ProfileDynamicTypes // aggressive use of profile
&& seems_never_null(obj, data));
// Null check; get casted pointer; set region slot 3
Node* null_ctl = top();
Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null);
Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace);
// If not_null_obj is dead, only null-path is taken
if (stopped()) { // Doing instance-of on a NULL?
@ -2723,11 +2728,13 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
}
ciProfileData* data = NULL;
bool safe_for_replace = false;
if (failure_control == NULL) { // use MDO in regular case only
assert(java_bc() == Bytecodes::_aastore ||
java_bc() == Bytecodes::_checkcast,
"interpreter profiles type checks only for these BCs");
data = method()->method_data()->bci_to_data(bci());
safe_for_replace = true;
}
// Make the merge point
@ -2742,7 +2749,7 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
// Null check; get casted pointer; set region slot 3
Node* null_ctl = top();
Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null);
Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace);
// If not_null_obj is dead, only null-path is taken
if (stopped()) { // Doing instance-of on a NULL?

View File

@ -378,8 +378,10 @@ class GraphKit : public Phase {
// Return a cast-not-null node which depends on the not-null control.
// If never_see_null, use an uncommon trap (*null_control sees a top).
// The cast is not valid along the null path; keep a copy of the original.
// If safe_for_replace, then we can replace the value with the cast
// in the parsing map (the cast is guaranteed to dominate the map)
Node* null_check_oop(Node* value, Node* *null_control,
bool never_see_null = false);
bool never_see_null = false, bool safe_for_replace = false);
// Check the null_seen bit.
bool seems_never_null(Node* obj, ciProfileData* data);

View File

@ -677,7 +677,7 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) {
} else { // Common case: size 1 bound removal
if( lrg.mask().Member(r_reg) ) {
lrg.Remove(r_reg);
lrg.set_mask_size(lrg.mask().is_AllStack() ? 65535:old_size-1);
lrg.set_mask_size(lrg.mask().is_AllStack() ? LRG::AllStack_size : old_size - 1);
}
}
// If 'l' goes completely dry, it must spill.

View File

@ -689,6 +689,7 @@ Node* IfNode::fold_compares(PhaseGVN* phase) {
ctrl->in(0)->in(1)->is_Bool() &&
ctrl->in(0)->in(1)->in(1)->Opcode() == Op_CmpI &&
ctrl->in(0)->in(1)->in(1)->in(2)->is_Con() &&
ctrl->in(0)->in(1)->in(1)->in(2) != phase->C->top() &&
ctrl->in(0)->in(1)->in(1)->in(1) == n) {
IfNode* dom_iff = ctrl->in(0)->as_If();
Node* otherproj = dom_iff->proj_out(!ctrl->as_Proj()->_con);

View File

@ -73,6 +73,7 @@ protected:
bool try_to_inline(ciMethod* callee_method,
ciMethod* caller_method,
int caller_bci,
JVMState* jvms,
ciCallProfile& profile,
WarmCallInfo* wci_result,
bool& should_delay);
@ -83,6 +84,7 @@ protected:
WarmCallInfo* wci_result);
bool should_not_inline(ciMethod* callee_method,
ciMethod* caller_method,
JVMState* jvms,
WarmCallInfo* wci_result);
void print_inlining(ciMethod* callee_method, int caller_bci,
bool success) const;

View File

@ -268,7 +268,7 @@ public:
return adjoinRange(value, value, dest, table_index);
}
void print(ciEnv* env) {
void print() {
if (is_singleton())
tty->print(" {%d}=>%d", lo(), dest());
else if (lo() == min_jint)
@ -471,8 +471,8 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi)
// These are the switch destinations hanging off the jumpnode
int i = 0;
for (SwitchRange* r = lo; r <= hi; r++) {
for (int j = r->lo(); j <= r->hi(); j++, i++) {
Node* input = _gvn.transform(new (C) JumpProjNode(jtn, i, r->dest(), j - lowval));
for (int64 j = r->lo(); j <= r->hi(); j++, i++) {
Node* input = _gvn.transform(new (C) JumpProjNode(jtn, i, r->dest(), (int)(j - lowval)));
{
PreserveJVMState pjvms(this);
set_control(input);
@ -632,7 +632,7 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi,
}
tty->print(" ");
for( r = lo; r <= hi; r++ ) {
r->print(env());
r->print();
}
tty->print_cr("");
}

View File

@ -343,10 +343,14 @@ void Parse::increment_and_test_invocation_counter(int limit) {
// Get the Method* node.
ciMethod* m = method();
address counters_adr = m->ensure_method_counters();
MethodCounters* counters_adr = m->ensure_method_counters();
if (counters_adr == NULL) {
C->record_failure("method counters allocation failed");
return;
}
Node* ctrl = control();
const TypePtr* adr_type = TypeRawPtr::make(counters_adr);
const TypePtr* adr_type = TypeRawPtr::make((address) counters_adr);
Node *counters_node = makecon(adr_type);
Node* adr_iic_node = basic_plus_adr(counters_node, counters_node,
MethodCounters::interpreter_invocation_counter_offset_in_bytes());

View File

@ -375,6 +375,7 @@ Node *PhaseChaitin::split_Rematerialize( Node *def, Block *b, uint insidx, uint
}
if (lidx < _lrg_map.max_lrg_id() && lrgs(lidx).reg() >= LRG::SPILL_REG) {
assert(Reachblock != NULL, "Reachblock must be non-NULL");
Node *rdef = Reachblock[lrg2reach[lidx]];
if (rdef) {
spill->set_req(i, rdef);
@ -1336,7 +1337,8 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
_lrg_map.find(pred->get_node(insert - 1)) >= lrgs_before_phi_split) {
insert--;
}
def = split_Rematerialize(def, pred, insert, maxlrg, splits, slidx, lrg2reach, Reachblock, false);
// since the def cannot contain any live range input, we can pass in NULL as Reachlock parameter
def = split_Rematerialize(def, pred, insert, maxlrg, splits, slidx, lrg2reach, NULL, false);
if (!def) {
return 0; // Bail out
}

View File

@ -138,9 +138,10 @@ static bool check_compiled_frame(JavaThread* thread) {
#define gen(env, var, type_func_gen, c_func, fancy_jump, pass_tls, save_arg_regs, return_pc) \
var = generate_stub(env, type_func_gen, CAST_FROM_FN_PTR(address, c_func), #var, fancy_jump, pass_tls, save_arg_regs, return_pc)
var = generate_stub(env, type_func_gen, CAST_FROM_FN_PTR(address, c_func), #var, fancy_jump, pass_tls, save_arg_regs, return_pc); \
if (var == NULL) { return false; }
void OptoRuntime::generate(ciEnv* env) {
bool OptoRuntime::generate(ciEnv* env) {
generate_exception_blob();
@ -158,7 +159,7 @@ void OptoRuntime::generate(ciEnv* env) {
gen(env, _multianewarrayN_Java , multianewarrayN_Type , multianewarrayN_C , 0 , true , false, false);
gen(env, _g1_wb_pre_Java , g1_wb_pre_Type , SharedRuntime::g1_wb_pre , 0 , false, false, false);
gen(env, _g1_wb_post_Java , g1_wb_post_Type , SharedRuntime::g1_wb_post , 0 , false, false, false);
gen(env, _complete_monitor_locking_Java , complete_monitor_enter_Type , SharedRuntime::complete_monitor_locking_C , 0 , false, false, false);
gen(env, _complete_monitor_locking_Java , complete_monitor_enter_Type , SharedRuntime::complete_monitor_locking_C, 0, false, false, false);
gen(env, _rethrow_Java , rethrow_Type , rethrow_C , 2 , true , false, true );
gen(env, _slow_arraycopy_Java , slow_arraycopy_Type , SharedRuntime::slow_arraycopy_C , 0 , false, false, false);
@ -168,7 +169,7 @@ void OptoRuntime::generate(ciEnv* env) {
gen(env, _zap_dead_Java_locals_Java , zap_dead_locals_Type , zap_dead_Java_locals_C , 0 , false, true , false );
gen(env, _zap_dead_native_locals_Java , zap_dead_locals_Type , zap_dead_native_locals_C , 0 , false, true , false );
# endif
return true;
}
#undef gen
@ -976,30 +977,36 @@ JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* t
address handler_address = NULL;
Handle exception(thread, thread->exception_oop());
address pc = thread->exception_pc();
// Clear out the exception oop and pc since looking up an
// exception handler can cause class loading, which might throw an
// exception and those fields are expected to be clear during
// normal bytecode execution.
thread->clear_exception_oop_and_pc();
if (TraceExceptions) {
trace_exception(exception(), thread->exception_pc(), "");
trace_exception(exception(), pc, "");
}
// for AbortVMOnException flag
NOT_PRODUCT(Exceptions::debug_check_abort(exception));
#ifdef ASSERT
if (!(exception->is_a(SystemDictionary::Throwable_klass()))) {
// should throw an exception here
ShouldNotReachHere();
}
#endif
#ifdef ASSERT
if (!(exception->is_a(SystemDictionary::Throwable_klass()))) {
// should throw an exception here
ShouldNotReachHere();
}
#endif
// new exception handling: this method is entered only from adapters
// exceptions from compiled java methods are handled in compiled code
// using rethrow node
address pc = thread->exception_pc();
nm = CodeCache::find_nmethod(pc);
assert(nm != NULL, "No NMethod found");
if (nm->is_native_method()) {
fatal("Native mathod should not have path to exception handling");
fatal("Native method should not have path to exception handling");
} else {
// we are switching to old paradigm: search for exception handler in caller_frame
// instead in exception handler of caller_frame.sender()
@ -1346,7 +1353,8 @@ static void trace_exception(oop exception_oop, address exception_pc, const char*
tty->print(" in ");
CodeBlob* blob = CodeCache::find_blob(exception_pc);
if (blob->is_nmethod()) {
((nmethod*)blob)->method()->print_value();
nmethod* nm = blob->as_nmethod_or_null();
nm->method()->print_value();
} else if (blob->is_runtime_stub()) {
tty->print("<runtime-stub>");
} else {

View File

@ -203,8 +203,10 @@ private:
static bool is_callee_saved_register(MachRegisterNumbers reg);
// One time only generate runtime code stubs
static void generate(ciEnv* env);
// One time only generate runtime code stubs. Returns true
// when runtime stubs have been generated successfully and
// false otherwise.
static bool generate(ciEnv* env);
// Returns the name of a stub
static const char* stub_name(address entry);

View File

@ -2677,6 +2677,14 @@ class CommandLineFlags {
product(bool, AggressiveOpts, false, \
"Enable aggressive optimizations - see arguments.cpp") \
\
product_pd(uintx, TypeProfileLevel, \
"=XY, with Y, Type profiling of arguments at call" \
" X, Type profiling of return value at call" \
"X and Y in 0->off ; 1->js292 only; 2->all methods") \
\
product(intx, TypeProfileArgsLimit, 2, \
"max number of call arguments to consider for type profiling") \
\
/* statistics */ \
develop(bool, CountCompiledCalls, false, \
"Count method invocations") \
@ -3823,7 +3831,6 @@ class CommandLineFlags {
product(bool, UseLockedTracing, false, \
"Use locked-tracing when doing event-based tracing")
/*
* Macros for factoring of globals
*/

View File

@ -183,6 +183,7 @@ void print_method_profiling_data() {
collected_profiled_methods->sort(&compare_methods);
int count = collected_profiled_methods->length();
int total_size = 0;
if (count > 0) {
for (int index = 0; index < count; index++) {
Method* m = collected_profiled_methods->at(index);
@ -190,10 +191,13 @@ void print_method_profiling_data() {
tty->print_cr("------------------------------------------------------------------------");
//m->print_name(tty);
m->print_invocation_count();
tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes());
tty->cr();
m->print_codes();
total_size += m->method_data()->size_in_bytes();
}
tty->print_cr("------------------------------------------------------------------------");
tty->print_cr("Total MDO size: %d bytes", total_size);
}
}

View File

@ -378,6 +378,16 @@ Symbol* SignatureStream::as_symbol_or_null() {
return result;
}
int SignatureStream::reference_parameter_count() {
int args_count = 0;
for ( ; !at_return_type(); next()) {
if (is_object()) {
args_count++;
}
}
return args_count;
}
bool SignatureVerifier::is_valid_signature(Symbol* sig) {
const char* signature = (const char*)sig->bytes();
ssize_t len = sig->utf8_length();

View File

@ -401,6 +401,9 @@ class SignatureStream : public StackObj {
// return same as_symbol except allocation of new symbols is avoided.
Symbol* as_symbol_or_null();
// count the number of references in the signature
int reference_parameter_count();
};
class SignatureVerifier : public StackObj {

View File

@ -1454,7 +1454,6 @@ void JavaThread::initialize() {
_interp_only_mode = 0;
_special_runtime_exit_condition = _no_async_condition;
_pending_async_exception = NULL;
_is_compiling = false;
_thread_stat = NULL;
_thread_stat = new ThreadStatistics();
_blocked_on_compilation = false;
@ -1815,7 +1814,8 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
// Call Thread.exit(). We try 3 times in case we got another Thread.stop during
// the execution of the method. If that is not enough, then we don't really care. Thread.stop
// is deprecated anyhow.
{ int count = 3;
if (!is_Compiler_thread()) {
int count = 3;
while (java_lang_Thread::threadGroup(threadObj()) != NULL && (count-- > 0)) {
EXCEPTION_MARK;
JavaValue result(T_VOID);
@ -1828,7 +1828,6 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
CLEAR_PENDING_EXCEPTION;
}
}
// notify JVMTI
if (JvmtiExport::should_post_thread_life()) {
JvmtiExport::post_thread_end(this);
@ -3239,6 +3238,7 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerCounters* counters)
_counters = counters;
_buffer_blob = NULL;
_scanned_nmethod = NULL;
_compiler = NULL;
#ifndef PRODUCT
_ideal_graph_printer = NULL;
@ -3255,6 +3255,7 @@ void CompilerThread::oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClos
}
}
// ======= Threads ========
// The Threads class links together all active threads, and provides
@ -3275,8 +3276,6 @@ bool Threads::_vm_complete = false;
// All JavaThreads
#define ALL_JAVA_THREADS(X) for (JavaThread* X = _thread_list; X; X = X->next())
void os_stream();
// All JavaThreads + all non-JavaThreads (i.e., every thread in the system)
void Threads::threads_do(ThreadClosure* tc) {
assert_locked_or_safepoint(Threads_lock);

View File

@ -923,9 +923,6 @@ class JavaThread: public Thread {
volatile address _exception_handler_pc; // PC for handler of exception
volatile int _is_method_handle_return; // true (== 1) if the current exception PC is a MethodHandle call site.
// support for compilation
bool _is_compiling; // is true if a compilation is active inthis thread (one compilation per thread possible)
// support for JNI critical regions
jint _jni_active_critical; // count of entries into JNI critical region
@ -1005,10 +1002,6 @@ class JavaThread: public Thread {
// Testers
virtual bool is_Java_thread() const { return true; }
// compilation
void set_is_compiling(bool f) { _is_compiling = f; }
bool is_compiling() const { return _is_compiling; }
// Thread chain operations
JavaThread* next() const { return _next; }
void set_next(JavaThread* p) { _next = p; }
@ -1283,6 +1276,11 @@ class JavaThread: public Thread {
void set_exception_handler_pc(address a) { _exception_handler_pc = a; }
void set_is_method_handle_return(bool value) { _is_method_handle_return = value ? 1 : 0; }
void clear_exception_oop_and_pc() {
set_exception_oop(NULL);
set_exception_pc(NULL);
}
// Stack overflow support
inline size_t stack_available(address cur_sp);
address stack_yellow_zone_base()
@ -1811,13 +1809,14 @@ class CompilerThread : public JavaThread {
private:
CompilerCounters* _counters;
ciEnv* _env;
CompileLog* _log;
CompileTask* _task;
CompileQueue* _queue;
BufferBlob* _buffer_blob;
ciEnv* _env;
CompileLog* _log;
CompileTask* _task;
CompileQueue* _queue;
BufferBlob* _buffer_blob;
nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper
nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper
AbstractCompiler* _compiler;
public:
@ -1829,14 +1828,17 @@ class CompilerThread : public JavaThread {
// Hide this compiler thread from external view.
bool is_hidden_from_external_view() const { return true; }
CompileQueue* queue() { return _queue; }
CompilerCounters* counters() { return _counters; }
void set_compiler(AbstractCompiler* c) { _compiler = c; }
AbstractCompiler* compiler() const { return _compiler; }
CompileQueue* queue() const { return _queue; }
CompilerCounters* counters() const { return _counters; }
// Get/set the thread's compilation environment.
ciEnv* env() { return _env; }
void set_env(ciEnv* env) { _env = env; }
BufferBlob* get_buffer_blob() { return _buffer_blob; }
BufferBlob* get_buffer_blob() const { return _buffer_blob; }
void set_buffer_blob(BufferBlob* b) { _buffer_blob = b; };
// Get/set the thread's logging information

View File

@ -917,7 +917,6 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
volatile_nonstatic_field(JavaThread, _exception_oop, oop) \
volatile_nonstatic_field(JavaThread, _exception_pc, address) \
volatile_nonstatic_field(JavaThread, _is_method_handle_return, int) \
nonstatic_field(JavaThread, _is_compiling, bool) \
nonstatic_field(JavaThread, _special_runtime_exit_condition, JavaThread::AsyncRequests) \
nonstatic_field(JavaThread, _saved_exception_pc, address) \
volatile_nonstatic_field(JavaThread, _thread_state, JavaThreadState) \

View File

@ -133,11 +133,10 @@ SharkCompiler::SharkCompiler()
exit(1);
}
execution_engine()->addModule(
_native_context->module());
execution_engine()->addModule(_native_context->module());
// All done
mark_initialized();
set_state(initialized);
}
void SharkCompiler::initialize() {

View File

@ -50,10 +50,6 @@ class SharkCompiler : public AbstractCompiler {
return ! (method->is_method_handle_intrinsic() || method->is_compiled_lambda_form());
}
// Customization
bool needs_adapters() { return false; }
bool needs_stubs() { return false; }
// Initialization
void initialize();

View File

@ -465,7 +465,7 @@ static const char* make_log_name_internal(const char* log_name, const char* forc
}
// log_name comes from -XX:LogFile=log_name or -Xloggc:log_name
// in log_name, %p => pipd1234 and
// in log_name, %p => pid1234 and
// %t => YYYY-MM-DD_HH-MM-SS
static const char* make_log_name(const char* log_name, const char* force_directory) {
char timestr[32];
@ -792,7 +792,7 @@ bool defaultStream::has_log_file() {
void defaultStream::init_log() {
// %%% Need a MutexLocker?
const char* log_name = LogFile != NULL ? LogFile : "hotspot_pid%p.log";
const char* log_name = LogFile != NULL ? LogFile : "hotspot_%p.log";
const char* try_name = make_log_name(log_name, NULL);
fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name);
if (!file->is_open()) {

View File

@ -1050,7 +1050,7 @@ void VMError::report_and_die() {
FILE* replay_data_file = os::open(fd, "w");
if (replay_data_file != NULL) {
fileStream replay_data_stream(replay_data_file, /*need_close=*/true);
env->dump_replay_data(&replay_data_stream);
env->dump_replay_data_unsafe(&replay_data_stream);
out.print_raw("#\n# Compiler replay data is saved as:\n# ");
out.print_raw_cr(buffer);
} else {

View File

@ -1,55 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
#
# @test
# @bug 8013496
# @summary Test checks that the order in which ReversedCodeCacheSize and
# InitialCodeCacheSize are passed to the VM is irrelevant.
# @run shell Test8013496.sh
#
#
## some tests require path to find test source dir
if [ "${TESTSRC}" = "" ]
then
TESTSRC=${PWD}
echo "TESTSRC not set. Using "${TESTSRC}" as default"
fi
echo "TESTSRC=${TESTSRC}"
## Adding common setup Variables for running shell tests.
. ${TESTSRC}/../../test_env.sh
set -x
${TESTJAVA}/bin/java ${TESTVMOPTS} -XX:ReservedCodeCacheSize=2m -XX:InitialCodeCacheSize=500K -version > 1.out 2>&1
${TESTJAVA}/bin/java ${TESTVMOPTS} -XX:InitialCodeCacheSize=500K -XX:ReservedCodeCacheSize=2m -version > 2.out 2>&1
diff 1.out 2.out
result=$?
if [ $result -eq 0 ] ; then
echo "Test Passed"
exit 0
else
echo "Test Failed"
exit 1
fi

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8013496
* @summary Test checks that the order in which ReversedCodeCacheSize and
* InitialCodeCacheSize are passed to the VM is irrelevant.
* @library /testlibrary
*
*/
import com.oracle.java.testlibrary.*;
public class CheckReservedInitialCodeCacheSizeArgOrder {
public static void main(String[] args) throws Exception {
ProcessBuilder pb1, pb2;
OutputAnalyzer out1, out2;
pb1 = ProcessTools.createJavaProcessBuilder("-XX:InitialCodeCacheSize=4m", "-XX:ReservedCodeCacheSize=8m", "-version");
pb2 = ProcessTools.createJavaProcessBuilder("-XX:ReservedCodeCacheSize=8m", "-XX:InitialCodeCacheSize=4m", "-version");
out1 = new OutputAnalyzer(pb1.start());
out2 = new OutputAnalyzer(pb2.start());
// Check that the outputs are equal
if (out1.getStdout().compareTo(out2.getStdout()) != 0) {
throw new RuntimeException("Test failed");
}
out1.shouldHaveExitValue(0);
out2.shouldHaveExitValue(0);
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8023014
* @summary Test ensures that there is no crash when compiler initialization fails
* @library /testlibrary
*
*/
import com.oracle.java.testlibrary.*;
public class SmallCodeCacheStartup {
public static void main(String[] args) throws Exception {
ProcessBuilder pb;
OutputAnalyzer out;
pb = ProcessTools.createJavaProcessBuilder("-XX:ReservedCodeCacheSize=3m", "-XX:CICompilerCount=64", "-version");
out = new OutputAnalyzer(pb.start());
out.shouldContain("no space to run compiler");
out.shouldHaveExitValue(0);
}
}