This commit is contained in:
J. Duke 2017-07-05 17:06:53 +02:00
commit 0ec5e88e3e
95 changed files with 2189 additions and 613 deletions

View File

@ -56,3 +56,4 @@ ab4ae8f4514693a9fe17ca2fec0239d8f8450d2c jdk7-b78
20aeeb51713990dbea6929a2e100a8bbf5df70d4 jdk7-b79
a3242906c7747b5d9bcc3d118c7c3c69aa40f4b7 jdk7-b80
8403096d1fe7ff5318df9708cfec84a3fd3e1cf9 jdk7-b81
e1176f86805fe07fd9fb9da065dc51b47712ce76 jdk7-b82

View File

@ -56,3 +56,4 @@ a7f7276b48cd74d8eb1baa83fbf3d1ef4a2603c8 jdk7-b78
ec0421b5703b677e2226cf4bf7ae4eaafd8061c5 jdk7-b79
0336e70ca0aeabc783cc01658f36cb6e27ea7934 jdk7-b80
e08a42a2a94d97ea8eedb187a94dbff822c8fbba jdk7-b81
1e8c1bfad1abb4b81407a0f2645e0fb85764ca48 jdk7-b82

View File

@ -56,3 +56,26 @@ e703499b4b51e3af756ae77c3d5e8b3058a14e4e jdk7-b78
a5a6adfca6ecefb5894a848debabfe442ff50e25 jdk7-b79
3003ddd1d4330b06cb4691ae74d600d3685899eb jdk7-b80
1f9b07674480c224828852ffe137beea36b3cab5 jdk7-b81
1999f5b12482d66c8b0daf6709daea4f51893a04 jdk7-b82
a94714c550658fd6741793ef036cb9625dc2ab1a hs17-b01
faf94d94786b621f8e13cbcc941ca69c6d967c3f hs17-b02
f4b900403d6e4b0af51447bd13bbe23fe3a1dac7 hs17-b03
d8dd291a362acb656026a9c0a9da48501505a1e7 hs17-b04
9174bb32e934965288121f75394874eeb1fcb649 hs17-b05
a5a6adfca6ecefb5894a848debabfe442ff50e25 hs17-b06
3003ddd1d4330b06cb4691ae74d600d3685899eb hs17-b07
1f9b07674480c224828852ffe137beea36b3cab5 hs17-b08
ff3232b68fbb35185b338d7ff4695b52460243f3 hs17-b09
981375ca07b7f0605f92f57aad95122e8c385a4d hs16-b01
f4cbf78110c726919f46b59a3b054c54c7e889b4 hs16-b02
07c1c01e031513bfe6a7d17c6cf30d2752824ae9 hs16-b03
08f86fa55a31113df626a75c8a626e66a543a1bd hs16-b04
32c83fb84370a35344676991a48440378e6b6c8a hs16-b05
ba313800759b678979434d6da8ed3bf49eb8bea4 hs16-b06
3c0f729815607e1678bd0c41ae68494c700dcc71 hs16-b07
ac59d4e6dae51ac5fc31a9a4940d1857f91161b1 hs16-b08
3f844a28c5f4912bd04043b44f21b25b0805ffc2 hs15-b01
1605bb4eb5a7a1703b13d5b077a22cc665fe45f7 hs15-b02
2581d90c6c9b2012da930eb4742add94a03069a0 hs15-b03
9ab385cb0c42997e16a7761ebcd25c90560a2714 hs15-b04
fafab5d5349c7c066d677538db67a1ee0fb33bd2 hs15-b05

View File

@ -1,5 +1,5 @@
#
# Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
# Copyright 2005-2010 Sun Microsystems, Inc. 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
@ -312,10 +312,13 @@ endif
$(EXPORT_LIB_DIR)/%.jar: $(GEN_DIR)/%.jar
$(install-file)
# Include files (jvmti.h, jni.h, $(JDK_INCLUDE_SUBDIR)/jni_md.h, jmm.h)
# Include files (jvmti.h, jvmticmlr.h, jni.h, $(JDK_INCLUDE_SUBDIR)/jni_md.h, jmm.h)
$(EXPORT_INCLUDE_DIR)/%: $(GEN_DIR)/jvmtifiles/%
$(install-file)
$(EXPORT_INCLUDE_DIR)/%: $(HS_SRC_DIR)/share/vm/code/%
$(install-file)
$(EXPORT_INCLUDE_DIR)/%: $(HS_SRC_DIR)/share/vm/prims/%
$(install-file)

View File

@ -1,5 +1,5 @@
#
# Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved.
# Copyright 2006-2010 Sun Microsystems, Inc. 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
@ -261,6 +261,7 @@ EXPORT_JRE_LIB_ARCH_DIR = $(EXPORT_JRE_LIB_DIR)/$(LIBARCH)
# Common export list of files
EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jvmti.h
EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jvmticmlr.h
EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jni.h
EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/$(JDK_INCLUDE_SUBDIR)/jni_md.h
EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jmm.h

View File

@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2009
HS_MAJOR_VER=17
HS_MINOR_VER=0
HS_BUILD_NUMBER=08
HS_BUILD_NUMBER=09
JDK_MAJOR_VER=1
JDK_MINOR_VER=7

View File

@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2000-2010 Sun Microsystems, Inc. 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
@ -357,7 +357,7 @@ void LIR_Assembler::monitorexit(LIR_Opr obj_opr, LIR_Opr lock_opr, Register hdr,
}
void LIR_Assembler::emit_exception_handler() {
int LIR_Assembler::emit_exception_handler() {
// if the last instruction is a call (typically to do a throw which
// is coming at the end after block reordering) the return address
// must still point into the code area in order to avoid assertion
@ -373,15 +373,12 @@ void LIR_Assembler::emit_exception_handler() {
if (handler_base == NULL) {
// not enough space left for the handler
bailout("exception handler overflow");
return;
return -1;
}
#ifdef ASSERT
int offset = code_offset();
#endif // ASSERT
compilation()->offsets()->set_value(CodeOffsets::Exceptions, code_offset());
if (compilation()->has_exception_handlers() || compilation()->env()->jvmti_can_post_exceptions()) {
if (compilation()->has_exception_handlers() || compilation()->env()->jvmti_can_post_on_exceptions()) {
__ call(Runtime1::entry_for(Runtime1::handle_exception_id), relocInfo::runtime_call_type);
__ delayed()->nop();
}
@ -390,11 +387,13 @@ void LIR_Assembler::emit_exception_handler() {
__ delayed()->nop();
debug_only(__ stop("should have gone to the caller");)
assert(code_offset() - offset <= exception_handler_size, "overflow");
__ end_a_stub();
return offset;
}
void LIR_Assembler::emit_deopt_handler() {
int LIR_Assembler::emit_deopt_handler() {
// if the last instruction is a call (typically to do a throw which
// is coming at the end after block reordering) the return address
// must still point into the code area in order to avoid assertion
@ -408,23 +407,18 @@ void LIR_Assembler::emit_deopt_handler() {
if (handler_base == NULL) {
// not enough space left for the handler
bailout("deopt handler overflow");
return;
return -1;
}
#ifdef ASSERT
int offset = code_offset();
#endif // ASSERT
compilation()->offsets()->set_value(CodeOffsets::Deopt, code_offset());
AddressLiteral deopt_blob(SharedRuntime::deopt_blob()->unpack());
__ JUMP(deopt_blob, G3_scratch, 0); // sethi;jmp
__ delayed()->nop();
assert(code_offset() - offset <= deopt_handler_size, "overflow");
debug_only(__ stop("should have gone to the caller");)
__ end_a_stub();
return offset;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -366,8 +366,9 @@ frame::frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_adjusted_sta
// as get_original_pc() needs correct value for unextended_sp()
if (_pc != NULL) {
_cb = CodeCache::find_blob(_pc);
if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) {
_pc = ((nmethod*)_cb)->get_original_pc(this);
address original_pc = nmethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;
@ -519,9 +520,9 @@ void frame::patch_pc(Thread* thread, address pc) {
_cb = CodeCache::find_blob(pc);
*O7_addr() = pc - pc_return_offset;
_cb = CodeCache::find_blob(_pc);
if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) {
address orig = ((nmethod*)_cb)->get_original_pc(this);
assert(orig == _pc, "expected original to be stored before patching");
address original_pc = nmethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
assert(original_pc == _pc, "expected original to be stored before patching");
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;

View File

@ -1681,11 +1681,8 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
// If no method data exists, go to profile_continue.
test_method_data_pointer(profile_continue);
// We are making a call. Increment the count.
increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
// Record the receiver type.
record_klass_in_profile(receiver, scratch);
record_klass_in_profile(receiver, scratch, true);
// The method data pointer needs to be updated to reflect the new target.
update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size()));
@ -1695,9 +1692,13 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
void InterpreterMacroAssembler::record_klass_in_profile_helper(
Register receiver, Register scratch,
int start_row, Label& done) {
if (TypeProfileWidth == 0)
int start_row, Label& done, bool is_virtual_call) {
if (TypeProfileWidth == 0) {
if (is_virtual_call) {
increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
}
return;
}
int last_row = VirtualCallData::row_limit() - 1;
assert(start_row <= last_row, "must be work left to do");
@ -1714,6 +1715,7 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
// See if the receiver is receiver[n].
int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row));
test_mdp_data_at(recvr_offset, receiver, next_test, scratch);
// delayed()->tst(scratch);
// The receiver is receiver[n]. Increment count[n].
int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row));
@ -1723,20 +1725,31 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
bind(next_test);
if (test_for_null_also) {
Label found_null;
// Failed the equality check on receiver[n]... Test for null.
if (start_row == last_row) {
// The only thing left to do is handle the null case.
brx(Assembler::notZero, false, Assembler::pt, done);
delayed()->nop();
if (is_virtual_call) {
brx(Assembler::zero, false, Assembler::pn, found_null);
delayed()->nop();
// Receiver did not match any saved receiver and there is no empty row for it.
// Increment total counter to indicate polimorphic case.
increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
ba(false, done);
delayed()->nop();
bind(found_null);
} else {
brx(Assembler::notZero, false, Assembler::pt, done);
delayed()->nop();
}
break;
}
// Since null is rare, make it be the branch-taken case.
Label found_null;
brx(Assembler::zero, false, Assembler::pn, found_null);
delayed()->nop();
// Put all the "Case 3" tests here.
record_klass_in_profile_helper(receiver, scratch, start_row + 1, done);
record_klass_in_profile_helper(receiver, scratch, start_row + 1, done, is_virtual_call);
// Found a null. Keep searching for a matching receiver,
// but remember that this is an empty (unused) slot.
@ -1753,16 +1766,18 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row));
mov(DataLayout::counter_increment, scratch);
set_mdp_data_at(count_offset, scratch);
ba(false, done);
delayed()->nop();
if (start_row > 0) {
ba(false, done);
delayed()->nop();
}
}
void InterpreterMacroAssembler::record_klass_in_profile(Register receiver,
Register scratch) {
Register scratch, bool is_virtual_call) {
assert(ProfileInterpreter, "must be profiling");
Label done;
record_klass_in_profile_helper(receiver, scratch, 0, done);
record_klass_in_profile_helper(receiver, scratch, 0, done, is_virtual_call);
bind (done);
}
@ -1840,7 +1855,7 @@ void InterpreterMacroAssembler::profile_typecheck(Register klass,
mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
// Record the object type.
record_klass_in_profile(klass, scratch);
record_klass_in_profile(klass, scratch, false);
}
// The method data pointer needs to be updated.

View File

@ -290,9 +290,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
void test_mdp_data_at(int offset, Register value, Label& not_equal_continue,
Register scratch);
void record_klass_in_profile(Register receiver, Register scratch);
void record_klass_in_profile(Register receiver, Register scratch, bool is_virtual_call);
void record_klass_in_profile_helper(Register receiver, Register scratch,
int start_row, Label& done);
int start_row, Label& done, bool is_virtual_call);
void update_mdp_by_offset(int offset_of_disp, Register scratch);
void update_mdp_by_offset(Register reg, int offset_of_disp,

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2010 Sun Microsystems, Inc. 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
@ -1189,7 +1189,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
// VMReg max_arg,
int comp_args_on_stack, // VMRegStackSlots
const BasicType *sig_bt,
const VMRegPair *regs) {
const VMRegPair *regs,
AdapterFingerPrint* fingerprint) {
address i2c_entry = __ pc();
AdapterGenerator agen(masm);
@ -1258,7 +1259,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
agen.gen_c2i_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
__ flush();
return new AdapterHandlerEntry(i2c_entry, c2i_entry, c2i_unverified_entry);
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2000-2010 Sun Microsystems, Inc. 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
@ -418,13 +418,12 @@ int LIR_Assembler::initial_frame_size_in_bytes() {
}
void LIR_Assembler::emit_exception_handler() {
int LIR_Assembler::emit_exception_handler() {
// if the last instruction is a call (typically to do a throw which
// is coming at the end after block reordering) the return address
// must still point into the code area in order to avoid assertion
// failures when searching for the corresponding bci => add a nop
// (was bug 5/14/1999 - gri)
__ nop();
// generate code for exception handler
@ -432,17 +431,14 @@ void LIR_Assembler::emit_exception_handler() {
if (handler_base == NULL) {
// not enough space left for the handler
bailout("exception handler overflow");
return;
return -1;
}
#ifdef ASSERT
int offset = code_offset();
#endif // ASSERT
compilation()->offsets()->set_value(CodeOffsets::Exceptions, code_offset());
int offset = code_offset();
// if the method does not have an exception handler, then there is
// no reason to search for one
if (compilation()->has_exception_handlers() || compilation()->env()->jvmti_can_post_exceptions()) {
if (compilation()->has_exception_handlers() || compilation()->env()->jvmti_can_post_on_exceptions()) {
// the exception oop and pc are in rax, and rdx
// no other registers need to be preserved, so invalidate them
__ invalidate_registers(false, true, true, false, true, true);
@ -474,19 +470,19 @@ void LIR_Assembler::emit_exception_handler() {
// unwind activation and forward exception to caller
// rax,: exception
__ jump(RuntimeAddress(Runtime1::entry_for(Runtime1::unwind_exception_id)));
assert(code_offset() - offset <= exception_handler_size, "overflow");
__ end_a_stub();
return offset;
}
void LIR_Assembler::emit_deopt_handler() {
int LIR_Assembler::emit_deopt_handler() {
// if the last instruction is a call (typically to do a throw which
// is coming at the end after block reordering) the return address
// must still point into the code area in order to avoid assertion
// failures when searching for the corresponding bci => add a nop
// (was bug 5/14/1999 - gri)
__ nop();
// generate code for exception handler
@ -494,23 +490,17 @@ void LIR_Assembler::emit_deopt_handler() {
if (handler_base == NULL) {
// not enough space left for the handler
bailout("deopt handler overflow");
return;
return -1;
}
#ifdef ASSERT
int offset = code_offset();
#endif // ASSERT
compilation()->offsets()->set_value(CodeOffsets::Deopt, code_offset());
InternalAddress here(__ pc());
__ pushptr(here.addr());
__ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack()));
assert(code_offset() - offset <= deopt_handler_size, "overflow");
__ end_a_stub();
return offset;
}
@ -3219,7 +3209,6 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
Register mdo = op->mdo()->as_register();
__ movoop(mdo, md->constant_encoding());
Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()));
__ addl(counter_addr, DataLayout::counter_increment);
Bytecodes::Code bc = method->java_code_at_bci(bci);
// Perform additional virtual call profiling for invokevirtual and
// invokeinterface bytecodes
@ -3286,14 +3275,18 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
__ jcc(Assembler::notEqual, next_test);
__ movptr(recv_addr, recv);
__ movl(Address(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i))), DataLayout::counter_increment);
if (i < (VirtualCallData::row_limit() - 1)) {
__ jmp(update_done);
}
__ jmp(update_done);
__ bind(next_test);
}
// Receiver did not match any saved receiver and there is no empty row for it.
// Increment total counter to indicate polimorphic case.
__ addl(counter_addr, DataLayout::counter_increment);
__ bind(update_done);
}
} else {
// Static call
__ addl(counter_addr, DataLayout::counter_increment);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -222,9 +222,9 @@ void frame::patch_pc(Thread* thread, address pc) {
}
((address *)sp())[-1] = pc;
_cb = CodeCache::find_blob(pc);
if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) {
address orig = (((nmethod*)_cb)->get_original_pc(this));
assert(orig == _pc, "expected original to be stored before patching");
address original_pc = nmethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
assert(original_pc == _pc, "expected original PC to be stored before patching");
_deopt_state = is_deoptimized;
// leave _pc as is
} else {
@ -323,19 +323,61 @@ frame frame::sender_for_entry_frame(RegisterMap* map) const {
return fr;
}
//------------------------------------------------------------------------------
// frame::verify_deopt_original_pc
//
// Verifies the calculated original PC of a deoptimization PC for the
// given unextended SP. The unextended SP might also be the saved SP
// for MethodHandle call sites.
#if ASSERT
void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) {
frame fr;
// This is ugly but it's better than to change {get,set}_original_pc
// to take an SP value as argument. And it's only a debugging
// method anyway.
fr._unextended_sp = unextended_sp;
address original_pc = nm->get_original_pc(&fr);
assert(nm->code_contains(original_pc), "original PC must be in nmethod");
assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be");
}
#endif
//------------------------------------------------------------------------------
// frame::sender_for_interpreter_frame
frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
// sp is the raw sp from the sender after adapter or interpreter extension
intptr_t* sp = (intptr_t*) addr_at(sender_sp_offset);
// SP is the raw SP from the sender after adapter or interpreter
// extension.
intptr_t* sender_sp = this->sender_sp();
// This is the sp before any possible extension (adapter/locals).
intptr_t* unextended_sp = interpreter_frame_sender_sp();
// Stored FP.
intptr_t* saved_fp = link();
address sender_pc = this->sender_pc();
CodeBlob* sender_cb = CodeCache::find_blob_unsafe(sender_pc);
assert(sender_cb, "sanity");
nmethod* sender_nm = sender_cb->as_nmethod_or_null();
if (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc)) {
unextended_sp = (intptr_t*) at(link_offset);
if (sender_nm != NULL) {
// If the sender PC is a deoptimization point, get the original
// PC. For MethodHandle call site the unextended_sp is stored in
// saved_fp.
if (sender_nm->is_deopt_mh_entry(sender_pc)) {
DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, saved_fp));
unextended_sp = saved_fp;
}
else if (sender_nm->is_deopt_entry(sender_pc)) {
DEBUG_ONLY(verify_deopt_original_pc(sender_nm, unextended_sp));
}
else if (sender_nm->is_method_handle_return(sender_pc)) {
unextended_sp = saved_fp;
}
}
// The interpreter and compiler(s) always save EBP/RBP in a known
@ -359,40 +401,51 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
}
#endif // AMD64
}
#endif /* COMPILER2 */
return frame(sp, unextended_sp, link(), sender_pc);
#endif // COMPILER2
return frame(sender_sp, unextended_sp, saved_fp, sender_pc);
}
//------------------------------sender_for_compiled_frame-----------------------
//------------------------------------------------------------------------------
// frame::sender_for_compiled_frame
frame frame::sender_for_compiled_frame(RegisterMap* map) const {
assert(map != NULL, "map must be set");
const bool c1_compiled = _cb->is_compiled_by_c1();
// frame owned by optimizing compiler
intptr_t* sender_sp = NULL;
assert(_cb->frame_size() >= 0, "must have non-zero frame size");
sender_sp = unextended_sp() + _cb->frame_size();
intptr_t* sender_sp = unextended_sp() + _cb->frame_size();
intptr_t* unextended_sp = sender_sp;
// On Intel the return_address is always the word on the stack
address sender_pc = (address) *(sender_sp-1);
// This is the saved value of ebp which may or may not really be an fp.
// it is only an fp if the sender is an interpreter frame (or c1?)
// This is the saved value of EBP which may or may not really be an FP.
// It is only an FP if the sender is an interpreter frame (or C1?).
intptr_t* saved_fp = (intptr_t*) *(sender_sp - frame::sender_sp_offset);
intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset);
intptr_t* unextended_sp = sender_sp;
// If we are returning to a compiled method handle call site,
// the saved_fp will in fact be a saved value of the unextended SP.
// The simplest way to tell whether we are returning to such a call
// site is as follows:
// If we are returning to a compiled MethodHandle call site, the
// saved_fp will in fact be a saved value of the unextended SP. The
// simplest way to tell whether we are returning to such a call site
// is as follows:
CodeBlob* sender_cb = CodeCache::find_blob_unsafe(sender_pc);
assert(sender_cb, "sanity");
nmethod* sender_nm = sender_cb->as_nmethod_or_null();
if (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc)) {
unextended_sp = saved_fp;
if (sender_nm != NULL) {
// If the sender PC is a deoptimization point, get the original
// PC. For MethodHandle call site the unextended_sp is stored in
// saved_fp.
if (sender_nm->is_deopt_mh_entry(sender_pc)) {
DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, saved_fp));
unextended_sp = saved_fp;
}
else if (sender_nm->is_deopt_entry(sender_pc)) {
DEBUG_ONLY(verify_deopt_original_pc(sender_nm, unextended_sp));
}
else if (sender_nm->is_method_handle_return(sender_pc)) {
unextended_sp = saved_fp;
}
}
if (map->update_map()) {
@ -403,7 +456,7 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const {
if (_cb->oop_maps() != NULL) {
OopMapSet::update_register_map(this, map);
}
// Since the prolog does the save and restore of epb there is no oopmap
// Since the prolog does the save and restore of EBP there is no oopmap
// for it so we must fill in its location as if there was an oopmap entry
// since if our caller was compiled code there could be live jvm state in it.
map->set_location(rbp->as_VMReg(), (address) (sender_sp - frame::sender_sp_offset));
@ -422,6 +475,9 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const {
return frame(sender_sp, unextended_sp, saved_fp, sender_pc);
}
//------------------------------------------------------------------------------
// frame::sender
frame frame::sender(RegisterMap* map) const {
// Default is we done have to follow them. The sender_for_xxx will
// update it accordingly

View File

@ -163,6 +163,14 @@
return (intptr_t*) addr_at(offset);
}
#if ASSERT
// Used in frame::sender_for_{interpreter,compiled}_frame
static void verify_deopt_original_pc( nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false);
static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) {
verify_deopt_original_pc(nm, unextended_sp, true);
}
#endif
public:
// Constructors

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -35,32 +35,35 @@ inline frame::frame() {
_deopt_state = unknown;
}
inline frame:: frame(intptr_t* sp, intptr_t* fp, address pc) {
inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
_sp = sp;
_unextended_sp = sp;
_fp = fp;
_pc = pc;
assert(pc != NULL, "no pc?");
_cb = CodeCache::find_blob(pc);
_deopt_state = not_deoptimized;
if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) {
_pc = (((nmethod*)_cb)->get_original_pc(this));
address original_pc = nmethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;
}
}
inline frame:: frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
_sp = sp;
_unextended_sp = unextended_sp;
_fp = fp;
_pc = pc;
assert(pc != NULL, "no pc?");
_cb = CodeCache::find_blob(pc);
_deopt_state = not_deoptimized;
if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) {
_pc = (((nmethod*)_cb)->get_original_pc(this));
address original_pc = nmethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
assert(((nmethod*)_cb)->code_contains(_pc), "original PC must be in nmethod");
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;
@ -86,9 +89,9 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) {
_cb = CodeCache::find_blob(_pc);
_deopt_state = not_deoptimized;
if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) {
_pc = (((nmethod*)_cb)->get_original_pc(this));
address original_pc = nmethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;

View File

@ -1239,17 +1239,19 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver, Register
// If no method data exists, go to profile_continue.
test_method_data_pointer(mdp, profile_continue);
// We are making a call. Increment the count.
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
Label skip_receiver_profile;
if (receiver_can_be_null) {
Label not_null;
testptr(receiver, receiver);
jcc(Assembler::zero, skip_receiver_profile);
jccb(Assembler::notZero, not_null);
// We are making a call. Increment the count for null receiver.
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
jmp(skip_receiver_profile);
bind(not_null);
}
// Record the receiver type.
record_klass_in_profile(receiver, mdp, reg2);
record_klass_in_profile(receiver, mdp, reg2, true);
bind(skip_receiver_profile);
// The method data pointer needs to be updated to reflect the new target.
@ -1263,10 +1265,14 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver, Register
void InterpreterMacroAssembler::record_klass_in_profile_helper(
Register receiver, Register mdp,
Register reg2,
int start_row, Label& done) {
if (TypeProfileWidth == 0)
Register reg2, int start_row,
Label& done, bool is_virtual_call) {
if (TypeProfileWidth == 0) {
if (is_virtual_call) {
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
}
return;
}
int last_row = VirtualCallData::row_limit() - 1;
assert(start_row <= last_row, "must be work left to do");
@ -1294,19 +1300,28 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
bind(next_test);
if (row == start_row) {
Label found_null;
// Failed the equality check on receiver[n]... Test for null.
testptr(reg2, reg2);
if (start_row == last_row) {
// The only thing left to do is handle the null case.
jcc(Assembler::notZero, done);
if (is_virtual_call) {
jccb(Assembler::zero, found_null);
// Receiver did not match any saved receiver and there is no empty row for it.
// Increment total counter to indicate polimorphic case.
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
jmp(done);
bind(found_null);
} else {
jcc(Assembler::notZero, done);
}
break;
}
// Since null is rare, make it be the branch-taken case.
Label found_null;
jcc(Assembler::zero, found_null);
// Put all the "Case 3" tests here.
record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done);
record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call);
// Found a null. Keep searching for a matching receiver,
// but remember that this is an empty (unused) slot.
@ -1323,16 +1338,18 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row));
movptr(reg2, (int32_t)DataLayout::counter_increment);
set_mdp_data_at(mdp, count_offset, reg2);
jmp(done);
if (start_row > 0) {
jmp(done);
}
}
void InterpreterMacroAssembler::record_klass_in_profile(Register receiver,
Register mdp,
Register reg2) {
Register mdp, Register reg2,
bool is_virtual_call) {
assert(ProfileInterpreter, "must be profiling");
Label done;
record_klass_in_profile_helper(receiver, mdp, reg2, 0, done);
record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call);
bind (done);
}
@ -1425,7 +1442,7 @@ void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass,
mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
// Record the object type.
record_klass_in_profile(klass, mdp, reg2);
record_klass_in_profile(klass, mdp, reg2, false);
assert(reg2 == rdi, "we know how to fix this blown reg");
restore_locals(); // Restore EDI
}

View File

@ -213,10 +213,10 @@ class InterpreterMacroAssembler: public MacroAssembler {
Label& not_equal_continue);
void record_klass_in_profile(Register receiver, Register mdp,
Register reg2);
Register reg2, bool is_virtual_call);
void record_klass_in_profile_helper(Register receiver, Register mdp,
Register reg2,
int start_row, Label& done);
Register reg2, int start_row,
Label& done, bool is_virtual_call);
void update_mdp_by_offset(Register mdp_in, int offset_of_offset);
void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp);

View File

@ -1262,17 +1262,19 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
// If no method data exists, go to profile_continue.
test_method_data_pointer(mdp, profile_continue);
// We are making a call. Increment the count.
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
Label skip_receiver_profile;
if (receiver_can_be_null) {
Label not_null;
testptr(receiver, receiver);
jcc(Assembler::zero, skip_receiver_profile);
jccb(Assembler::notZero, not_null);
// We are making a call. Increment the count for null receiver.
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
jmp(skip_receiver_profile);
bind(not_null);
}
// Record the receiver type.
record_klass_in_profile(receiver, mdp, reg2);
record_klass_in_profile(receiver, mdp, reg2, true);
bind(skip_receiver_profile);
// The method data pointer needs to be updated to reflect the new target.
@ -1296,10 +1298,14 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
// See below for example code.
void InterpreterMacroAssembler::record_klass_in_profile_helper(
Register receiver, Register mdp,
Register reg2,
int start_row, Label& done) {
if (TypeProfileWidth == 0)
Register reg2, int start_row,
Label& done, bool is_virtual_call) {
if (TypeProfileWidth == 0) {
if (is_virtual_call) {
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
}
return;
}
int last_row = VirtualCallData::row_limit() - 1;
assert(start_row <= last_row, "must be work left to do");
@ -1327,19 +1333,28 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
bind(next_test);
if (test_for_null_also) {
Label found_null;
// Failed the equality check on receiver[n]... Test for null.
testptr(reg2, reg2);
if (start_row == last_row) {
// The only thing left to do is handle the null case.
jcc(Assembler::notZero, done);
if (is_virtual_call) {
jccb(Assembler::zero, found_null);
// Receiver did not match any saved receiver and there is no empty row for it.
// Increment total counter to indicate polimorphic case.
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
jmp(done);
bind(found_null);
} else {
jcc(Assembler::notZero, done);
}
break;
}
// Since null is rare, make it be the branch-taken case.
Label found_null;
jcc(Assembler::zero, found_null);
// Put all the "Case 3" tests here.
record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done);
record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call);
// Found a null. Keep searching for a matching receiver,
// but remember that this is an empty (unused) slot.
@ -1356,7 +1371,9 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row));
movl(reg2, DataLayout::counter_increment);
set_mdp_data_at(mdp, count_offset, reg2);
jmp(done);
if (start_row > 0) {
jmp(done);
}
}
// Example state machine code for three profile rows:
@ -1368,7 +1385,7 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
// if (row[1].rec != NULL) {
// // degenerate decision tree, rooted at row[2]
// if (row[2].rec == rec) { row[2].incr(); goto done; }
// if (row[2].rec != NULL) { goto done; } // overflow
// if (row[2].rec != NULL) { count.incr(); goto done; } // overflow
// row[2].init(rec); goto done;
// } else {
// // remember row[1] is empty
@ -1381,14 +1398,15 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
// if (row[2].rec == rec) { row[2].incr(); goto done; }
// row[0].init(rec); goto done;
// }
// done:
void InterpreterMacroAssembler::record_klass_in_profile(Register receiver,
Register mdp,
Register reg2) {
Register mdp, Register reg2,
bool is_virtual_call) {
assert(ProfileInterpreter, "must be profiling");
Label done;
record_klass_in_profile_helper(receiver, mdp, reg2, 0, done);
record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call);
bind (done);
}
@ -1484,7 +1502,7 @@ void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass,
mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
// Record the object type.
record_klass_in_profile(klass, mdp, reg2);
record_klass_in_profile(klass, mdp, reg2, false);
}
update_mdp_by_constant(mdp, mdp_delta);

View File

@ -222,10 +222,10 @@ class InterpreterMacroAssembler: public MacroAssembler {
Label& not_equal_continue);
void record_klass_in_profile(Register receiver, Register mdp,
Register reg2);
Register reg2, bool is_virtual_call);
void record_klass_in_profile_helper(Register receiver, Register mdp,
Register reg2,
int start_row, Label& done);
Register reg2, int start_row,
Label& done, bool is_virtual_call);
void update_mdp_by_offset(Register mdp_in, int offset_of_offset);
void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2010 Sun Microsystems, Inc. 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
@ -907,7 +907,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
int total_args_passed,
int comp_args_on_stack,
const BasicType *sig_bt,
const VMRegPair *regs) {
const VMRegPair *regs,
AdapterFingerPrint* fingerprint) {
address i2c_entry = __ pc();
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
@ -954,7 +955,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
__ flush();
return new AdapterHandlerEntry(i2c_entry, c2i_entry, c2i_unverified_entry);
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
}
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2010 Sun Microsystems, Inc. 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
@ -778,7 +778,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
int total_args_passed,
int comp_args_on_stack,
const BasicType *sig_bt,
const VMRegPair *regs) {
const VMRegPair *regs,
AdapterFingerPrint* fingerprint) {
address i2c_entry = __ pc();
gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
@ -824,7 +825,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
__ flush();
return new AdapterHandlerEntry(i2c_entry, c2i_entry, c2i_unverified_entry);
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
}
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,

View File

@ -718,10 +718,8 @@ class StubGenerator: public StubCodeGenerator {
case BarrierSet::G1SATBCTLogging:
{
__ pusha(); // push registers
__ push(count);
__ push(start);
__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre)));
__ addptr(rsp, 2*wordSize);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre),
start, count);
__ popa();
}
break;
@ -752,10 +750,8 @@ class StubGenerator: public StubCodeGenerator {
case BarrierSet::G1SATBCTLogging:
{
__ pusha(); // push registers
__ push(count);
__ push(start);
__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post)));
__ addptr(rsp, 2*wordSize);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post),
start, count);
__ popa();
}
break;

View File

@ -1172,7 +1172,7 @@ class StubGenerator: public StubCodeGenerator {
__ movptr(c_rarg0, addr);
__ movptr(c_rarg1, count);
}
__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre)));
__ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre), 2);
__ popa();
}
break;
@ -1212,7 +1212,7 @@ class StubGenerator: public StubCodeGenerator {
__ shrptr(scratch, LogBytesPerHeapOop); // convert to element count
__ mov(c_rarg0, start);
__ mov(c_rarg1, scratch);
__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post)));
__ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), 2);
__ popa();
}
break;

View File

@ -235,6 +235,11 @@ reg_class xdb_reg7( XMM7a,XMM7b );
//----------SOURCE BLOCK-------------------------------------------------------
// This is a block of C++ code which provides values, functions, and
// definitions necessary in the rest of the architecture description
source_hpp %{
// Must be visible to the DFA in dfa_x86_32.cpp
extern bool is_operand_hi32_zero(Node* n);
%}
source %{
#define RELOC_IMM32 Assembler::imm_operand
#define RELOC_DISP32 Assembler::disp32_operand
@ -1485,6 +1490,21 @@ const RegMask Matcher::method_handle_invoke_SP_save_mask() {
return EBP_REG_mask;
}
// Returns true if the high 32 bits of the value is known to be zero.
bool is_operand_hi32_zero(Node* n) {
int opc = n->Opcode();
if (opc == Op_LoadUI2L) {
return true;
}
if (opc == Op_AndL) {
Node* o2 = n->in(2);
if (o2->is_Con() && (o2->get_long() & 0xFFFFFFFF00000000LL) == 0LL) {
return true;
}
}
return false;
}
%}
//----------ENCODING BLOCK-----------------------------------------------------
@ -8599,6 +8619,63 @@ instruct mulL_eReg(eADXRegL dst, eRegL src, eRegI tmp, eFlagsReg cr) %{
ins_pipe( pipe_slow );
%}
// Multiply Register Long where the left operand's high 32 bits are zero
instruct mulL_eReg_lhi0(eADXRegL dst, eRegL src, eRegI tmp, eFlagsReg cr) %{
predicate(is_operand_hi32_zero(n->in(1)));
match(Set dst (MulL dst src));
effect(KILL cr, TEMP tmp);
ins_cost(2*100+2*400);
// Basic idea: lo(result) = lo(x_lo * y_lo)
// hi(result) = hi(x_lo * y_lo) + lo(x_lo * y_hi) where lo(x_hi * y_lo) = 0 because x_hi = 0
format %{ "MOV $tmp,$src.hi\n\t"
"IMUL $tmp,EAX\n\t"
"MUL EDX:EAX,$src.lo\n\t"
"ADD EDX,$tmp" %}
ins_encode %{
__ movl($tmp$$Register, HIGH_FROM_LOW($src$$Register));
__ imull($tmp$$Register, rax);
__ mull($src$$Register);
__ addl(rdx, $tmp$$Register);
%}
ins_pipe( pipe_slow );
%}
// Multiply Register Long where the right operand's high 32 bits are zero
instruct mulL_eReg_rhi0(eADXRegL dst, eRegL src, eRegI tmp, eFlagsReg cr) %{
predicate(is_operand_hi32_zero(n->in(2)));
match(Set dst (MulL dst src));
effect(KILL cr, TEMP tmp);
ins_cost(2*100+2*400);
// Basic idea: lo(result) = lo(x_lo * y_lo)
// hi(result) = hi(x_lo * y_lo) + lo(x_hi * y_lo) where lo(x_lo * y_hi) = 0 because y_hi = 0
format %{ "MOV $tmp,$src.lo\n\t"
"IMUL $tmp,EDX\n\t"
"MUL EDX:EAX,$src.lo\n\t"
"ADD EDX,$tmp" %}
ins_encode %{
__ movl($tmp$$Register, $src$$Register);
__ imull($tmp$$Register, rdx);
__ mull($src$$Register);
__ addl(rdx, $tmp$$Register);
%}
ins_pipe( pipe_slow );
%}
// Multiply Register Long where the left and the right operands' high 32 bits are zero
instruct mulL_eReg_hi0(eADXRegL dst, eRegL src, eFlagsReg cr) %{
predicate(is_operand_hi32_zero(n->in(1)) && is_operand_hi32_zero(n->in(2)));
match(Set dst (MulL dst src));
effect(KILL cr);
ins_cost(1*400);
// Basic idea: lo(result) = lo(x_lo * y_lo)
// hi(result) = hi(x_lo * y_lo) where lo(x_hi * y_lo) = 0 and lo(x_lo * y_hi) = 0 because x_hi = 0 and y_hi = 0
format %{ "MUL EDX:EAX,$src.lo\n\t" %}
ins_encode %{
__ mull($src$$Register);
%}
ins_pipe( pipe_slow );
%}
// Multiply Register Long by small constant
instruct mulL_eReg_con(eADXRegL dst, immL_127 src, eRegI tmp, eFlagsReg cr) %{
match(Set dst (MulL dst src));

View File

@ -1,6 +1,6 @@
/*
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2007, 2008 Red Hat, Inc.
* Copyright 2007, 2008, 2009, 2010 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -47,6 +47,10 @@ address InterpreterGenerator::generate_method_handle_entry() {
return ShouldNotCallThisEntry();
}
bool AbstractInterpreter::can_be_compiled(methodHandle m) {
return true;
}
int AbstractInterpreter::size_activation(methodOop method,
int tempcount,
int popframe_extra_args,

View File

@ -1,6 +1,6 @@
/*
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2007, 2008, 2009 Red Hat, Inc.
* Copyright 2007, 2008, 2009, 2010 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -47,8 +47,10 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(
int total_args_passed,
int comp_args_on_stack,
const BasicType *sig_bt,
const VMRegPair *regs) {
return new AdapterHandlerEntry(
const VMRegPair *regs,
AdapterFingerPrint *fingerprint) {
return AdapterHandlerLibrary::new_entry(
fingerprint,
ShouldNotCallThisStub(),
ShouldNotCallThisStub(),
ShouldNotCallThisStub());

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -142,6 +142,9 @@ void os::run_periodic_checks() {
}
#ifndef _WIN64
// previous UnhandledExceptionFilter, if there is one
static LPTOP_LEVEL_EXCEPTION_FILTER prev_uef_handler = NULL;
LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo);
#endif
void os::init_system_properties_values() {
@ -260,7 +263,8 @@ void os::init_system_properties_values() {
}
#ifndef _WIN64
SetUnhandledExceptionFilter(Handle_FLT_Exception);
// set our UnhandledExceptionFilter and save any previous one
prev_uef_handler = SetUnhandledExceptionFilter(Handle_FLT_Exception);
#endif
// Done
@ -1969,7 +1973,7 @@ LONG Handle_IDiv_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) {
#ifndef _WIN64
//-----------------------------------------------------------------------------
LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) {
// handle exception caused by native mothod modifying control word
// handle exception caused by native method modifying control word
PCONTEXT ctx = exceptionInfo->ContextRecord;
DWORD exception_code = exceptionInfo->ExceptionRecord->ExceptionCode;
@ -1990,6 +1994,13 @@ LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) {
return EXCEPTION_CONTINUE_EXECUTION;
}
}
if (prev_uef_handler != NULL) {
// We didn't handle this exception so pass it to the previous
// UnhandledExceptionFilter.
return (prev_uef_handler)(exceptionInfo);
}
return EXCEPTION_CONTINUE_SEARCH;
}
#else //_WIN64

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2010 Sun Microsystems, Inc. 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
@ -1496,7 +1496,7 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
unsigned i;
// Generate Expand function header
fprintf(fp,"MachNode *%sNode::Expand(State *state, Node_List &proj_list) {\n", node->_ident);
fprintf(fp,"MachNode *%sNode::Expand(State *state, Node_List &proj_list, Node* mem) {\n", node->_ident);
fprintf(fp,"Compile* C = Compile::current();\n");
// Generate expand code
if( node->expands() ) {
@ -1546,15 +1546,16 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
// Build a mapping from operand index to input edges
fprintf(fp," unsigned idx0 = oper_input_base();\n");
// The order in which inputs are added to a node is very
// The order in which the memory input is added to a node is very
// strange. Store nodes get a memory input before Expand is
// called and all other nodes get it afterwards so
// oper_input_base is wrong during expansion. This code adjusts
// is so that expansion will work correctly.
bool missing_memory_edge = node->_matrule->needs_ideal_memory_edge(_globalNames) &&
node->is_ideal_store() == Form::none;
if (missing_memory_edge) {
fprintf(fp," idx0--; // Adjust base because memory edge hasn't been inserted yet\n");
// called and other nodes get it afterwards or before depending on
// match order so oper_input_base is wrong during expansion. This
// code adjusts it so that expansion will work correctly.
int has_memory_edge = node->_matrule->needs_ideal_memory_edge(_globalNames);
if (has_memory_edge) {
fprintf(fp," if (mem == (Node*)1) {\n");
fprintf(fp," idx0--; // Adjust base because memory edge hasn't been inserted yet\n");
fprintf(fp," }\n");
}
for( i = 0; i < node->num_opnds(); i++ ) {
@ -1611,9 +1612,11 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
int node_mem_op = node->memory_operand(_globalNames);
assert( node_mem_op != InstructForm::NO_MEMORY_OPERAND,
"expand rule member needs memory but top-level inst doesn't have any" );
if (!missing_memory_edge) {
if (has_memory_edge) {
// Copy memory edge
fprintf(fp," n%d->add_req(_in[1]);\t// Add memory edge\n", cnt);
fprintf(fp," if (mem != (Node*)1) {\n");
fprintf(fp," n%d->add_req(_in[1]);\t// Add memory edge\n", cnt);
fprintf(fp," }\n");
}
}
@ -1689,7 +1692,7 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
} // done iterating over a new instruction's operands
// Invoke Expand() for the newly created instruction.
fprintf(fp," result = n%d->Expand( state, proj_list );\n", cnt);
fprintf(fp," result = n%d->Expand( state, proj_list, mem );\n", cnt);
assert( !new_inst->expands(), "Do not have complete support for recursive expansion");
} // done iterating over new instructions
fprintf(fp,"\n");

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2010 Sun Microsystems, Inc. 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
@ -1754,7 +1754,7 @@ void ArchDesc::declareClasses(FILE *fp) {
instr->has_temps() ||
instr->_matrule != NULL &&
instr->num_opnds() != instr->num_unique_opnds() ) {
fprintf(fp," virtual MachNode *Expand(State *state, Node_List &proj_list);\n");
fprintf(fp," virtual MachNode *Expand(State *state, Node_List &proj_list, Node* mem);\n");
}
if (instr->is_pinned(_globalNames)) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -39,6 +39,7 @@ public:
Dtrace_trap = OSR_Entry, // dtrace probes can never have an OSR entry so reuse it
Exceptions, // Offset where exception handler lives
Deopt, // Offset where deopt handler lives
DeoptMH, // Offset where MethodHandle deopt handler lives
max_Entries };
// special value to note codeBlobs where profile (forte) stack walking is
@ -51,12 +52,13 @@ private:
public:
CodeOffsets() {
_values[Entry] = 0;
_values[Entry ] = 0;
_values[Verified_Entry] = 0;
_values[Frame_Complete] = frame_never_safe;
_values[OSR_Entry] = 0;
_values[Exceptions] = -1;
_values[Deopt] = -1;
_values[OSR_Entry ] = 0;
_values[Exceptions ] = -1;
_values[Deopt ] = -1;
_values[DeoptMH ] = -1;
}
int value(Entries e) { return _values[e]; }

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2010 Sun Microsystems, Inc. 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
@ -205,6 +205,8 @@ void Compilation::emit_lir() {
void Compilation::emit_code_epilog(LIR_Assembler* assembler) {
CHECK_BAILOUT();
CodeOffsets* code_offsets = assembler->offsets();
// generate code or slow cases
assembler->emit_slow_case_stubs();
CHECK_BAILOUT();
@ -213,10 +215,18 @@ void Compilation::emit_code_epilog(LIR_Assembler* assembler) {
assembler->emit_exception_entries(exception_info_list());
CHECK_BAILOUT();
// generate code for exception handler
assembler->emit_exception_handler();
// Generate code for exception handler.
code_offsets->set_value(CodeOffsets::Exceptions, assembler->emit_exception_handler());
CHECK_BAILOUT();
assembler->emit_deopt_handler();
// Generate code for deopt handler.
code_offsets->set_value(CodeOffsets::Deopt, assembler->emit_deopt_handler());
CHECK_BAILOUT();
// Generate code for MethodHandle deopt handler. We can use the
// same code as for the normal deopt handler, we just need a
// different entry point address.
code_offsets->set_value(CodeOffsets::DeoptMH, assembler->emit_deopt_handler());
CHECK_BAILOUT();
// done

View File

@ -1,5 +1,5 @@
/*
* Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2000-2010 Sun Microsystems, Inc. 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
@ -133,9 +133,9 @@ class LIR_Assembler: public CompilationResourceObj {
void add_call_info_here(CodeEmitInfo* info) { add_call_info(code_offset(), info); }
// code patterns
void emit_exception_handler();
int emit_exception_handler();
void emit_exception_entries(ExceptionInfoList* info_list);
void emit_deopt_handler();
int emit_deopt_handler();
void emit_code(BlockList* hir);
void emit_block(BlockBegin* block);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2005-2010 Sun Microsystems, Inc. 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
@ -1765,7 +1765,7 @@ void LIRGenerator::do_Throw(Throw* x) {
__ null_check(exception_opr, new CodeEmitInfo(info, true));
}
if (compilation()->env()->jvmti_can_post_exceptions() &&
if (compilation()->env()->jvmti_can_post_on_exceptions() &&
!block()->is_set(BlockBegin::default_exception_handler_flag)) {
// we need to go through the exception lookup path to get JVMTI
// notification done

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2010 Sun Microsystems, Inc. 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
@ -110,8 +110,8 @@ static void deopt_caller() {
RegisterMap reg_map(thread, false);
frame runtime_frame = thread->last_frame();
frame caller_frame = runtime_frame.sender(&reg_map);
VM_DeoptimizeFrame deopt(thread, caller_frame.id());
VMThread::execute(&deopt);
// bypass VM_DeoptimizeFrame and deoptimize the frame directly
Deoptimization::deoptimize_frame(thread, caller_frame.id());
assert(caller_is_deopted(), "Must be deoptimized");
}
}
@ -354,7 +354,7 @@ JRT_END
JRT_ENTRY(void, Runtime1::post_jvmti_exception_throw(JavaThread* thread))
if (JvmtiExport::can_post_exceptions()) {
if (JvmtiExport::can_post_on_exceptions()) {
vframeStream vfst(thread, true);
address bcp = vfst.method()->bcp_from(vfst.bci());
JvmtiExport::post_exception_throw(thread, vfst.method(), bcp, thread->exception_oop());
@ -437,7 +437,7 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
bool guard_pages_enabled = thread->stack_yellow_zone_enabled();
if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack();
if (JvmtiExport::can_post_exceptions()) {
if (JvmtiExport::can_post_on_exceptions()) {
// To ensure correct notification of exception catches and throws
// we have to deoptimize here. If we attempted to notify the
// catches and throws during this exception lookup it's possible

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2010 Sun Microsystems, Inc. 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
@ -178,7 +178,7 @@ void ciEnv::cache_jvmti_state() {
_jvmti_can_hotswap_or_post_breakpoint = JvmtiExport::can_hotswap_or_post_breakpoint();
_jvmti_can_examine_or_deopt_anywhere = JvmtiExport::can_examine_or_deopt_anywhere();
_jvmti_can_access_local_variables = JvmtiExport::can_access_local_variables();
_jvmti_can_post_exceptions = JvmtiExport::can_post_exceptions();
_jvmti_can_post_on_exceptions = JvmtiExport::can_post_on_exceptions();
}
// ------------------------------------------------------------------
@ -891,8 +891,8 @@ void ciEnv::register_method(ciMethod* target,
JvmtiExport::can_examine_or_deopt_anywhere()) ||
(!jvmti_can_access_local_variables() &&
JvmtiExport::can_access_local_variables()) ||
(!jvmti_can_post_exceptions() &&
JvmtiExport::can_post_exceptions()) )) {
(!jvmti_can_post_on_exceptions() &&
JvmtiExport::can_post_on_exceptions()) )) {
record_failure("Jvmti state change invalidated dependencies");
}
@ -962,18 +962,10 @@ void ciEnv::register_method(ciMethod* target,
if (nm == NULL) {
// The CodeCache is full. Print out warning and disable compilation.
record_failure("code cache is full");
UseInterpreter = true;
if (UseCompiler || AlwaysCompileLoopMethods ) {
#ifndef PRODUCT
warning("CodeCache is full. Compiler has been disabled");
if (CompileTheWorld || ExitOnFullCodeCache) {
before_exit(JavaThread::current());
exit_globals(); // will delete tty
vm_direct_exit(CompileTheWorld ? 0 : 1);
}
#endif
UseCompiler = false;
AlwaysCompileLoopMethods = false;
{
MutexUnlocker ml(Compile_lock);
MutexUnlocker locker(MethodCompileQueue_lock);
CompileBroker::handle_full_code_cache();
}
} else {
NOT_PRODUCT(nm->set_has_debug_info(has_debug_info); )

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2010 Sun Microsystems, Inc. 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
@ -57,7 +57,7 @@ private:
bool _jvmti_can_hotswap_or_post_breakpoint;
bool _jvmti_can_examine_or_deopt_anywhere;
bool _jvmti_can_access_local_variables;
bool _jvmti_can_post_exceptions;
bool _jvmti_can_post_on_exceptions;
// Cache DTrace flags
bool _dtrace_extended_probes;
@ -259,7 +259,7 @@ public:
bool jvmti_can_hotswap_or_post_breakpoint() const { return _jvmti_can_hotswap_or_post_breakpoint; }
bool jvmti_can_examine_or_deopt_anywhere() const { return _jvmti_can_examine_or_deopt_anywhere; }
bool jvmti_can_access_local_variables() const { return _jvmti_can_access_local_variables; }
bool jvmti_can_post_exceptions() const { return _jvmti_can_post_exceptions; }
bool jvmti_can_post_on_exceptions() const { return _jvmti_can_post_on_exceptions; }
// Cache DTrace flags
void cache_dtrace_flags();

View File

@ -436,15 +436,20 @@ ciCallProfile ciMethod::call_profile_at_bci(int bci) {
// we will set result._method also.
}
// Determine call site's morphism.
// The call site count could be == (receivers_count_total + 1)
// not only in the case of a polymorphic call but also in the case
// when a method data snapshot is taken after the site count was updated
// but before receivers counters were updated.
if (morphism == result._limit) {
// There were no array klasses and morphism <= MorphismLimit.
if (morphism < ciCallProfile::MorphismLimit ||
morphism == ciCallProfile::MorphismLimit &&
(receivers_count_total+1) >= count) {
// The call site count is 0 with known morphism (onlt 1 or 2 receivers)
// or < 0 in the case of a type check failured for checkcast, aastore, instanceof.
// The call site count is > 0 in the case of a polymorphic virtual call.
if (morphism > 0 && morphism == result._limit) {
// The morphism <= MorphismLimit.
if ((morphism < ciCallProfile::MorphismLimit) ||
(morphism == ciCallProfile::MorphismLimit && count == 0)) {
#ifdef ASSERT
if (count > 0) {
tty->print_cr("bci: %d", bci);
this->print_codes();
assert(false, "this call site should not be polymorphic");
}
#endif
result._morphism = morphism;
}
}
@ -452,10 +457,8 @@ ciCallProfile ciMethod::call_profile_at_bci(int bci) {
// zero or less, presume that this is a typecheck profile and
// do nothing. Otherwise, increase count to be the sum of all
// receiver's counts.
if (count > 0) {
if (count < receivers_count_total) {
count = receivers_count_total;
}
if (count >= 0) {
count += receivers_count_total;
}
}
result._count = count;

View File

@ -1249,6 +1249,7 @@ void ClassLoader::compile_the_world() {
}
int ClassLoader::_compile_the_world_counter = 0;
static int _codecache_sweep_counter = 0;
void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
int len = (int)strlen(name);
@ -1293,6 +1294,13 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
for (int n = 0; n < k->methods()->length(); n++) {
methodHandle m (THREAD, methodOop(k->methods()->obj_at(n)));
if (CompilationPolicy::canBeCompiled(m)) {
if (++_codecache_sweep_counter == CompileTheWorldSafepointInterval) {
// Give sweeper a chance to keep up with CTW
VM_ForceSafepoint op;
VMThread::execute(&op);
_codecache_sweep_counter = 0;
}
// Force compilation
CompileBroker::compile_method(m, InvocationEntryBci,
methodHandle(), 0, "CTW", THREAD);

View File

@ -96,6 +96,7 @@ int CodeCache::_number_of_blobs = 0;
int CodeCache::_number_of_nmethods_with_dependencies = 0;
bool CodeCache::_needs_cache_clean = false;
nmethod* CodeCache::_scavenge_root_nmethods = NULL;
nmethod* CodeCache::_saved_nmethods = NULL;
CodeBlob* CodeCache::first() {
@ -395,6 +396,85 @@ void CodeCache::verify_perm_nmethods(CodeBlobClosure* f_or_null) {
}
#endif //PRODUCT
nmethod* CodeCache::find_and_remove_saved_code(methodOop m) {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
nmethod* saved = _saved_nmethods;
nmethod* prev = NULL;
while (saved != NULL) {
if (saved->is_in_use() && saved->method() == m) {
if (prev != NULL) {
prev->set_saved_nmethod_link(saved->saved_nmethod_link());
} else {
_saved_nmethods = saved->saved_nmethod_link();
}
assert(saved->is_speculatively_disconnected(), "shouldn't call for other nmethods");
saved->set_speculatively_disconnected(false);
saved->set_saved_nmethod_link(NULL);
if (PrintMethodFlushing) {
saved->print_on(tty, " ### nmethod is reconnected");
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("nmethod_reconnected compile_id='%3d'", saved->compile_id());
xtty->method(methodOop(m));
xtty->stamp();
xtty->end_elem();
}
return saved;
}
prev = saved;
saved = saved->saved_nmethod_link();
}
return NULL;
}
void CodeCache::remove_saved_code(nmethod* nm) {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
assert(nm->is_speculatively_disconnected(), "shouldn't call for other nmethods");
nmethod* saved = _saved_nmethods;
nmethod* prev = NULL;
while (saved != NULL) {
if (saved == nm) {
if (prev != NULL) {
prev->set_saved_nmethod_link(saved->saved_nmethod_link());
} else {
_saved_nmethods = saved->saved_nmethod_link();
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("nmethod_removed compile_id='%3d'", nm->compile_id());
xtty->stamp();
xtty->end_elem();
}
return;
}
prev = saved;
saved = saved->saved_nmethod_link();
}
ShouldNotReachHere();
}
void CodeCache::speculatively_disconnect(nmethod* nm) {
assert_locked_or_safepoint(CodeCache_lock);
assert(nm->is_in_use() && !nm->is_speculatively_disconnected(), "should only disconnect live nmethods");
nm->set_saved_nmethod_link(_saved_nmethods);
_saved_nmethods = nm;
if (PrintMethodFlushing) {
nm->print_on(tty, " ### nmethod is speculatively disconnected");
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("nmethod_disconnected compile_id='%3d'", nm->compile_id());
xtty->method(methodOop(nm->method()));
xtty->stamp();
xtty->end_elem();
}
nm->method()->clear_code();
nm->set_speculatively_disconnected(true);
}
void CodeCache::gc_prologue() {
assert(!nmethod::oops_do_marking_is_active(), "oops_do_marking_epilogue must be called");
}

View File

@ -46,6 +46,7 @@ class CodeCache : AllStatic {
static int _number_of_nmethods_with_dependencies;
static bool _needs_cache_clean;
static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link()
static nmethod* _saved_nmethods; // linked via nm->saved_nmethod_look()
static void verify_if_often() PRODUCT_RETURN;
@ -141,11 +142,16 @@ class CodeCache : AllStatic {
static size_t capacity() { return _heap->capacity(); }
static size_t max_capacity() { return _heap->max_capacity(); }
static size_t unallocated_capacity() { return _heap->unallocated_capacity(); }
static bool needs_flushing() { return unallocated_capacity() < CodeCacheFlushingMinimumFreeSpace; }
static bool needs_cache_clean() { return _needs_cache_clean; }
static void set_needs_cache_clean(bool v) { _needs_cache_clean = v; }
static void clear_inline_caches(); // clear all inline caches
static nmethod* find_and_remove_saved_code(methodOop m);
static void remove_saved_code(nmethod* nm);
static void speculatively_disconnect(nmethod* nm);
// Deoptimization
static int mark_for_deoptimization(DepChange& changes);
#ifdef HOTSWAP

View File

@ -843,13 +843,15 @@ static bool count_find_witness_calls() {
if (occasional_print || final_stats) {
// Every now and then dump a little info about dependency searching.
if (xtty != NULL) {
xtty->elem("deps_find_witness calls='%d' steps='%d' recursions='%d' singles='%d'",
ttyLocker ttyl;
xtty->elem("deps_find_witness calls='%d' steps='%d' recursions='%d' singles='%d'",
deps_find_witness_calls,
deps_find_witness_steps,
deps_find_witness_recursions,
deps_find_witness_singles);
}
if (final_stats || (TraceDependencies && WizardMode)) {
ttyLocker ttyl;
tty->print_cr("Dependency check (find_witness) "
"calls=%d, steps=%d (avg=%.1f), recursions=%d, singles=%d",
deps_find_witness_calls,

View File

@ -0,0 +1,115 @@
/*
* Copyright 2010 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* This header file defines the data structures sent by the VM
* through the JVMTI CompiledMethodLoad callback function via the
* "void * compile_info" parameter. The memory pointed to by the
* compile_info parameter may not be referenced after returning from
* the CompiledMethodLoad callback. These are VM implementation
* specific data structures that may evolve in future releases. A
* JVMTI agent should interpret a non-NULL compile_info as a pointer
* to a region of memory containing a list of records. In a typical
* usage scenario, a JVMTI agent would cast each record to a
* jvmtiCompiledMethodLoadRecordHeader, a struct that represents
* arbitrary information. This struct contains a kind field to indicate
* the kind of information being passed, and a pointer to the next
* record. If the kind field indicates inlining information, then the
* agent would cast the record to a jvmtiCompiledMethodLoadInlineRecord.
* This record contains an array of PCStackInfo structs, which indicate
* for every pc address what are the methods on the invocation stack.
* The "methods" and "bcis" fields in each PCStackInfo struct specify a
* 1-1 mapping between these inlined methods and their bytecode indices.
* This can be used to derive the proper source lines of the inlined
* methods.
*/
#ifndef _JVMTI_CMLR_H_
#define _JVMTI_CMLR_H_
enum {
JVMTI_CMLR_MAJOR_VERSION_1 = 0x00000001,
JVMTI_CMLR_MINOR_VERSION_0 = 0x00000000,
JVMTI_CMLR_MAJOR_VERSION = 0x00000001,
JVMTI_CMLR_MINOR_VERSION = 0x00000000
/*
* This comment is for the "JDK import from HotSpot" sanity check:
* version: 1.0.0
*/
};
typedef enum {
JVMTI_CMLR_DUMMY = 1,
JVMTI_CMLR_INLINE_INFO = 2
} jvmtiCMLRKind;
/*
* Record that represents arbitrary information passed through JVMTI
* CompiledMethodLoadEvent void pointer.
*/
typedef struct _jvmtiCompiledMethodLoadRecordHeader {
jvmtiCMLRKind kind; /* id for the kind of info passed in the record */
jint majorinfoversion; /* major and minor info version values. Init'ed */
jint minorinfoversion; /* to current version value in jvmtiExport.cpp. */
struct _jvmtiCompiledMethodLoadRecordHeader* next;
} jvmtiCompiledMethodLoadRecordHeader;
/*
* Record that gives information about the methods on the compile-time
* stack at a specific pc address of a compiled method. Each element in
* the methods array maps to same element in the bcis array.
*/
typedef struct _PCStackInfo {
void* pc; /* the pc address for this compiled method */
jint numstackframes; /* number of methods on the stack */
jmethodID* methods; /* array of numstackframes method ids */
jint* bcis; /* array of numstackframes bytecode indices */
} PCStackInfo;
/*
* Record that contains inlining information for each pc address of
* an nmethod.
*/
typedef struct _jvmtiCompiledMethodLoadInlineRecord {
jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
jint numpcs; /* number of pc descriptors in this nmethod */
PCStackInfo* pcinfo; /* array of numpcs pc descriptors */
} jvmtiCompiledMethodLoadInlineRecord;
/*
* Dummy record used to test that we can pass records with different
* information through the void pointer provided that they can be cast
* to a jvmtiCompiledMethodLoadRecordHeader.
*/
typedef struct _jvmtiCompiledMethodLoadDummyRecord {
jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
char message[50];
} jvmtiCompiledMethodLoadDummyRecord;
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -587,11 +587,13 @@ nmethod::nmethod(
_osr_link = NULL;
_scavenge_root_link = NULL;
_scavenge_root_state = 0;
_saved_nmethod_link = NULL;
_compiler = NULL;
// We have no exception handler or deopt handler make the
// values something that will never match a pc like the nmethod vtable entry
_exception_offset = 0;
_deoptimize_offset = 0;
_deoptimize_mh_offset = 0;
_orig_pc_offset = 0;
#ifdef HAVE_DTRACE_H
_trap_offset = 0;
@ -682,6 +684,7 @@ nmethod::nmethod(
// values something that will never match a pc like the nmethod vtable entry
_exception_offset = 0;
_deoptimize_offset = 0;
_deoptimize_mh_offset = 0;
_trap_offset = offsets->value(CodeOffsets::Dtrace_trap);
_orig_pc_offset = 0;
_stub_offset = data_offset();
@ -794,6 +797,7 @@ nmethod::nmethod(
// Exception handler and deopt handler are in the stub section
_exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions);
_deoptimize_offset = _stub_offset + offsets->value(CodeOffsets::Deopt);
_deoptimize_mh_offset = _stub_offset + offsets->value(CodeOffsets::DeoptMH);
_consts_offset = instructions_offset() + code_buffer->total_offset_of(code_buffer->consts()->start());
_scopes_data_offset = data_offset();
_scopes_pcs_offset = _scopes_data_offset + round_to(debug_info->data_size (), oopSize);
@ -1033,7 +1037,7 @@ void nmethod::cleanup_inline_caches() {
if( cb != NULL && cb->is_nmethod() ) {
nmethod* nm = (nmethod*)cb;
// Clean inline caches pointing to both zombie and not_entrant methods
if (!nm->is_in_use()) ic->set_to_clean();
if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean();
}
break;
}
@ -1043,7 +1047,7 @@ void nmethod::cleanup_inline_caches() {
if( cb != NULL && cb->is_nmethod() ) {
nmethod* nm = (nmethod*)cb;
// Clean inline caches pointing to both zombie and not_entrant methods
if (!nm->is_in_use()) csc->set_to_clean();
if (!nm->is_in_use() || (nm->method()->code() != nm)) csc->set_to_clean();
}
break;
}
@ -1113,7 +1117,6 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) {
if (_method->code() == this) {
_method->clear_code(); // Break a cycle
}
inc_decompile_count(); // Last chance to make a mark on the MDO
_method = NULL; // Clear the method of this dead nmethod
}
// Make the class unloaded - i.e., change state and notify sweeper
@ -1173,15 +1176,17 @@ void nmethod::log_state_change() const {
bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
assert(state == zombie || state == not_entrant, "must be zombie or not_entrant");
// If the method is already zombie there is nothing to do
if (is_zombie()) {
return false;
}
bool was_alive = false;
// Make sure the nmethod is not flushed in case of a safepoint in code below.
nmethodLocker nml(this);
{
// If the method is already zombie there is nothing to do
if (is_zombie()) {
return false;
}
// invalidate osr nmethod before acquiring the patching lock since
// they both acquire leaf locks and we don't want a deadlock.
// This logic is equivalent to the logic below for patching the
@ -1219,6 +1224,8 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
assert(state == not_entrant, "other cases may need to be handled differently");
}
was_alive = is_in_use(); // Read state under lock
// Change state
flags.state = state;
@ -1245,8 +1252,11 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
mark_as_seen_on_stack();
}
// It's a true state change, so mark the method as decompiled.
inc_decompile_count();
if (was_alive) {
// It's a true state change, so mark the method as decompiled.
// Do it only for transition from alive.
inc_decompile_count();
}
// zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event
// and it hasn't already been reported for this nmethod then report it now.
@ -1312,7 +1322,8 @@ void nmethod::flush() {
// completely deallocate this method
EventMark m("flushing nmethod " INTPTR_FORMAT " %s", this, "");
if (PrintMethodFlushing) {
tty->print_cr("*flushing nmethod " INTPTR_FORMAT ". Live blobs: %d", this, CodeCache::nof_blobs());
tty->print_cr("*flushing nmethod %3d/" INTPTR_FORMAT ". Live blobs:" UINT32_FORMAT "/Free CodeCache:" SIZE_FORMAT "Kb",
_compile_id, this, CodeCache::nof_blobs(), CodeCache::unallocated_capacity()/1024);
}
// We need to deallocate any ExceptionCache data.
@ -1330,6 +1341,10 @@ void nmethod::flush() {
CodeCache::drop_scavenge_root_nmethod(this);
}
if (is_speculatively_disconnected()) {
CodeCache::remove_saved_code(this);
}
((CodeBlob*)(this))->flush();
CodeCache::free(this);
@ -2031,9 +2046,21 @@ void nmethodLocker::unlock_nmethod(nmethod* nm) {
guarantee(nm->_lock_count >= 0, "unmatched nmethod lock/unlock");
}
bool nmethod::is_deopt_pc(address pc) {
bool ret = pc == deopt_handler_begin();
return ret;
// -----------------------------------------------------------------------------
// nmethod::get_deopt_original_pc
//
// Return the original PC for the given PC if:
// (a) the given PC belongs to a nmethod and
// (b) it is a deopt PC
address nmethod::get_deopt_original_pc(const frame* fr) {
if (fr->cb() == NULL) return NULL;
nmethod* nm = fr->cb()->as_nmethod_or_null();
if (nm != NULL && nm->is_deopt_pc(fr->pc()))
return nm->get_original_pc(fr);
return NULL;
}
@ -2404,6 +2431,8 @@ void nmethod::print_nmethod_labels(outputStream* stream, address block_begin) {
if (block_begin == verified_entry_point()) stream->print_cr("[Verified Entry Point]");
if (block_begin == exception_begin()) stream->print_cr("[Exception Handler]");
if (block_begin == stub_begin()) stream->print_cr("[Stub Code]");
if (block_begin == deopt_handler_begin()) stream->print_cr("[Deopt Handler Code]");
if (block_begin == deopt_mh_handler_begin()) stream->print_cr("[Deopt MH Handler Code]");
if (block_begin == consts_begin()) stream->print_cr("[Constants]");
if (block_begin == entry_point()) {
methodHandle m = method();

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -95,6 +95,8 @@ struct nmFlags {
unsigned int has_unsafe_access:1; // May fault due to unsafe access.
unsigned int has_method_handle_invokes:1; // Has this method MethodHandle invokes?
unsigned int speculatively_disconnected:1; // Marked for potential unload
void clear();
};
@ -137,6 +139,7 @@ class nmethod : public CodeBlob {
// To support simple linked-list chaining of nmethods:
nmethod* _osr_link; // from instanceKlass::osr_nmethods_head
nmethod* _scavenge_root_link; // from CodeCache::scavenge_root_nmethods
nmethod* _saved_nmethod_link; // from CodeCache::speculatively_disconnect
static nmethod* volatile _oops_do_mark_nmethods;
nmethod* volatile _oops_do_mark_link;
@ -145,8 +148,12 @@ class nmethod : public CodeBlob {
// Offsets for different nmethod parts
int _exception_offset;
// All deoptee's will resume execution at this location described by this offset
// All deoptee's will resume execution at this location described by
// this offset.
int _deoptimize_offset;
// All deoptee's at a MethodHandle call site will resume execution
// at this location described by this offset.
int _deoptimize_mh_offset;
#ifdef HAVE_DTRACE_H
int _trap_offset;
#endif // def HAVE_DTRACE_H
@ -329,24 +336,25 @@ class nmethod : public CodeBlob {
bool is_compiled_by_c2() const;
// boundaries for different parts
address code_begin () const { return _entry_point; }
address code_end () const { return header_begin() + _stub_offset ; }
address exception_begin () const { return header_begin() + _exception_offset ; }
address deopt_handler_begin() const { return header_begin() + _deoptimize_offset ; }
address stub_begin () const { return header_begin() + _stub_offset ; }
address stub_end () const { return header_begin() + _consts_offset ; }
address consts_begin () const { return header_begin() + _consts_offset ; }
address consts_end () const { return header_begin() + _scopes_data_offset ; }
address scopes_data_begin () const { return header_begin() + _scopes_data_offset ; }
address scopes_data_end () const { return header_begin() + _scopes_pcs_offset ; }
PcDesc* scopes_pcs_begin () const { return (PcDesc*)(header_begin() + _scopes_pcs_offset ); }
PcDesc* scopes_pcs_end () const { return (PcDesc*)(header_begin() + _dependencies_offset); }
address dependencies_begin () const { return header_begin() + _dependencies_offset ; }
address dependencies_end () const { return header_begin() + _handler_table_offset ; }
address handler_table_begin() const { return header_begin() + _handler_table_offset ; }
address handler_table_end () const { return header_begin() + _nul_chk_table_offset ; }
address nul_chk_table_begin() const { return header_begin() + _nul_chk_table_offset ; }
address nul_chk_table_end () const { return header_begin() + _nmethod_end_offset ; }
address code_begin () const { return _entry_point; }
address code_end () const { return header_begin() + _stub_offset ; }
address exception_begin () const { return header_begin() + _exception_offset ; }
address deopt_handler_begin () const { return header_begin() + _deoptimize_offset ; }
address deopt_mh_handler_begin() const { return header_begin() + _deoptimize_mh_offset ; }
address stub_begin () const { return header_begin() + _stub_offset ; }
address stub_end () const { return header_begin() + _consts_offset ; }
address consts_begin () const { return header_begin() + _consts_offset ; }
address consts_end () const { return header_begin() + _scopes_data_offset ; }
address scopes_data_begin () const { return header_begin() + _scopes_data_offset ; }
address scopes_data_end () const { return header_begin() + _scopes_pcs_offset ; }
PcDesc* scopes_pcs_begin () const { return (PcDesc*)(header_begin() + _scopes_pcs_offset ); }
PcDesc* scopes_pcs_end () const { return (PcDesc*)(header_begin() + _dependencies_offset) ; }
address dependencies_begin () const { return header_begin() + _dependencies_offset ; }
address dependencies_end () const { return header_begin() + _handler_table_offset ; }
address handler_table_begin () const { return header_begin() + _handler_table_offset ; }
address handler_table_end () const { return header_begin() + _nul_chk_table_offset ; }
address nul_chk_table_begin () const { return header_begin() + _nul_chk_table_offset ; }
address nul_chk_table_end () const { return header_begin() + _nmethod_end_offset ; }
int code_size () const { return code_end () - code_begin (); }
int stub_size () const { return stub_end () - stub_begin (); }
@ -413,6 +421,9 @@ class nmethod : public CodeBlob {
bool has_method_handle_invokes() const { return flags.has_method_handle_invokes; }
void set_has_method_handle_invokes(bool z) { flags.has_method_handle_invokes = z; }
bool is_speculatively_disconnected() const { return flags.speculatively_disconnected; }
void set_speculatively_disconnected(bool z) { flags.speculatively_disconnected = z; }
int level() const { return flags.level; }
void set_level(int newLevel) { check_safepoint(); flags.level = newLevel; }
@ -437,6 +448,9 @@ class nmethod : public CodeBlob {
nmethod* scavenge_root_link() const { return _scavenge_root_link; }
void set_scavenge_root_link(nmethod *n) { _scavenge_root_link = n; }
nmethod* saved_nmethod_link() const { return _saved_nmethod_link; }
void set_saved_nmethod_link(nmethod *n) { _saved_nmethod_link = n; }
public:
// Sweeper support
@ -515,7 +529,7 @@ class nmethod : public CodeBlob {
private:
ScopeDesc* scope_desc_in(address begin, address end);
address* orig_pc_addr(const frame* fr ) { return (address*) ((address)fr->unextended_sp() + _orig_pc_offset); }
address* orig_pc_addr(const frame* fr) { return (address*) ((address)fr->unextended_sp() + _orig_pc_offset); }
PcDesc* find_pc_desc_internal(address pc, bool approximate);
@ -538,13 +552,17 @@ class nmethod : public CodeBlob {
void copy_scopes_pcs(PcDesc* pcs, int count);
void copy_scopes_data(address buffer, int size);
// deopt
// return true is the pc is one would expect if the frame is being deopted.
bool is_deopt_pc(address pc);
// Deopt
// Return true is the PC is one would expect if the frame is being deopted.
bool is_deopt_pc (address pc) { return is_deopt_entry(pc) || is_deopt_mh_entry(pc); }
bool is_deopt_entry (address pc) { return pc == deopt_handler_begin(); }
bool is_deopt_mh_entry(address pc) { return pc == deopt_mh_handler_begin(); }
// Accessor/mutator for the original pc of a frame before a frame was deopted.
address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); }
void set_original_pc(const frame* fr, address pc) { *orig_pc_addr(fr) = pc; }
static address get_deopt_original_pc(const frame* fr);
// MethodHandle
bool is_method_handle_return(address return_pc);

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2010 Sun Microsystems, Inc. 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
@ -69,6 +69,7 @@ HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end,
bool CompileBroker::_initialized = false;
volatile bool CompileBroker::_should_block = false;
volatile jint CompileBroker::_should_compile_new_jobs = run_compilation;
// The installed compiler(s)
AbstractCompiler* CompileBroker::_compilers[2];
@ -986,6 +987,13 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
return method_code;
}
if (method->is_not_compilable(comp_level)) return NULL;
nmethod* saved = CodeCache::find_and_remove_saved_code(method());
if (saved != NULL) {
method->set_code(method, saved);
return saved;
}
} else {
// osr compilation
#ifndef TIERED
@ -1037,6 +1045,14 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
method->jmethod_id();
}
// If the compiler is shut off due to code cache flushing or otherwise,
// fail out now so blocking compiles dont hang the java thread
if (!should_compile_new_jobs() || (UseCodeCacheFlushing && CodeCache::needs_flushing())) {
method->invocation_counter()->decay();
method->backedge_counter()->decay();
return NULL;
}
// do the compilation
if (method->is_native()) {
if (!PreferInterpreterNativeStubs) {
@ -1116,7 +1132,7 @@ bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci,
// the specified level
if (is_native &&
(!CICompileNatives || !compiler(comp_level)->supports_native())) {
method->set_not_compilable();
method->set_not_compilable_quietly();
return true;
}
@ -1140,7 +1156,7 @@ bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci,
method->print_short_name(tty);
tty->cr();
}
method->set_not_compilable();
method->set_not_compilable_quietly();
}
return false;
@ -1173,7 +1189,7 @@ uint CompileBroker::assign_compile_id(methodHandle method, int osr_bci) {
}
// Method was not in the appropriate compilation range.
method->set_not_compilable();
method->set_not_compilable_quietly();
return 0;
}
@ -1325,26 +1341,13 @@ void CompileBroker::compiler_thread_loop() {
{
// We need this HandleMark to avoid leaking VM handles.
HandleMark hm(thread);
if (CodeCache::unallocated_capacity() < CodeCacheMinimumFreeSpace) {
// The CodeCache is full. Print out warning and disable compilation.
UseInterpreter = true;
if (UseCompiler || AlwaysCompileLoopMethods ) {
if (log != NULL) {
log->begin_elem("code_cache_full");
log->stamp();
log->end_elem();
}
#ifndef PRODUCT
warning("CodeCache is full. Compiler has been disabled");
if (CompileTheWorld || ExitOnFullCodeCache) {
before_exit(thread);
exit_globals(); // will delete tty
vm_direct_exit(CompileTheWorld ? 0 : 1);
}
#endif
UseCompiler = false;
AlwaysCompileLoopMethods = false;
}
// the code cache is really full
handle_full_code_cache();
} else if (UseCodeCacheFlushing && CodeCache::needs_flushing()) {
// Attempt to start cleaning the code cache while there is still a little headroom
NMethodSweeper::handle_full_code_cache(false);
}
CompileTask* task = queue->get();
@ -1369,7 +1372,7 @@ void CompileBroker::compiler_thread_loop() {
// Never compile a method if breakpoints are present in it
if (method()->number_of_breakpoints() == 0) {
// Compile the method.
if (UseCompiler || AlwaysCompileLoopMethods) {
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.
@ -1587,10 +1590,10 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
if (is_osr) {
method->set_not_osr_compilable();
} else {
method->set_not_compilable();
method->set_not_compilable_quietly();
}
} else if (compilable == ciEnv::MethodCompilable_not_at_tier) {
method->set_not_compilable(task->comp_level());
method->set_not_compilable_quietly(task->comp_level());
}
// Note that the queued_for_compilation bits are cleared without
@ -1613,6 +1616,38 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
}
// ------------------------------------------------------------------
// CompileBroker::handle_full_code_cache
//
// The CodeCache is full. Print out warning and disable compilation or
// try code cache cleaning so compilation can continue later.
void CompileBroker::handle_full_code_cache() {
UseInterpreter = true;
if (UseCompiler || AlwaysCompileLoopMethods ) {
CompilerThread* thread = CompilerThread::current();
CompileLog* log = thread->log();
if (log != NULL) {
log->begin_elem("code_cache_full");
log->stamp();
log->end_elem();
}
#ifndef PRODUCT
warning("CodeCache is full. Compiler has been disabled");
if (CompileTheWorld || ExitOnFullCodeCache) {
before_exit(JavaThread::current());
exit_globals(); // will delete tty
vm_direct_exit(CompileTheWorld ? 0 : 1);
}
#endif
if (UseCodeCacheFlushing) {
NMethodSweeper::handle_full_code_cache(true);
} else {
UseCompiler = false;
AlwaysCompileLoopMethods = false;
}
}
}
// ------------------------------------------------------------------
// CompileBroker::set_last_compile
//

View File

@ -193,6 +193,9 @@ class CompileBroker: AllStatic {
static bool _initialized;
static volatile bool _should_block;
// This flag can be used to stop compilation or turn it back on
static volatile jint _should_compile_new_jobs;
// The installed compiler(s)
static AbstractCompiler* _compilers[2];
@ -319,6 +322,7 @@ class CompileBroker: AllStatic {
static void compiler_thread_loop();
static uint get_compilation_id() { return _compilation_id; }
static bool is_idle();
// Set _should_block.
@ -328,6 +332,20 @@ class CompileBroker: AllStatic {
// Call this from the compiler at convenient points, to poll for _should_block.
static void maybe_block();
enum {
// Flags for toggling compiler activity
stop_compilation = 0,
run_compilation = 1
};
static bool should_compile_new_jobs() { return UseCompiler && (_should_compile_new_jobs == run_compilation); }
static bool set_should_compile_new_jobs(jint new_state) {
// Return success if the current caller set it
jint old = Atomic::cmpxchg(new_state, &_should_compile_new_jobs, 1-new_state);
return (old == (1-new_state));
}
static void handle_full_code_cache();
// Return total compilation ticks
static jlong total_compilation_ticks() {
return _perf_total_compilation != NULL ? _perf_total_compilation->get_value() : 0;

View File

@ -3655,9 +3655,7 @@ bool CMSCollector::markFromRootsWork(bool asynch) {
verify_work_stacks_empty();
verify_overflow_empty();
assert(_revisitStack.isEmpty(), "tabula rasa");
DEBUG_ONLY(RememberKlassesChecker cmx(CMSClassUnloadingEnabled);)
DEBUG_ONLY(RememberKlassesChecker cmx(should_unload_classes());)
bool result = false;
if (CMSConcurrentMTEnabled && ParallelCMSThreads > 0) {
result = do_marking_mt(asynch);
@ -4124,7 +4122,6 @@ void CMSConcMarkingTask::do_work_steal(int i) {
void CMSConcMarkingTask::coordinator_yield() {
assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
"CMS thread should hold CMS token");
DEBUG_ONLY(RememberKlassesChecker mux(false);)
// First give up the locks, then yield, then re-lock
// We should probably use a constructor/destructor idiom to
@ -4201,9 +4198,7 @@ bool CMSCollector::do_marking_mt(bool asynch) {
// Mutate the Refs discovery so it is MT during the
// multi-threaded marking phase.
ReferenceProcessorMTMutator mt(ref_processor(), num_workers > 1);
DEBUG_ONLY(RememberKlassesChecker cmx(CMSClassUnloadingEnabled);)
DEBUG_ONLY(RememberKlassesChecker cmx(should_unload_classes());)
conc_workers()->start_task(&tsk);
while (tsk.yielded()) {
tsk.coordinator_yield();
@ -4472,7 +4467,7 @@ size_t CMSCollector::preclean_work(bool clean_refs, bool clean_survivor) {
// for cleaner interfaces.
rp->preclean_discovered_references(
rp->is_alive_non_header(), &keep_alive, &complete_trace,
&yield_cl);
&yield_cl, should_unload_classes());
}
if (clean_survivor) { // preclean the active survivor space(s)
@ -4494,7 +4489,7 @@ size_t CMSCollector::preclean_work(bool clean_refs, bool clean_survivor) {
SurvivorSpacePrecleanClosure
sss_cl(this, _span, &_markBitMap, &_markStack,
&pam_cl, before_count, CMSYield);
DEBUG_ONLY(RememberKlassesChecker mx(CMSClassUnloadingEnabled);)
DEBUG_ONLY(RememberKlassesChecker mx(should_unload_classes());)
dng->from()->object_iterate_careful(&sss_cl);
dng->to()->object_iterate_careful(&sss_cl);
}
@ -4665,7 +4660,7 @@ size_t CMSCollector::preclean_mod_union_table(
verify_work_stacks_empty();
verify_overflow_empty();
sample_eden();
DEBUG_ONLY(RememberKlassesChecker mx(CMSClassUnloadingEnabled);)
DEBUG_ONLY(RememberKlassesChecker mx(should_unload_classes());)
stop_point =
gen->cmsSpace()->object_iterate_careful_m(dirtyRegion, cl);
}
@ -4753,7 +4748,7 @@ size_t CMSCollector::preclean_card_table(ConcurrentMarkSweepGeneration* gen,
sample_eden();
verify_work_stacks_empty();
verify_overflow_empty();
DEBUG_ONLY(RememberKlassesChecker mx(CMSClassUnloadingEnabled);)
DEBUG_ONLY(RememberKlassesChecker mx(should_unload_classes());)
HeapWord* stop_point =
gen->cmsSpace()->object_iterate_careful_m(dirtyRegion, cl);
if (stop_point != NULL) {
@ -4853,7 +4848,7 @@ void CMSCollector::checkpointRootsFinalWork(bool asynch,
assert(haveFreelistLocks(), "must have free list locks");
assert_lock_strong(bitMapLock());
DEBUG_ONLY(RememberKlassesChecker fmx(CMSClassUnloadingEnabled);)
DEBUG_ONLY(RememberKlassesChecker fmx(should_unload_classes());)
if (!init_mark_was_synchronous) {
// We might assume that we need not fill TLAB's when
// CMSScavengeBeforeRemark is set, because we may have just done

View File

@ -1004,7 +1004,12 @@ public:
// storage in the heap comes from a young region or not.
// See ReduceInitialCardMarks.
virtual bool can_elide_tlab_store_barriers() const {
return true;
// 6920090: Temporarily disabled, because of lingering
// instabilities related to RICM with G1. In the
// interim, the option ReduceInitialCardMarksForG1
// below is left solely as a debugging device at least
// until 6920109 fixes the instabilities.
return ReduceInitialCardMarksForG1;
}
virtual bool card_mark_must_follow_store() const {
@ -1026,6 +1031,8 @@ public:
// However, non-generational G1 (-XX:-G1Gen) appears to have
// bit-rotted so was not tested below.
virtual bool can_elide_initializing_store_barrier(oop new_obj) {
// Re 6920090, 6920109 above.
assert(ReduceInitialCardMarksForG1, "Else cannot be here");
assert(G1Gen || !is_in_young(new_obj),
"Non-generational G1 should never return true below");
return is_in_young(new_obj);

View File

@ -291,6 +291,10 @@
"a particular entry exceeds this value.") \
\
develop(bool, G1VerifyCTCleanup, false, \
"Verify card table cleanup.")
"Verify card table cleanup.") \
\
develop(bool, ReduceInitialCardMarksForG1, false, \
"When ReduceInitialCardMarks is true, this flag setting " \
" controls whether G1 allows the RICM optimization")
G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG)

View File

@ -66,7 +66,8 @@ void CollectedHeap::pre_initialize() {
// Used for ReduceInitialCardMarks (when COMPILER2 is used);
// otherwise remains unused.
#ifdef COMPLER2
_defer_initial_card_mark = ReduceInitialCardMarks && (DeferInitialCardMark || card_mark_must_follow_store());
_defer_initial_card_mark = ReduceInitialCardMarks && can_elide_tlab_store_barriers()
&& (DeferInitialCardMark || card_mark_must_follow_store());
#else
assert(_defer_initial_card_mark == false, "Who would set it?");
#endif

View File

@ -775,6 +775,7 @@ output.cpp allocation.inline.hpp
output.cpp assembler.inline.hpp
output.cpp callnode.hpp
output.cpp cfgnode.hpp
output.cpp compileBroker.hpp
output.cpp debugInfo.hpp
output.cpp debugInfoRec.hpp
output.cpp handles.inline.hpp

View File

@ -921,6 +921,7 @@ classFileStream.hpp top.hpp
classLoader.cpp allocation.inline.hpp
classLoader.cpp arguments.hpp
classLoader.cpp bytecodeStream.hpp
classLoader.cpp classFileParser.hpp
classLoader.cpp classFileStream.hpp
classLoader.cpp classLoader.hpp
@ -948,6 +949,7 @@ classLoader.cpp jvm_misc.hpp
classLoader.cpp management.hpp
classLoader.cpp oop.inline.hpp
classLoader.cpp oopFactory.hpp
classLoader.cpp oopMapCache.hpp
classLoader.cpp os_<os_family>.inline.hpp
classLoader.cpp symbolOop.hpp
classLoader.cpp systemDictionary.hpp
@ -1030,6 +1032,7 @@ codeCache.cpp objArrayOop.hpp
codeCache.cpp oop.inline.hpp
codeCache.cpp pcDesc.hpp
codeCache.cpp resourceArea.hpp
codeCache.cpp xmlstream.hpp
codeCache.hpp allocation.hpp
codeCache.hpp codeBlob.hpp
@ -1118,6 +1121,7 @@ compileBroker.cpp nativeLookup.hpp
compileBroker.cpp oop.inline.hpp
compileBroker.cpp os.hpp
compileBroker.cpp sharedRuntime.hpp
compileBroker.cpp sweeper.hpp
compileBroker.cpp systemDictionary.hpp
compileBroker.cpp vmSymbols.hpp
@ -2530,6 +2534,7 @@ jvmtiExport.hpp growableArray.hpp
jvmtiExport.hpp handles.hpp
jvmtiExport.hpp iterator.hpp
jvmtiExport.hpp jvmti.h
jvmtiExport.hpp jvmticmlr.h
jvmtiExport.hpp oop.hpp
jvmtiExport.hpp oopsHierarchy.hpp
@ -3716,6 +3721,7 @@ sharedHeap.hpp permGen.hpp
sharedRuntime.cpp abstractCompiler.hpp
sharedRuntime.cpp arguments.hpp
sharedRuntime.cpp biasedLocking.hpp
sharedRuntime.cpp compileBroker.hpp
sharedRuntime.cpp compiledIC.hpp
sharedRuntime.cpp compilerOracle.hpp
sharedRuntime.cpp copy.hpp
@ -3724,6 +3730,7 @@ sharedRuntime.cpp events.hpp
sharedRuntime.cpp forte.hpp
sharedRuntime.cpp gcLocker.inline.hpp
sharedRuntime.cpp handles.inline.hpp
sharedRuntime.cpp hashtable.inline.hpp
sharedRuntime.cpp init.hpp
sharedRuntime.cpp interfaceSupport.hpp
sharedRuntime.cpp interpreterRuntime.hpp
@ -3751,6 +3758,7 @@ sharedRuntime.cpp xmlstream.hpp
sharedRuntime.hpp allocation.hpp
sharedRuntime.hpp bytecodeHistogram.hpp
sharedRuntime.hpp bytecodeTracer.hpp
sharedRuntime.hpp hashtable.hpp
sharedRuntime.hpp linkResolver.hpp
sharedRuntime.hpp resourceArea.hpp
sharedRuntime.hpp threadLocalStorage.hpp
@ -3968,6 +3976,7 @@ stubs.hpp os_<os_family>.inline.hpp
sweeper.cpp atomic.hpp
sweeper.cpp codeCache.hpp
sweeper.cpp compileBroker.hpp
sweeper.cpp events.hpp
sweeper.cpp methodOop.hpp
sweeper.cpp mutexLocker.hpp
@ -3975,6 +3984,8 @@ sweeper.cpp nmethod.hpp
sweeper.cpp os.hpp
sweeper.cpp resourceArea.hpp
sweeper.cpp sweeper.hpp
sweeper.cpp vm_operations.hpp
sweeper.cpp xmlstream.hpp
symbolKlass.cpp gcLocker.hpp
symbolKlass.cpp handles.inline.hpp
@ -4628,6 +4639,7 @@ vm_operations.cpp deoptimization.hpp
vm_operations.cpp interfaceSupport.hpp
vm_operations.cpp isGCActiveMark.hpp
vm_operations.cpp resourceArea.hpp
vm_operations.cpp sweeper.hpp
vm_operations.cpp threadService.hpp
vm_operations.cpp thread_<os_family>.inline.hpp
vm_operations.cpp vmSymbols.hpp

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -397,7 +397,7 @@ IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea
// notify JVMTI of an exception throw; JVMTI will detect if this is a first
// time throw or a stack unwinding throw and accordingly notify the debugger
if (JvmtiExport::can_post_exceptions()) {
if (JvmtiExport::can_post_on_exceptions()) {
JvmtiExport::post_exception_throw(thread, h_method(), bcp(thread), h_exception());
}
@ -426,7 +426,7 @@ IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThrea
}
// notify debugger of an exception catch
// (this is good for exceptions caught in native methods as well)
if (JvmtiExport::can_post_exceptions()) {
if (JvmtiExport::can_post_on_exceptions()) {
JvmtiExport::notice_unwind_due_to_exception(thread, h_method(), handler_pc, h_exception(), (handler_pc != NULL));
}

View File

@ -296,23 +296,32 @@ public:
// RememberKlassesChecker can be passed "false" to turn off checking.
// It is used by CMS when CMS yields to a different collector.
class RememberKlassesChecker: StackObj {
bool _state;
bool _skip;
bool _saved_state;
bool _do_check;
public:
RememberKlassesChecker(bool checking_on) : _state(false), _skip(false) {
_skip = !(ClassUnloading && !UseConcMarkSweepGC ||
CMSClassUnloadingEnabled && UseConcMarkSweepGC);
if (_skip) {
return;
RememberKlassesChecker(bool checking_on) : _saved_state(false),
_do_check(true) {
// The ClassUnloading unloading flag affects the collectors except
// for CMS.
// CMS unloads classes if CMSClassUnloadingEnabled is true or
// if ExplicitGCInvokesConcurrentAndUnloadsClasses is true and
// the current collection is an explicit collection. Turning
// on the checking in general for
// ExplicitGCInvokesConcurrentAndUnloadsClasses and
// UseConcMarkSweepGC should not lead to false positives.
_do_check =
ClassUnloading && !UseConcMarkSweepGC ||
CMSClassUnloadingEnabled && UseConcMarkSweepGC ||
ExplicitGCInvokesConcurrentAndUnloadsClasses && UseConcMarkSweepGC;
if (_do_check) {
_saved_state = OopClosure::must_remember_klasses();
OopClosure::set_must_remember_klasses(checking_on);
}
_state = OopClosure::must_remember_klasses();
OopClosure::set_must_remember_klasses(checking_on);
}
~RememberKlassesChecker() {
if (_skip) {
return;
if (_do_check) {
OopClosure::set_must_remember_klasses(_saved_state);
}
OopClosure::set_must_remember_klasses(_state);
}
};
#endif // ASSERT

View File

@ -1227,13 +1227,16 @@ void ReferenceProcessor::preclean_discovered_references(
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
YieldClosure* yield) {
YieldClosure* yield,
bool should_unload_classes) {
NOT_PRODUCT(verify_ok_to_handle_reflists());
#ifdef ASSERT
bool must_remember_klasses = ClassUnloading && !UseConcMarkSweepGC ||
CMSClassUnloadingEnabled && UseConcMarkSweepGC;
CMSClassUnloadingEnabled && UseConcMarkSweepGC ||
ExplicitGCInvokesConcurrentAndUnloadsClasses &&
UseConcMarkSweepGC && should_unload_classes;
RememberKlassesChecker mx(must_remember_klasses);
#endif
// Soft references

View File

@ -170,11 +170,13 @@ class ReferenceProcessor : public CHeapObj {
// The caller is responsible for taking care of potential
// interference with concurrent operations on these lists
// (or predicates involved) by other threads. Currently
// only used by the CMS collector.
// only used by the CMS collector. should_unload_classes is
// used to aid assertion checking when classes are collected.
void preclean_discovered_references(BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
YieldClosure* yield);
YieldClosure* yield,
bool should_unload_classes);
// Delete entries in the discovered lists that have
// either a null referent or are not active. Such

View File

@ -1391,6 +1391,9 @@ public:
}
void inc_decompile_count() {
_nof_decompiles += 1;
if (decompile_count() > (uint)PerMethodRecompilationCutoff) {
method()->set_not_compilable();
}
}
// Support for code generation

View File

@ -575,12 +575,6 @@ bool methodOopDesc::is_not_compilable(int comp_level) const {
return true;
}
methodDataOop mdo = method_data();
if (mdo != NULL
&& (uint)mdo->decompile_count() > (uint)PerMethodRecompilationCutoff) {
// Since (uint)-1 is large, -1 really means 'no cutoff'.
return true;
}
#ifdef COMPILER2
if (is_tier1_compile(comp_level)) {
if (is_not_tier1_compilable()) {
@ -593,7 +587,16 @@ bool methodOopDesc::is_not_compilable(int comp_level) const {
}
// call this when compiler finds that this method is not compilable
void methodOopDesc::set_not_compilable(int comp_level) {
void methodOopDesc::set_not_compilable(int comp_level, bool report) {
if (PrintCompilation && report) {
ttyLocker ttyl;
tty->print("made not compilable ");
this->print_short_name(tty);
int size = this->code_size();
if (size > 0)
tty->print(" (%d bytes)", size);
tty->cr();
}
if ((TraceDeoptimization || LogCompilation) && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("make_not_compilable thread='%d'", (int) os::current_thread_id());
@ -688,7 +691,7 @@ address methodOopDesc::make_adapters(methodHandle mh, TRAPS) {
// so making them eagerly shouldn't be too expensive.
AdapterHandlerEntry* adapter = AdapterHandlerLibrary::get_adapter(mh);
if (adapter == NULL ) {
THROW_0(vmSymbols::java_lang_OutOfMemoryError());
THROW_MSG_NULL(vmSymbols::java_lang_VirtualMachineError(), "out of space in CodeCache for adapters");
}
mh->set_adapter_entry(adapter);
@ -705,6 +708,16 @@ address methodOopDesc::make_adapters(methodHandle mh, TRAPS) {
// This function must not hit a safepoint!
address methodOopDesc::verified_code_entry() {
debug_only(No_Safepoint_Verifier nsv;)
nmethod *code = (nmethod *)OrderAccess::load_ptr_acquire(&_code);
if (code == NULL && UseCodeCacheFlushing) {
nmethod *saved_code = CodeCache::find_and_remove_saved_code(this);
if (saved_code != NULL) {
methodHandle method(this);
assert( ! saved_code->is_osr_method(), "should not get here for osr" );
set_code( method, saved_code );
}
}
assert(_from_compiled_entry != NULL, "must be set");
return _from_compiled_entry;
}
@ -733,8 +746,8 @@ void methodOopDesc::set_code(methodHandle mh, nmethod *code) {
int comp_level = code->comp_level();
// In theory there could be a race here. In practice it is unlikely
// and not worth worrying about.
if (comp_level > highest_tier_compile()) {
set_highest_tier_compile(comp_level);
if (comp_level > mh->highest_tier_compile()) {
mh->set_highest_tier_compile(comp_level);
}
OrderAccess::storestore();

View File

@ -303,7 +303,7 @@ class methodOopDesc : public oopDesc {
bool check_code() const; // Not inline to avoid circular ref
nmethod* volatile code() const { assert( check_code(), "" ); return (nmethod *)OrderAccess::load_ptr_acquire(&_code); }
void clear_code(); // Clear out any compiled code
void set_code(methodHandle mh, nmethod* code);
static void set_code(methodHandle mh, nmethod* code);
void set_adapter_entry(AdapterHandlerEntry* adapter) { _adapter = adapter; }
address get_i2c_entry();
address get_c2i_entry();
@ -596,7 +596,10 @@ class methodOopDesc : public oopDesc {
// whether it is not compilable for another reason like having a
// breakpoint set in it.
bool is_not_compilable(int comp_level = CompLevel_highest_tier) const;
void set_not_compilable(int comp_level = CompLevel_highest_tier);
void set_not_compilable(int comp_level = CompLevel_highest_tier, bool report = true);
void set_not_compilable_quietly(int comp_level = CompLevel_highest_tier) {
set_not_compilable(comp_level, false);
}
bool is_not_osr_compilable() const { return is_not_compilable() || access_flags().is_not_osr_compilable(); }
void set_not_osr_compilable() { _access_flags.set_not_osr_compilable(); }

View File

@ -182,26 +182,16 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
}
}
CallGenerator* miss_cg;
Deoptimization::DeoptReason reason = (profile.morphism() == 2) ?
Deoptimization::Reason_bimorphic :
Deoptimization::Reason_class_check;
if (( profile.morphism() == 1 ||
(profile.morphism() == 2 && next_hit_cg != NULL) ) &&
!too_many_traps(Deoptimization::Reason_class_check)
// Check only total number of traps per method to allow
// the transition from monomorphic to bimorphic case between
// compilations without falling into virtual call.
// A monomorphic case may have the class_check trap flag is set
// due to the time gap between the uncommon trap processing
// when flags are set in MDO and the call site bytecode execution
// in Interpreter when MDO counters are updated.
// There was also class_check trap in monomorphic case due to
// the bug 6225440.
!too_many_traps(jvms->method(), jvms->bci(), reason)
) {
// Generate uncommon trap for class check failure path
// in case of monomorphic or bimorphic virtual call site.
miss_cg = CallGenerator::for_uncommon_trap(call_method,
Deoptimization::Reason_class_check,
miss_cg = CallGenerator::for_uncommon_trap(call_method, reason,
Deoptimization::Action_maybe_recompile);
} else {
// Generate virtual call for class check failure path

View File

@ -1,5 +1,5 @@
/*
* Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2001-2010 Sun Microsystems, Inc. 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
@ -455,16 +455,44 @@ Bytecodes::Code GraphKit::java_bc() const {
return Bytecodes::_illegal;
}
void GraphKit::uncommon_trap_if_should_post_on_exceptions(Deoptimization::DeoptReason reason,
bool must_throw) {
// if the exception capability is set, then we will generate code
// to check the JavaThread.should_post_on_exceptions flag to see
// if we actually need to report exception events (for this
// thread). If we don't need to report exception events, we will
// take the normal fast path provided by add_exception_events. If
// exception event reporting is enabled for this thread, we will
// take the uncommon_trap in the BuildCutout below.
// first must access the should_post_on_exceptions_flag in this thread's JavaThread
Node* jthread = _gvn.transform(new (C, 1) ThreadLocalNode());
Node* adr = basic_plus_adr(top(), jthread, in_bytes(JavaThread::should_post_on_exceptions_flag_offset()));
Node* should_post_flag = make_load(control(), adr, TypeInt::INT, T_INT, Compile::AliasIdxRaw, false);
// Test the should_post_on_exceptions_flag vs. 0
Node* chk = _gvn.transform( new (C, 3) CmpINode(should_post_flag, intcon(0)) );
Node* tst = _gvn.transform( new (C, 2) BoolNode(chk, BoolTest::eq) );
// Branch to slow_path if should_post_on_exceptions_flag was true
{ BuildCutout unless(this, tst, PROB_MAX);
// Do not try anything fancy if we're notifying the VM on every throw.
// Cf. case Bytecodes::_athrow in parse2.cpp.
uncommon_trap(reason, Deoptimization::Action_none,
(ciKlass*)NULL, (char*)NULL, must_throw);
}
}
//------------------------------builtin_throw----------------------------------
void GraphKit::builtin_throw(Deoptimization::DeoptReason reason, Node* arg) {
bool must_throw = true;
if (env()->jvmti_can_post_exceptions()) {
// Do not try anything fancy if we're notifying the VM on every throw.
// Cf. case Bytecodes::_athrow in parse2.cpp.
uncommon_trap(reason, Deoptimization::Action_none,
(ciKlass*)NULL, (char*)NULL, must_throw);
return;
if (env()->jvmti_can_post_on_exceptions()) {
// check if we must post exception events, take uncommon trap if so
uncommon_trap_if_should_post_on_exceptions(reason, must_throw);
// here if should_post_on_exceptions is false
// continue on with the normal codegen
}
// If this particular condition has not yet happened at this

View File

@ -1,5 +1,5 @@
/*
* Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2001-2010 Sun Microsystems, Inc. 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
@ -251,6 +251,11 @@ class GraphKit : public Phase {
// via an uncommon trap.
void builtin_throw(Deoptimization::DeoptReason reason, Node* arg = NULL);
// Helper to check the JavaThread::_should_post_on_exceptions flag
// and branch to an uncommon_trap if it is true (with the specified reason and must_throw)
void uncommon_trap_if_should_post_on_exceptions(Deoptimization::DeoptReason reason,
bool must_throw) ;
// Helper Functions for adding debug information
void kill_dead_locals();
#ifdef ASSERT

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2010 Sun Microsystems, Inc. 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

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -232,7 +232,7 @@ public:
// Expand method for MachNode, replaces nodes representing pseudo
// instructions with a set of nodes which represent real machine
// instructions and compute the same value.
virtual MachNode *Expand( State *, Node_List &proj_list ) { return this; }
virtual MachNode *Expand( State *, Node_List &proj_list, Node* mem ) { return this; }
// Bottom_type call; value comes from operand0
virtual const class Type *bottom_type() const { return _opnds[0]->type(); }

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -1580,7 +1580,7 @@ MachNode *Matcher::ReduceInst( State *s, int rule, Node *&mem ) {
uint num_proj = _proj_list.size();
// Perform any 1-to-many expansions required
MachNode *ex = mach->Expand(s,_proj_list);
MachNode *ex = mach->Expand(s,_proj_list, mem);
if( ex != mach ) {
assert(ex->ideal_reg() == mach->ideal_reg(), "ideal types should match");
if( ex->in(1)->is_Con() )

View File

@ -583,9 +583,22 @@ public:
// Preceeding equivalent StoreCMs may be eliminated.
class StoreCMNode : public StoreNode {
private:
virtual uint hash() const { return StoreNode::hash() + _oop_alias_idx; }
virtual uint cmp( const Node &n ) const {
return _oop_alias_idx == ((StoreCMNode&)n)._oop_alias_idx
&& StoreNode::cmp(n);
}
virtual uint size_of() const { return sizeof(*this); }
int _oop_alias_idx; // The alias_idx of OopStore
public:
StoreCMNode( Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, Node *oop_store, int oop_alias_idx ) : StoreNode(c,mem,adr,at,val,oop_store), _oop_alias_idx(oop_alias_idx) {}
StoreCMNode( Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, Node *oop_store, int oop_alias_idx ) :
StoreNode(c,mem,adr,at,val,oop_store),
_oop_alias_idx(oop_alias_idx) {
assert(_oop_alias_idx >= Compile::AliasIdxRaw ||
_oop_alias_idx == Compile::AliasIdxBot && Compile::current()->AliasLevel() == 0,
"bad oop alias idx");
}
virtual int Opcode() const;
virtual Node *Identity( PhaseTransform *phase );
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2010 Sun Microsystems, Inc. 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
@ -1093,7 +1093,7 @@ void Compile::Fill_buffer() {
cb->initialize(total_req, locs_req);
// Have we run out of code space?
if (cb->blob() == NULL) {
if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) {
turn_off_compiler(this);
return;
}
@ -1314,7 +1314,7 @@ void Compile::Fill_buffer() {
// Verify that there is sufficient space remaining
cb->insts()->maybe_expand_to_ensure_remaining(MAX_inst_size);
if (cb->blob() == NULL) {
if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) {
turn_off_compiler(this);
return;
}
@ -1430,10 +1430,14 @@ void Compile::Fill_buffer() {
_code_offsets.set_value(CodeOffsets::Exceptions, emit_exception_handler(*cb));
// Emit the deopt handler code.
_code_offsets.set_value(CodeOffsets::Deopt, emit_deopt_handler(*cb));
// Emit the MethodHandle deopt handler code. We can use the same
// code as for the normal deopt handler, we just need a different
// entry point address.
_code_offsets.set_value(CodeOffsets::DeoptMH, emit_deopt_handler(*cb));
}
// One last check for failed CodeBuffer::expand:
if (cb->blob() == NULL) {
if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) {
turn_off_compiler(this);
return;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2010 Sun Microsystems, Inc. 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
@ -2079,13 +2079,6 @@ void Parse::do_one_bytecode() {
// null exception oop throws NULL pointer exception
do_null_check(peek(), T_OBJECT);
if (stopped()) return;
if (env()->jvmti_can_post_exceptions()) {
// "Full-speed throwing" is not necessary here,
// since we're notifying the VM on every throw.
uncommon_trap(Deoptimization::Reason_unhandled,
Deoptimization::Action_none);
return;
}
// Hook the thrown exception directly to subsequent handlers.
if (BailoutToInterpreterForThrows) {
// Keep method interpreted from now on.
@ -2093,6 +2086,11 @@ void Parse::do_one_bytecode() {
Deoptimization::Action_make_not_compilable);
return;
}
if (env()->jvmti_can_post_on_exceptions()) {
// check if we must post exception events, take uncommon trap if so (with must_throw = false)
uncommon_trap_if_should_post_on_exceptions(Deoptimization::Reason_unhandled, false);
}
// Here if either can_post_on_exceptions or should_post_on_exceptions is false
add_exception_state(make_exception_state(peek()));
break;

View File

@ -414,8 +414,6 @@ void Parse::profile_not_taken_branch(bool force_update) {
void Parse::profile_call(Node* receiver) {
if (!method_data_update()) return;
profile_generic_call();
switch (bc()) {
case Bytecodes::_invokevirtual:
case Bytecodes::_invokeinterface:
@ -424,6 +422,7 @@ void Parse::profile_call(Node* receiver) {
case Bytecodes::_invokestatic:
case Bytecodes::_invokedynamic:
case Bytecodes::_invokespecial:
profile_generic_call();
break;
default: fatal("unexpected call bytecode");
}
@ -444,13 +443,16 @@ void Parse::profile_generic_call() {
void Parse::profile_receiver_type(Node* receiver) {
assert(method_data_update(), "must be generating profile code");
// Skip if we aren't tracking receivers
if (TypeProfileWidth < 1) return;
ciMethodData* md = method()->method_data();
assert(md != NULL, "expected valid ciMethodData");
ciProfileData* data = md->bci_to_data(bci());
assert(data->is_ReceiverTypeData(), "need ReceiverTypeData here");
// Skip if we aren't tracking receivers
if (TypeProfileWidth < 1) {
increment_md_counter_at(md, data, CounterData::count_offset());
return;
}
ciReceiverTypeData* rdata = (ciReceiverTypeData*)data->as_ReceiverTypeData();
Node* method_data = method_data_addressing(md, rdata, in_ByteSize(0));

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2010 Sun Microsystems, Inc. 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
@ -706,6 +706,11 @@ JRT_LEAF(void, OptoRuntime::profile_receiver_type_C(DataLayout* data, oopDesc* r
// vc->set_receiver_count(empty_row, DataLayout::counter_increment);
int count_off = ReceiverTypeData::receiver_count_cell_index(empty_row);
*(mdp + count_off) = DataLayout::counter_increment;
} else {
// Receiver did not match any saved receiver and there is no empty row for it.
// Increment total counter to indicate polimorphic case.
intptr_t* count_p = (intptr_t*)(((byte*)(data)) + in_bytes(CounterData::count_offset()));
*count_p += DataLayout::counter_increment;
}
JRT_END
@ -810,7 +815,7 @@ JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* t
// we are switching to old paradigm: search for exception handler in caller_frame
// instead in exception handler of caller_frame.sender()
if (JvmtiExport::can_post_exceptions()) {
if (JvmtiExport::can_post_on_exceptions()) {
// "Full-speed catching" is not necessary here,
// since we're notifying the VM on every catch.
// Force deoptimization and the rest of the lookup
@ -975,8 +980,8 @@ void OptoRuntime::deoptimize_caller_frame(JavaThread *thread, bool doit) {
assert(stub_frame.is_runtime_frame() || exception_blob()->contains(stub_frame.pc()), "sanity check");
frame caller_frame = stub_frame.sender(&reg_map);
VM_DeoptimizeFrame deopt(thread, caller_frame.id());
VMThread::execute(&deopt);
// bypass VM_DeoptimizeFrame and deoptimize the frame directly
Deoptimization::deoptimize_frame(thread, caller_frame.id());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2010 Sun Microsystems, Inc. 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
@ -82,7 +82,7 @@ static const jlong EARLY_EVENT_BITS = CLASS_FILE_LOAD_HOOK_BIT |
THREAD_START_BIT | THREAD_END_BIT |
DYNAMIC_CODE_GENERATED_BIT;
static const jlong GLOBAL_EVENT_BITS = ~THREAD_FILTERED_EVENT_BITS;
static const jlong SHOULD_POST_ON_EXCEPTIONS_BITS = EXCEPTION_BITS | METHOD_EXIT_BIT | FRAME_POP_BIT;
///////////////////////////////////////////////////////////////
//
@ -511,7 +511,12 @@ JvmtiEventControllerPrivate::recompute_thread_enabled(JvmtiThreadState *state) {
leave_interp_only_mode(state);
}
}
// update the JavaThread cached value for thread-specific should_post_on_exceptions value
bool should_post_on_exceptions = (any_env_enabled & SHOULD_POST_ON_EXCEPTIONS_BITS) != 0;
state->set_should_post_on_exceptions(should_post_on_exceptions);
}
return any_env_enabled;
}
@ -615,6 +620,10 @@ JvmtiEventControllerPrivate::recompute_enabled() {
// set global truly enabled, that is, any thread in any environment
JvmtiEventController::_universal_global_event_enabled.set_bits(any_env_thread_enabled);
// set global should_post_on_exceptions
JvmtiExport::set_should_post_on_exceptions((any_env_thread_enabled & SHOULD_POST_ON_EXCEPTIONS_BITS) != 0);
}
EC_TRACE(("JVMTI [-] # recompute enabled - after %llx", any_env_thread_enabled));

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2010 Sun Microsystems, Inc. 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
@ -686,11 +686,11 @@ class JvmtiCompiledMethodLoadEventMark : public JvmtiMethodEventMark {
jvmtiAddrLocationMap *_map;
const void *_compile_info;
public:
JvmtiCompiledMethodLoadEventMark(JavaThread *thread, nmethod *nm)
JvmtiCompiledMethodLoadEventMark(JavaThread *thread, nmethod *nm, void* compile_info_ptr = NULL)
: JvmtiMethodEventMark(thread,methodHandle(thread, nm->method())) {
_code_data = nm->code_begin();
_code_size = nm->code_size();
_compile_info = NULL; /* no info for our VM. */
_compile_info = compile_info_ptr; // Set void pointer of compiledMethodLoad Event. Default value is NULL.
JvmtiCodeBlobEvents::build_jvmti_addr_location_map(nm, &_map, &_map_length);
}
~JvmtiCompiledMethodLoadEventMark() {
@ -877,7 +877,7 @@ void JvmtiExport::post_raw_breakpoint(JavaThread *thread, methodOop method, addr
bool JvmtiExport::_can_get_source_debug_extension = false;
bool JvmtiExport::_can_maintain_original_method_order = false;
bool JvmtiExport::_can_post_interpreter_events = false;
bool JvmtiExport::_can_post_exceptions = false;
bool JvmtiExport::_can_post_on_exceptions = false;
bool JvmtiExport::_can_post_breakpoint = false;
bool JvmtiExport::_can_post_field_access = false;
bool JvmtiExport::_can_post_field_modification = false;
@ -908,6 +908,7 @@ bool JvmtiExport::_should_post_garbage_collection_finish = fals
bool JvmtiExport::_should_post_object_free = false;
bool JvmtiExport::_should_post_resource_exhausted = false;
bool JvmtiExport::_should_post_vm_object_alloc = false;
bool JvmtiExport::_should_post_on_exceptions = false;
////////////////////////////////////////////////////////////////////////////////////////////////
@ -1752,6 +1753,46 @@ void JvmtiExport::post_native_method_bind(methodOop method, address* function_pt
}
}
// Returns a record containing inlining information for the given nmethod
jvmtiCompiledMethodLoadInlineRecord* create_inline_record(nmethod* nm) {
jint numstackframes = 0;
jvmtiCompiledMethodLoadInlineRecord* record = (jvmtiCompiledMethodLoadInlineRecord*)NEW_RESOURCE_OBJ(jvmtiCompiledMethodLoadInlineRecord);
record->header.kind = JVMTI_CMLR_INLINE_INFO;
record->header.next = NULL;
record->header.majorinfoversion = JVMTI_CMLR_MAJOR_VERSION_1;
record->header.minorinfoversion = JVMTI_CMLR_MINOR_VERSION_0;
record->numpcs = 0;
for(PcDesc* p = nm->scopes_pcs_begin(); p < nm->scopes_pcs_end(); p++) {
if(p->scope_decode_offset() == DebugInformationRecorder::serialized_null) continue;
record->numpcs++;
}
record->pcinfo = (PCStackInfo*)(NEW_RESOURCE_ARRAY(PCStackInfo, record->numpcs));
int scope = 0;
for(PcDesc* p = nm->scopes_pcs_begin(); p < nm->scopes_pcs_end(); p++) {
if(p->scope_decode_offset() == DebugInformationRecorder::serialized_null) continue;
void* pc_address = (void*)p->real_pc(nm);
assert(pc_address != NULL, "pc_address must be non-null");
record->pcinfo[scope].pc = pc_address;
numstackframes=0;
for(ScopeDesc* sd = nm->scope_desc_at(p->real_pc(nm));sd != NULL;sd = sd->sender()) {
numstackframes++;
}
assert(numstackframes != 0, "numstackframes must be nonzero.");
record->pcinfo[scope].methods = (jmethodID *)NEW_RESOURCE_ARRAY(jmethodID, numstackframes);
record->pcinfo[scope].bcis = (jint *)NEW_RESOURCE_ARRAY(jint, numstackframes);
record->pcinfo[scope].numstackframes = numstackframes;
int stackframe = 0;
for(ScopeDesc* sd = nm->scope_desc_at(p->real_pc(nm));sd != NULL;sd = sd->sender()) {
// sd->method() can be NULL for stubs but not for nmethods. To be completely robust, include an assert that we should never see a null sd->method()
assert(!sd->method().is_null(), "sd->method() cannot be null.");
record->pcinfo[scope].methods[stackframe] = sd->method()->jmethod_id();
record->pcinfo[scope].bcis[stackframe] = sd->bci();
stackframe++;
}
scope++;
}
return record;
}
void JvmtiExport::post_compiled_method_load(nmethod *nm) {
// If there are pending CompiledMethodUnload events then these are
@ -1780,7 +1821,11 @@ void JvmtiExport::post_compiled_method_load(nmethod *nm) {
(nm->method() == NULL) ? "NULL" : nm->method()->name()->as_C_string()));
ResourceMark rm(thread);
JvmtiCompiledMethodLoadEventMark jem(thread, nm);
// Add inlining information
jvmtiCompiledMethodLoadInlineRecord* inlinerecord = create_inline_record(nm);
// Pass inlining information through the void pointer
JvmtiCompiledMethodLoadEventMark jem(thread, nm, inlinerecord);
JvmtiJavaThreadEventTransition jet(thread);
jvmtiEventCompiledMethodLoad callback = env->callbacks()->CompiledMethodLoad;
if (callback != NULL) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2010 Sun Microsystems, Inc. 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
@ -66,7 +66,7 @@ class JvmtiExport : public AllStatic {
JVMTI_SUPPORT_FLAG(can_get_source_debug_extension)
JVMTI_SUPPORT_FLAG(can_maintain_original_method_order)
JVMTI_SUPPORT_FLAG(can_post_interpreter_events)
JVMTI_SUPPORT_FLAG(can_post_exceptions)
JVMTI_SUPPORT_FLAG(can_post_on_exceptions)
JVMTI_SUPPORT_FLAG(can_post_breakpoint)
JVMTI_SUPPORT_FLAG(can_post_field_access)
JVMTI_SUPPORT_FLAG(can_post_field_modification)
@ -93,6 +93,7 @@ class JvmtiExport : public AllStatic {
JVMTI_SUPPORT_FLAG(should_post_data_dump)
JVMTI_SUPPORT_FLAG(should_post_garbage_collection_start)
JVMTI_SUPPORT_FLAG(should_post_garbage_collection_finish)
JVMTI_SUPPORT_FLAG(should_post_on_exceptions)
// ------ the below maybe don't have to be (but are for now)
// fixed conditions here ------------

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2010 Sun Microsystems, Inc. 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
@ -357,7 +357,7 @@ void JvmtiManageCapabilities::update() {
avail.can_access_local_variables ||
avail.can_redefine_classes ||
avail.can_retransform_classes);
JvmtiExport::set_can_post_exceptions(
JvmtiExport::set_can_post_on_exceptions(
avail.can_generate_exception_events ||
avail.can_generate_frame_pop_events ||
avail.can_generate_method_exit_events);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2010 Sun Microsystems, Inc. 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
@ -381,6 +381,9 @@ class JvmtiThreadState : public CHeapObj {
static ByteSize earlyret_value_offset() { return byte_offset_of(JvmtiThreadState, _earlyret_value); }
void oops_do(OopClosure* f); // GC support
public:
void set_should_post_on_exceptions(bool val) { _thread->set_should_post_on_exceptions_flag(val ? JNI_TRUE : JNI_FALSE); }
};
class RedefineVerifyMark : public StackObj {

View File

@ -2815,6 +2815,15 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
DebugNonSafepoints = true;
}
#ifndef PRODUCT
if (CompileTheWorld) {
// Force NmethodSweeper to sweep whole CodeCache each time.
if (FLAG_IS_DEFAULT(NmethodSweepFraction)) {
NmethodSweepFraction = 1;
}
}
#endif
if (PrintCommandLineFlags) {
CommandLineFlags::printSetFlags();
}

View File

@ -66,7 +66,7 @@ bool CompilationPolicy::mustBeCompiled(methodHandle m) {
if (!canBeCompiled(m)) return false;
return !UseInterpreter || // must compile all methods
(UseCompiler && AlwaysCompileLoopMethods && m->has_loops()); // eagerly compile loop methods
(UseCompiler && AlwaysCompileLoopMethods && m->has_loops() && CompileBroker::should_compile_new_jobs()); // eagerly compile loop methods
}
// Returns true if m is allowed to be compiled
@ -137,7 +137,7 @@ void SimpleCompPolicy::method_invocation_event( methodHandle m, TRAPS) {
reset_counter_for_invocation_event(m);
const char* comment = "count";
if (!delayCompilationDuringStartup() && canBeCompiled(m) && UseCompiler) {
if (!delayCompilationDuringStartup() && canBeCompiled(m) && UseCompiler && CompileBroker::should_compile_new_jobs()) {
nmethod* nm = m->code();
if (nm == NULL ) {
const char* comment = "count";
@ -162,7 +162,7 @@ void SimpleCompPolicy::method_back_branch_event(methodHandle m, int branch_bci,
int hot_count = m->backedge_count();
const char* comment = "backedge_count";
if (!m->is_not_osr_compilable() && !delayCompilationDuringStartup() && canBeCompiled(m)) {
if (!m->is_not_osr_compilable() && !delayCompilationDuringStartup() && canBeCompiled(m) && CompileBroker::should_compile_new_jobs()) {
CompileBroker::compile_method(m, loop_top_bci, m, hot_count, comment, CHECK);
NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(loop_top_bci));)
@ -204,7 +204,7 @@ void StackWalkCompPolicy::method_invocation_event(methodHandle m, TRAPS) {
reset_counter_for_invocation_event(m);
const char* comment = "count";
if (m->code() == NULL && !delayCompilationDuringStartup() && canBeCompiled(m) && UseCompiler) {
if (m->code() == NULL && !delayCompilationDuringStartup() && canBeCompiled(m) && UseCompiler && CompileBroker::should_compile_new_jobs()) {
ResourceMark rm(THREAD);
JavaThread *thread = (JavaThread*)THREAD;
frame fr = thread->last_frame();
@ -248,7 +248,7 @@ void StackWalkCompPolicy::method_back_branch_event(methodHandle m, int branch_bc
int hot_count = m->backedge_count();
const char* comment = "backedge_count";
if (!m->is_not_osr_compilable() && !delayCompilationDuringStartup() && canBeCompiled(m)) {
if (!m->is_not_osr_compilable() && !delayCompilationDuringStartup() && canBeCompiled(m) && CompileBroker::should_compile_new_jobs()) {
CompileBroker::compile_method(m, loop_top_bci, m, hot_count, comment, CHECK);
NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(loop_top_bci));)

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -235,6 +235,12 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
assert(cb->frame_size() >= 0, "Unexpected frame size");
intptr_t* unpack_sp = stub_frame.sp() + cb->frame_size();
// If the deopt call site is a MethodHandle invoke call site we have
// to adjust the unpack_sp.
nmethod* deoptee_nm = deoptee.cb()->as_nmethod_or_null();
if (deoptee_nm != NULL && deoptee_nm->is_method_handle_return(deoptee.pc()))
unpack_sp = deoptee.unextended_sp();
#ifdef ASSERT
assert(cb->is_deoptimization_stub() || cb->is_uncommon_trap_stub(), "just checking");
Events::log("fetch unroll sp " INTPTR_FORMAT, unpack_sp);
@ -1332,13 +1338,14 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
// Whether the interpreter is producing MDO data or not, we also need
// to use the MDO to detect hot deoptimization points and control
// aggressive optimization.
bool inc_recompile_count = false;
ProfileData* pdata = NULL;
if (ProfileTraps && update_trap_state && trap_mdo.not_null()) {
assert(trap_mdo() == get_method_data(thread, trap_method, false), "sanity");
uint this_trap_count = 0;
bool maybe_prior_trap = false;
bool maybe_prior_recompile = false;
ProfileData* pdata
= query_update_method_data(trap_mdo, trap_bci, reason,
pdata = query_update_method_data(trap_mdo, trap_bci, reason,
//outputs:
this_trap_count,
maybe_prior_trap,
@ -1374,18 +1381,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
// Detect repeated recompilation at the same BCI, and enforce a limit.
if (make_not_entrant && maybe_prior_recompile) {
// More than one recompile at this point.
trap_mdo->inc_overflow_recompile_count();
if (maybe_prior_trap
&& ((uint)trap_mdo->overflow_recompile_count()
> (uint)PerBytecodeRecompilationCutoff)) {
// Give up on the method containing the bad BCI.
if (trap_method() == nm->method()) {
make_not_compilable = true;
} else {
trap_method->set_not_compilable();
// But give grace to the enclosing nm->method().
}
}
inc_recompile_count = maybe_prior_trap;
}
} else {
// For reasons which are not recorded per-bytecode, we simply
@ -1412,7 +1408,17 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
reset_counters = true;
}
if (make_not_entrant && pdata != NULL) {
}
// Take requested actions on the method:
// Recompile
if (make_not_entrant) {
if (!nm->make_not_entrant()) {
return; // the call did not change nmethod's state
}
if (pdata != NULL) {
// Record the recompilation event, if any.
int tstate0 = pdata->trap_state();
int tstate1 = trap_state_set_recompiled(tstate0, true);
@ -1421,7 +1427,19 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
}
}
// Take requested actions on the method:
if (inc_recompile_count) {
trap_mdo->inc_overflow_recompile_count();
if ((uint)trap_mdo->overflow_recompile_count() >
(uint)PerBytecodeRecompilationCutoff) {
// Give up on the method containing the bad BCI.
if (trap_method() == nm->method()) {
make_not_compilable = true;
} else {
trap_method->set_not_compilable();
// But give grace to the enclosing nm->method().
}
}
}
// Reset invocation counters
if (reset_counters) {
@ -1431,13 +1449,8 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
reset_invocation_counter(trap_scope);
}
// Recompile
if (make_not_entrant) {
nm->make_not_entrant();
}
// Give up compiling
if (make_not_compilable) {
if (make_not_compilable && !nm->method()->is_not_compilable()) {
assert(make_not_entrant, "consistent");
nm->method()->set_not_compilable();
}
@ -1510,9 +1523,11 @@ Deoptimization::query_update_method_data(methodDataHandle trap_mdo,
if (tstate1 != tstate0)
pdata->set_trap_state(tstate1);
} else {
if (LogCompilation && xtty != NULL)
if (LogCompilation && xtty != NULL) {
ttyLocker ttyl;
// Missing MDP? Leave a small complaint in the log.
xtty->elem("missing_mdp bci='%d'", trap_bci);
}
}
}
@ -1666,6 +1681,7 @@ const char* Deoptimization::_trap_reason_name[Reason_LIMIT] = {
"class_check",
"array_check",
"intrinsic",
"bimorphic",
"unloaded",
"uninitialized",
"unreached",

View File

@ -33,12 +33,15 @@ class Deoptimization : AllStatic {
enum DeoptReason {
Reason_many = -1, // indicates presence of several reasons
Reason_none = 0, // indicates absence of a relevant deopt.
// Next 7 reasons are recorded per bytecode in DataLayout::trap_bits
Reason_null_check, // saw unexpected null or zero divisor (@bci)
Reason_null_assert, // saw unexpected non-null or non-zero (@bci)
Reason_range_check, // saw unexpected array index (@bci)
Reason_class_check, // saw unexpected object class (@bci)
Reason_array_check, // saw unexpected array class (aastore @bci)
Reason_intrinsic, // saw unexpected operand to intrinsic (@bci)
Reason_bimorphic, // saw unexpected object class in bimorphic inlining (@bci)
Reason_unloaded, // unloaded class or constant pool entry
Reason_uninitialized, // bad class state (uninitialized)
Reason_unreached, // code is not reached, compiler
@ -49,7 +52,7 @@ class Deoptimization : AllStatic {
Reason_predicate, // compiler generated predicate failed
Reason_LIMIT,
// Note: Keep this enum in sync. with _trap_reason_name.
Reason_RECORDED_LIMIT = Reason_unloaded // some are not recorded per bc
Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc
// Note: Reason_RECORDED_LIMIT should be < 8 to fit into 3 bits of
// DataLayout::trap_bits. This dependency is enforced indirectly
// via asserts, to avoid excessive direct header-to-header dependencies.
@ -279,7 +282,7 @@ class Deoptimization : AllStatic {
int trap_state);
static bool reason_is_recorded_per_bytecode(DeoptReason reason) {
return reason > Reason_none && reason < Reason_RECORDED_LIMIT;
return reason > Reason_none && reason <= Reason_RECORDED_LIMIT;
}
static DeoptReason reason_recorded_per_bytecode_if_any(DeoptReason reason) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -107,7 +107,11 @@ void RegisterMap::print() const {
address frame::raw_pc() const {
if (is_deoptimized_frame()) {
return ((nmethod*) cb())->deopt_handler_begin() - pc_return_offset;
nmethod* nm = cb()->as_nmethod_or_null();
if (nm->is_method_handle_return(pc()))
return nm->deopt_mh_handler_begin() - pc_return_offset;
else
return nm->deopt_handler_begin() - pc_return_offset;
} else {
return (pc() - pc_return_offset);
}
@ -269,10 +273,16 @@ void frame::deoptimize(JavaThread* thread, bool thread_is_known_safe) {
} // NeedsDeoptSuspend
address deopt = nm->deopt_handler_begin();
// If the call site is a MethodHandle call site use the MH deopt
// handler.
address deopt = nm->is_method_handle_return(pc()) ?
nm->deopt_mh_handler_begin() :
nm->deopt_handler_begin();
// Save the original pc before we patch in the new one
nm->set_original_pc(this, pc());
patch_pc(thread, deopt);
#ifdef ASSERT
{
RegisterMap map(thread, false);

View File

@ -742,6 +742,9 @@ class CommandLineFlags {
diagnostic(bool, PrintAdapterHandlers, false, \
"Print code generated for i2c/c2i adapters") \
\
develop(bool, VerifyAdapterSharing, false, \
"Verify that the code for shared adapters is the equivalent") \
\
diagnostic(bool, PrintAssembly, false, \
"Print assembly code (using external disassembler.so)") \
\
@ -1201,7 +1204,7 @@ class CommandLineFlags {
product(bool, UseSerialGC, false, \
"Use the serial garbage collector") \
\
experimental(bool, UseG1GC, false, \
product(bool, UseG1GC, false, \
"Use the Garbage-First garbage collector") \
\
product(bool, UseParallelGC, false, \
@ -2447,6 +2450,9 @@ class CommandLineFlags {
notproduct(bool, CompileTheWorldIgnoreInitErrors, false, \
"Compile all methods although class initializer failed") \
\
notproduct(intx, CompileTheWorldSafepointInterval, 100, \
"Force a safepoint every n compiles so sweeper can keep up") \
\
develop(bool, TraceIterativeGVN, false, \
"Print progress during Iterative Global Value Numbering") \
\
@ -2861,7 +2867,7 @@ class CommandLineFlags {
product(intx, PerMethodRecompilationCutoff, 400, \
"After recompiling N times, stay in the interpreter (-1=>'Inf')") \
\
product(intx, PerBytecodeRecompilationCutoff, 100, \
product(intx, PerBytecodeRecompilationCutoff, 200, \
"Per-BCI limit on repeated recompilation (-1=>'Inf')") \
\
product(intx, PerMethodTrapLimit, 100, \
@ -3114,6 +3120,15 @@ class CommandLineFlags {
notproduct(bool, ExitOnFullCodeCache, false, \
"Exit the VM if we fill the code cache.") \
\
product(bool, UseCodeCacheFlushing, false, \
"Attempt to clean the code cache before shutting off compiler") \
\
product(intx, MinCodeCacheFlushingInterval, 30, \
"Min number of seconds between code cache cleaning sessions") \
\
product(uintx, CodeCacheFlushingMinimumFreeSpace, 1500*K, \
"When less than X space left, start code cache cleaning") \
\
/* interpreter debugging */ \
develop(intx, BinarySwitchThreshold, 5, \
"Minimal number of lookupswitch entries for rewriting to binary " \

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -364,7 +364,7 @@ oop SharedRuntime::retrieve_receiver( symbolHandle sig, frame caller ) {
void SharedRuntime::throw_and_post_jvmti_exception(JavaThread *thread, Handle h_exception) {
if (JvmtiExport::can_post_exceptions()) {
if (JvmtiExport::can_post_on_exceptions()) {
vframeStream vfst(thread, true);
methodHandle method = methodHandle(thread, vfst.method());
address bcp = method()->bcp_from(vfst.bci());
@ -1033,10 +1033,20 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method(JavaThread* thread))
address sender_pc = caller_frame.pc();
CodeBlob* sender_cb = caller_frame.cb();
nmethod* sender_nm = sender_cb->as_nmethod_or_null();
bool is_mh_invoke_via_adapter = false; // Direct c2c call or via adapter?
if (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc)) {
// If the callee_target is set, then we have come here via an i2c
// adapter.
methodOop callee = thread->callee_target();
if (callee != NULL) {
assert(callee->is_method(), "sanity");
is_mh_invoke_via_adapter = true;
}
}
if (caller_frame.is_interpreted_frame() ||
caller_frame.is_entry_frame() ||
(sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc))) {
caller_frame.is_entry_frame() ||
is_mh_invoke_via_adapter) {
methodOop callee = thread->callee_target();
guarantee(callee != NULL && callee->is_method(), "bad handshake");
thread->set_vm_result(callee);
@ -1351,7 +1361,7 @@ methodHandle SharedRuntime::reresolve_call_site(JavaThread *thread, TRAPS) {
// We are calling the interpreter via a c2i. Normally this would mean that
// we were called by a compiled method. However we could have lost a race
// where we went int -> i2c -> c2i and so the caller could in fact be
// interpreted. If the caller is compiled we attampt to patch the caller
// interpreted. If the caller is compiled we attempt to patch the caller
// so he no longer calls into the interpreter.
IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(methodOopDesc* method, address caller_pc))
methodOop moop(method);
@ -1367,10 +1377,19 @@ IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(methodOopDesc* method, addr
// we did we'd leap into space because the callsite needs to use
// "to interpreter" stub in order to load up the methodOop. Don't
// ask me how I know this...
//
CodeBlob* cb = CodeCache::find_blob(caller_pc);
if ( !cb->is_nmethod() || entry_point == moop->get_c2i_entry()) {
if (!cb->is_nmethod() || entry_point == moop->get_c2i_entry()) {
return;
}
// The check above makes sure this is a nmethod.
nmethod* nm = cb->as_nmethod_or_null();
assert(nm, "must be");
// Don't fixup MethodHandle call sites as c2i/i2c adapters are used
// to implement MethodHandle actions.
if (nm->is_method_handle_return(caller_pc)) {
return;
}
@ -1385,7 +1404,7 @@ IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(methodOopDesc* method, addr
if (moop->code() == NULL) return;
if (((nmethod*)cb)->is_in_use()) {
if (nm->is_in_use()) {
// Expect to find a native call there (unless it was no-inline cache vtable dispatch)
MutexLockerEx ml_patch(Patching_lock, Mutex::_no_safepoint_check_flag);
@ -1417,7 +1436,7 @@ IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(methodOopDesc* method, addr
if (callee == cb || callee->is_adapter_blob()) {
// static call or optimized virtual
if (TraceCallFixup) {
tty->print("fixup callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
tty->print("fixup callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
moop->print_short_name(tty);
tty->print_cr(" to " INTPTR_FORMAT, entry_point);
}
@ -1433,7 +1452,7 @@ IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(methodOopDesc* method, addr
}
} else {
if (TraceCallFixup) {
tty->print("already patched callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
tty->print("already patched callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
moop->print_short_name(tty);
tty->print_cr(" to " INTPTR_FORMAT, entry_point);
}
@ -1680,6 +1699,8 @@ void SharedRuntime::print_statistics() {
if( _find_handler_ctr ) tty->print_cr("%5d find exception handler", _find_handler_ctr );
if( _rethrow_ctr ) tty->print_cr("%5d rethrow handler", _rethrow_ctr );
AdapterHandlerLibrary::print_statistics();
if (xtty != NULL) xtty->tail("statistics");
}
@ -1780,11 +1801,282 @@ void SharedRuntime::print_call_statistics(int comp_total) {
#endif
// A simple wrapper class around the calling convention information
// that allows sharing of adapters for the same calling convention.
class AdapterFingerPrint : public CHeapObj {
private:
union {
int _compact[3];
int* _fingerprint;
} _value;
int _length; // A negative length indicates the fingerprint is in the compact form,
// Otherwise _value._fingerprint is the array.
// Remap BasicTypes that are handled equivalently by the adapters.
// These are correct for the current system but someday it might be
// necessary to make this mapping platform dependent.
static BasicType adapter_encoding(BasicType in) {
assert((~0xf & in) == 0, "must fit in 4 bits");
switch(in) {
case T_BOOLEAN:
case T_BYTE:
case T_SHORT:
case T_CHAR:
// There are all promoted to T_INT in the calling convention
return T_INT;
case T_OBJECT:
case T_ARRAY:
if (!TaggedStackInterpreter) {
#ifdef _LP64
return T_LONG;
#else
return T_INT;
#endif
}
return T_OBJECT;
case T_INT:
case T_LONG:
case T_FLOAT:
case T_DOUBLE:
case T_VOID:
return in;
default:
ShouldNotReachHere();
return T_CONFLICT;
}
}
public:
AdapterFingerPrint(int total_args_passed, BasicType* sig_bt) {
// The fingerprint is based on the BasicType signature encoded
// into an array of ints with four entries per int.
int* ptr;
int len = (total_args_passed + 3) >> 2;
if (len <= (int)(sizeof(_value._compact) / sizeof(int))) {
_value._compact[0] = _value._compact[1] = _value._compact[2] = 0;
// Storing the signature encoded as signed chars hits about 98%
// of the time.
_length = -len;
ptr = _value._compact;
} else {
_length = len;
_value._fingerprint = NEW_C_HEAP_ARRAY(int, _length);
ptr = _value._fingerprint;
}
// Now pack the BasicTypes with 4 per int
int sig_index = 0;
for (int index = 0; index < len; index++) {
int value = 0;
for (int byte = 0; byte < 4; byte++) {
if (sig_index < total_args_passed) {
value = (value << 4) | adapter_encoding(sig_bt[sig_index++]);
}
}
ptr[index] = value;
}
}
~AdapterFingerPrint() {
if (_length > 0) {
FREE_C_HEAP_ARRAY(int, _value._fingerprint);
}
}
int value(int index) {
if (_length < 0) {
return _value._compact[index];
}
return _value._fingerprint[index];
}
int length() {
if (_length < 0) return -_length;
return _length;
}
bool is_compact() {
return _length <= 0;
}
unsigned int compute_hash() {
int hash = 0;
for (int i = 0; i < length(); i++) {
int v = value(i);
hash = (hash << 8) ^ v ^ (hash >> 5);
}
return (unsigned int)hash;
}
const char* as_string() {
stringStream st;
for (int i = 0; i < length(); i++) {
st.print(PTR_FORMAT, value(i));
}
return st.as_string();
}
bool equals(AdapterFingerPrint* other) {
if (other->_length != _length) {
return false;
}
if (_length < 0) {
return _value._compact[0] == other->_value._compact[0] &&
_value._compact[1] == other->_value._compact[1] &&
_value._compact[2] == other->_value._compact[2];
} else {
for (int i = 0; i < _length; i++) {
if (_value._fingerprint[i] != other->_value._fingerprint[i]) {
return false;
}
}
}
return true;
}
};
// A hashtable mapping from AdapterFingerPrints to AdapterHandlerEntries
class AdapterHandlerTable : public BasicHashtable {
friend class AdapterHandlerTableIterator;
private:
#ifdef ASSERT
static int _lookups; // number of calls to lookup
static int _buckets; // number of buckets checked
static int _equals; // number of buckets checked with matching hash
static int _hits; // number of successful lookups
static int _compact; // number of equals calls with compact signature
#endif
AdapterHandlerEntry* bucket(int i) {
return (AdapterHandlerEntry*)BasicHashtable::bucket(i);
}
public:
AdapterHandlerTable()
: BasicHashtable(293, sizeof(AdapterHandlerEntry)) { }
// Create a new entry suitable for insertion in the table
AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry) {
AdapterHandlerEntry* entry = (AdapterHandlerEntry*)BasicHashtable::new_entry(fingerprint->compute_hash());
entry->init(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
return entry;
}
// Insert an entry into the table
void add(AdapterHandlerEntry* entry) {
int index = hash_to_index(entry->hash());
add_entry(index, entry);
}
void free_entry(AdapterHandlerEntry* entry) {
entry->deallocate();
BasicHashtable::free_entry(entry);
}
// Find a entry with the same fingerprint if it exists
AdapterHandlerEntry* lookup(int total_args_passed, BasicType* sig_bt) {
debug_only(_lookups++);
AdapterFingerPrint fp(total_args_passed, sig_bt);
unsigned int hash = fp.compute_hash();
int index = hash_to_index(hash);
for (AdapterHandlerEntry* e = bucket(index); e != NULL; e = e->next()) {
debug_only(_buckets++);
if (e->hash() == hash) {
debug_only(_equals++);
if (fp.equals(e->fingerprint())) {
#ifdef ASSERT
if (fp.is_compact()) _compact++;
_hits++;
#endif
return e;
}
}
}
return NULL;
}
void print_statistics() {
ResourceMark rm;
int longest = 0;
int empty = 0;
int total = 0;
int nonempty = 0;
for (int index = 0; index < table_size(); index++) {
int count = 0;
for (AdapterHandlerEntry* e = bucket(index); e != NULL; e = e->next()) {
count++;
}
if (count != 0) nonempty++;
if (count == 0) empty++;
if (count > longest) longest = count;
total += count;
}
tty->print_cr("AdapterHandlerTable: empty %d longest %d total %d average %f",
empty, longest, total, total / (double)nonempty);
#ifdef ASSERT
tty->print_cr("AdapterHandlerTable: lookups %d buckets %d equals %d hits %d compact %d",
_lookups, _buckets, _equals, _hits, _compact);
#endif
}
};
#ifdef ASSERT
int AdapterHandlerTable::_lookups;
int AdapterHandlerTable::_buckets;
int AdapterHandlerTable::_equals;
int AdapterHandlerTable::_hits;
int AdapterHandlerTable::_compact;
class AdapterHandlerTableIterator : public StackObj {
private:
AdapterHandlerTable* _table;
int _index;
AdapterHandlerEntry* _current;
void scan() {
while (_index < _table->table_size()) {
AdapterHandlerEntry* a = _table->bucket(_index);
if (a != NULL) {
_current = a;
return;
}
_index++;
}
}
public:
AdapterHandlerTableIterator(AdapterHandlerTable* table): _table(table), _index(0), _current(NULL) {
scan();
}
bool has_next() {
return _current != NULL;
}
AdapterHandlerEntry* next() {
if (_current != NULL) {
AdapterHandlerEntry* result = _current;
_current = _current->next();
if (_current == NULL) scan();
return result;
} else {
return NULL;
}
}
};
#endif
// ---------------------------------------------------------------------------
// Implementation of AdapterHandlerLibrary
const char* AdapterHandlerEntry::name = "I2C/C2I adapters";
GrowableArray<uint64_t>* AdapterHandlerLibrary::_fingerprints = NULL;
GrowableArray<AdapterHandlerEntry* >* AdapterHandlerLibrary::_handlers = NULL;
AdapterHandlerTable* AdapterHandlerLibrary::_adapters = NULL;
AdapterHandlerEntry* AdapterHandlerLibrary::_abstract_method_handler = NULL;
const int AdapterHandlerLibrary_size = 16*K;
BufferBlob* AdapterHandlerLibrary::_buffer = NULL;
@ -1796,28 +2088,31 @@ BufferBlob* AdapterHandlerLibrary::buffer_blob() {
}
void AdapterHandlerLibrary::initialize() {
if (_fingerprints != NULL) return;
_fingerprints = new(ResourceObj::C_HEAP)GrowableArray<uint64_t>(32, true);
_handlers = new(ResourceObj::C_HEAP)GrowableArray<AdapterHandlerEntry*>(32, true);
// Index 0 reserved for the slow path handler
_fingerprints->append(0/*the never-allowed 0 fingerprint*/);
_handlers->append(NULL);
if (_adapters != NULL) return;
_adapters = new AdapterHandlerTable();
// Create a special handler for abstract methods. Abstract methods
// are never compiled so an i2c entry is somewhat meaningless, but
// fill it in with something appropriate just in case. Pass handle
// wrong method for the c2i transitions.
address wrong_method = SharedRuntime::get_handle_wrong_method_stub();
_fingerprints->append(0/*the never-allowed 0 fingerprint*/);
assert(_handlers->length() == AbstractMethodHandler, "in wrong slot");
_handlers->append(new AdapterHandlerEntry(StubRoutines::throw_AbstractMethodError_entry(),
wrong_method, wrong_method));
_abstract_method_handler = AdapterHandlerLibrary::new_entry(new AdapterFingerPrint(0, NULL),
StubRoutines::throw_AbstractMethodError_entry(),
wrong_method, wrong_method);
}
int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) {
// Use customized signature handler. Need to lock around updates to the
// _fingerprints array (it is not safe for concurrent readers and a single
// writer: this can be fixed if it becomes a problem).
AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* fingerprint,
address i2c_entry,
address c2i_entry,
address c2i_unverified_entry) {
return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
}
AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) {
// Use customized signature handler. Need to lock around updates to
// the AdapterHandlerTable (it is not safe for concurrent readers
// and a single writer: this could be fixed if it becomes a
// problem).
// Get the address of the ic_miss handlers before we grab the
// AdapterHandlerLibrary_lock. This fixes bug 6236259 which
@ -1828,47 +2123,58 @@ int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) {
address ic_miss = SharedRuntime::get_ic_miss_stub();
assert(ic_miss != NULL, "must have handler");
int result;
ResourceMark rm;
NOT_PRODUCT(int code_size);
BufferBlob *B = NULL;
AdapterHandlerEntry* entry = NULL;
uint64_t fingerprint;
AdapterFingerPrint* fingerprint = NULL;
{
MutexLocker mu(AdapterHandlerLibrary_lock);
// make sure data structure is initialized
initialize();
if (method->is_abstract()) {
return AbstractMethodHandler;
return _abstract_method_handler;
}
// Fill in the signature array, for the calling-convention call.
int total_args_passed = method->size_of_parameters(); // All args on stack
BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed);
VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed);
int i = 0;
if (!method->is_static()) // Pass in receiver first
sig_bt[i++] = T_OBJECT;
for (SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) {
sig_bt[i++] = ss.type(); // Collect remaining bits of signature
if (ss.type() == T_LONG || ss.type() == T_DOUBLE)
sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots
}
assert(i == total_args_passed, "");
// Lookup method signature's fingerprint
fingerprint = Fingerprinter(method).fingerprint();
assert( fingerprint != CONST64( 0), "no zero fingerprints allowed" );
// Fingerprints are small fixed-size condensed representations of
// signatures. If the signature is too large, it won't fit in a
// fingerprint. Signatures which cannot support a fingerprint get a new i2c
// adapter gen'd each time, instead of searching the cache for one. This -1
// game can be avoided if I compared signatures instead of using
// fingerprints. However, -1 fingerprints are very rare.
if( fingerprint != UCONST64(-1) ) { // If this is a cache-able fingerprint
// Turns out i2c adapters do not care what the return value is. Mask it
// out so signatures that only differ in return type will share the same
// adapter.
fingerprint &= ~(SignatureIterator::result_feature_mask << SignatureIterator::static_feature_size);
// Search for a prior existing i2c/c2i adapter
int index = _fingerprints->find(fingerprint);
if( index >= 0 ) return index; // Found existing handlers?
} else {
// Annoyingly, I end up adding -1 fingerprints to the array of handlers,
// because I need a unique handler index. It cannot be scanned for
// because all -1's look alike. Instead, the matching index is passed out
// and immediately used to collect the 2 return values (the c2i and i2c
// adapters).
entry = _adapters->lookup(total_args_passed, sig_bt);
#ifdef ASSERT
AdapterHandlerEntry* shared_entry = NULL;
if (VerifyAdapterSharing && entry != NULL) {
shared_entry = entry;
entry = NULL;
}
#endif
if (entry != NULL) {
return entry;
}
// Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage
int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false);
// Make a C heap allocated version of the fingerprint to store in the adapter
fingerprint = new AdapterFingerPrint(total_args_passed, sig_bt);
// Create I2C & C2I handlers
ResourceMark rm;
BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache
if (buf != NULL) {
@ -1878,32 +2184,26 @@ int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) {
sizeof(buffer_locs)/sizeof(relocInfo));
MacroAssembler _masm(&buffer);
// Fill in the signature array, for the calling-convention call.
int total_args_passed = method->size_of_parameters(); // All args on stack
BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType,total_args_passed);
VMRegPair * regs = NEW_RESOURCE_ARRAY(VMRegPair ,total_args_passed);
int i=0;
if( !method->is_static() ) // Pass in receiver first
sig_bt[i++] = T_OBJECT;
for( SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) {
sig_bt[i++] = ss.type(); // Collect remaining bits of signature
if( ss.type() == T_LONG || ss.type() == T_DOUBLE )
sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots
}
assert( i==total_args_passed, "" );
// Now get the re-packed compiled-Java layout.
int comp_args_on_stack;
// Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage
comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false);
entry = SharedRuntime::generate_i2c2i_adapters(&_masm,
total_args_passed,
comp_args_on_stack,
sig_bt,
regs);
regs,
fingerprint);
#ifdef ASSERT
if (VerifyAdapterSharing) {
if (shared_entry != NULL) {
assert(shared_entry->compare_code(buf->instructions_begin(), buffer.code_size(), total_args_passed, sig_bt),
"code must match");
// Release the one just created and return the original
_adapters->free_entry(entry);
return shared_entry;
} else {
entry->save_code(buf->instructions_begin(), buffer.code_size(), total_args_passed, sig_bt);
}
}
#endif
B = BufferBlob::create(AdapterHandlerEntry::name, &buffer);
NOT_PRODUCT(code_size = buffer.code_size());
@ -1912,49 +2212,33 @@ int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) {
// CodeCache is full, disable compilation
// Ought to log this but compile log is only per compile thread
// and we're some non descript Java thread.
UseInterpreter = true;
if (UseCompiler || AlwaysCompileLoopMethods ) {
#ifndef PRODUCT
warning("CodeCache is full. Compiler has been disabled");
if (CompileTheWorld || ExitOnFullCodeCache) {
before_exit(JavaThread::current());
exit_globals(); // will delete tty
vm_direct_exit(CompileTheWorld ? 0 : 1);
}
#endif
UseCompiler = false;
AlwaysCompileLoopMethods = false;
}
return 0; // Out of CodeCache space (_handlers[0] == NULL)
MutexUnlocker mu(AdapterHandlerLibrary_lock);
CompileBroker::handle_full_code_cache();
return NULL; // Out of CodeCache space
}
entry->relocate(B->instructions_begin());
#ifndef PRODUCT
// debugging suppport
if (PrintAdapterHandlers) {
tty->cr();
tty->print_cr("i2c argument handler #%d for: %s %s (fingerprint = 0x%llx, %d bytes generated)",
_handlers->length(), (method->is_static() ? "static" : "receiver"),
method->signature()->as_C_string(), fingerprint, code_size );
tty->print_cr("i2c argument handler #%d for: %s %s (fingerprint = %s, %d bytes generated)",
_adapters->number_of_entries(), (method->is_static() ? "static" : "receiver"),
method->signature()->as_C_string(), fingerprint->as_string(), code_size );
tty->print_cr("c2i argument handler starts at %p",entry->get_c2i_entry());
Disassembler::decode(entry->get_i2c_entry(), entry->get_i2c_entry() + code_size);
}
#endif
// add handlers to library
_fingerprints->append(fingerprint);
_handlers->append(entry);
// set handler index
assert(_fingerprints->length() == _handlers->length(), "sanity check");
result = _fingerprints->length() - 1;
_adapters->add(entry);
}
// Outside of the lock
if (B != NULL) {
char blob_id[256];
jio_snprintf(blob_id,
sizeof(blob_id),
"%s(" PTR64_FORMAT ")@" PTR_FORMAT,
"%s(%s)@" PTR_FORMAT,
AdapterHandlerEntry::name,
fingerprint,
fingerprint->as_string(),
B->instructions_begin());
VTune::register_stub(blob_id, B->instructions_begin(), B->instructions_end());
Forte::register_stub(blob_id, B->instructions_begin(), B->instructions_end());
@ -1965,7 +2249,7 @@ int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) {
B->instructions_end());
}
}
return result;
return entry;
}
void AdapterHandlerEntry::relocate(address new_base) {
@ -1975,6 +2259,44 @@ void AdapterHandlerEntry::relocate(address new_base) {
_c2i_unverified_entry += delta;
}
void AdapterHandlerEntry::deallocate() {
delete _fingerprint;
#ifdef ASSERT
if (_saved_code) FREE_C_HEAP_ARRAY(unsigned char, _saved_code);
if (_saved_sig) FREE_C_HEAP_ARRAY(Basictype, _saved_sig);
#endif
}
#ifdef ASSERT
// Capture the code before relocation so that it can be compared
// against other versions. If the code is captured after relocation
// then relative instructions won't be equivalent.
void AdapterHandlerEntry::save_code(unsigned char* buffer, int length, int total_args_passed, BasicType* sig_bt) {
_saved_code = NEW_C_HEAP_ARRAY(unsigned char, length);
_code_length = length;
memcpy(_saved_code, buffer, length);
_total_args_passed = total_args_passed;
_saved_sig = NEW_C_HEAP_ARRAY(BasicType, _total_args_passed);
memcpy(_saved_sig, sig_bt, _total_args_passed * sizeof(BasicType));
}
bool AdapterHandlerEntry::compare_code(unsigned char* buffer, int length, int total_args_passed, BasicType* sig_bt) {
if (length != _code_length) {
return false;
}
for (int i = 0; i < length; i++) {
if (buffer[i] != _saved_code[i]) {
return false;
}
}
return true;
}
#endif
// Create a native wrapper for this native method. The wrapper converts the
// java compiled calling convention to the native convention, handlizes
// arguments, and transitions to native. On return from the native we transition
@ -2053,19 +2375,8 @@ nmethod *AdapterHandlerLibrary::create_native_wrapper(methodHandle method) {
// CodeCache is full, disable compilation
// Ought to log this but compile log is only per compile thread
// and we're some non descript Java thread.
UseInterpreter = true;
if (UseCompiler || AlwaysCompileLoopMethods ) {
#ifndef PRODUCT
warning("CodeCache is full. Compiler has been disabled");
if (CompileTheWorld || ExitOnFullCodeCache) {
before_exit(JavaThread::current());
exit_globals(); // will delete tty
vm_direct_exit(CompileTheWorld ? 0 : 1);
}
#endif
UseCompiler = false;
AlwaysCompileLoopMethods = false;
}
MutexUnlocker mu(AdapterHandlerLibrary_lock);
CompileBroker::handle_full_code_cache();
}
return nm;
}
@ -2308,30 +2619,31 @@ JRT_END
#ifndef PRODUCT
bool AdapterHandlerLibrary::contains(CodeBlob* b) {
if (_handlers == NULL) return false;
for (int i = 0 ; i < _handlers->length() ; i++) {
AdapterHandlerEntry* a = get_entry(i);
if ( a != NULL && b == CodeCache::find_blob(a->get_i2c_entry()) ) return true;
AdapterHandlerTableIterator iter(_adapters);
while (iter.has_next()) {
AdapterHandlerEntry* a = iter.next();
if ( b == CodeCache::find_blob(a->get_i2c_entry()) ) return true;
}
return false;
}
void AdapterHandlerLibrary::print_handler(CodeBlob* b) {
for (int i = 0 ; i < _handlers->length() ; i++) {
AdapterHandlerEntry* a = get_entry(i);
if ( a != NULL && b == CodeCache::find_blob(a->get_i2c_entry()) ) {
AdapterHandlerTableIterator iter(_adapters);
while (iter.has_next()) {
AdapterHandlerEntry* a = iter.next();
if ( b == CodeCache::find_blob(a->get_i2c_entry()) ) {
tty->print("Adapter for signature: ");
// Fingerprinter::print(_fingerprints->at(i));
tty->print("0x%" FORMAT64_MODIFIER "x", _fingerprints->at(i));
tty->print_cr(" i2c: " INTPTR_FORMAT " c2i: " INTPTR_FORMAT " c2iUV: " INTPTR_FORMAT,
tty->print_cr("%s i2c: " INTPTR_FORMAT " c2i: " INTPTR_FORMAT " c2iUV: " INTPTR_FORMAT,
a->fingerprint()->as_string(),
a->get_i2c_entry(), a->get_c2i_entry(), a->get_c2i_unverified_entry());
return;
}
}
assert(false, "Should have found handler");
}
void AdapterHandlerLibrary::print_statistics() {
_adapters->print_statistics();
}
#endif /* PRODUCT */

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -23,6 +23,8 @@
*/
class AdapterHandlerEntry;
class AdapterHandlerTable;
class AdapterFingerPrint;
class vframeStream;
// Runtime is the base class for various runtime interfaces
@ -337,7 +339,8 @@ class SharedRuntime: AllStatic {
int total_args_passed,
int max_arg,
const BasicType *sig_bt,
const VMRegPair *regs);
const VMRegPair *regs,
AdapterFingerPrint* fingerprint);
// OSR support
@ -528,28 +531,64 @@ class SharedRuntime: AllStatic {
// used by the adapters. The code generation happens here because it's very
// similar to what the adapters have to do.
class AdapterHandlerEntry : public CHeapObj {
class AdapterHandlerEntry : public BasicHashtableEntry {
friend class AdapterHandlerTable;
private:
AdapterFingerPrint* _fingerprint;
address _i2c_entry;
address _c2i_entry;
address _c2i_unverified_entry;
public:
#ifdef ASSERT
// Captures code and signature used to generate this adapter when
// verifing adapter equivalence.
unsigned char* _saved_code;
int _code_length;
BasicType* _saved_sig;
int _total_args_passed;
#endif
void init(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry) {
_fingerprint = fingerprint;
_i2c_entry = i2c_entry;
_c2i_entry = c2i_entry;
_c2i_unverified_entry = c2i_unverified_entry;
#ifdef ASSERT
_saved_code = NULL;
_code_length = 0;
_saved_sig = NULL;
_total_args_passed = 0;
#endif
}
void deallocate();
// should never be used
AdapterHandlerEntry();
public:
// The name we give all buffer blobs
static const char* name;
AdapterHandlerEntry(address i2c_entry, address c2i_entry, address c2i_unverified_entry):
_i2c_entry(i2c_entry),
_c2i_entry(c2i_entry),
_c2i_unverified_entry(c2i_unverified_entry) {
}
address get_i2c_entry() { return _i2c_entry; }
address get_c2i_entry() { return _c2i_entry; }
address get_c2i_unverified_entry() { return _c2i_unverified_entry; }
void relocate(address new_base);
AdapterFingerPrint* fingerprint() { return _fingerprint; }
AdapterHandlerEntry* next() {
return (AdapterHandlerEntry*)BasicHashtableEntry::next();
}
#ifdef ASSERT
// Used to verify that code generated for shared adapters is equivalent
void save_code(unsigned char* code, int length, int total_args_passed, BasicType* sig_bt);
bool compare_code(unsigned char* code, int length, int total_args_passed, BasicType* sig_bt);
#endif
#ifndef PRODUCT
void print();
#endif /* PRODUCT */
@ -558,30 +597,18 @@ class AdapterHandlerEntry : public CHeapObj {
class AdapterHandlerLibrary: public AllStatic {
private:
static BufferBlob* _buffer; // the temporary code buffer in CodeCache
static GrowableArray<uint64_t>* _fingerprints; // the fingerprint collection
static GrowableArray<AdapterHandlerEntry*> * _handlers; // the corresponding handlers
enum {
AbstractMethodHandler = 1 // special handler for abstract methods
};
static AdapterHandlerTable* _adapters;
static AdapterHandlerEntry* _abstract_method_handler;
static BufferBlob* buffer_blob();
static void initialize();
static int get_create_adapter_index(methodHandle method);
static address get_i2c_entry( int index ) {
return get_entry(index)->get_i2c_entry();
}
static address get_c2i_entry( int index ) {
return get_entry(index)->get_c2i_entry();
}
static address get_c2i_unverified_entry( int index ) {
return get_entry(index)->get_c2i_unverified_entry();
}
public:
static AdapterHandlerEntry* get_entry( int index ) { return _handlers->at(index); }
static AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint,
address i2c_entry, address c2i_entry, address c2i_unverified_entry);
static nmethod* create_native_wrapper(methodHandle method);
static AdapterHandlerEntry* get_adapter(methodHandle method) {
return get_entry(get_create_adapter_index(method));
}
static AdapterHandlerEntry* get_adapter(methodHandle method);
#ifdef HAVE_DTRACE_H
static nmethod* create_dtrace_nmethod (methodHandle method);
#endif // HAVE_DTRACE_H
@ -589,6 +616,7 @@ class AdapterHandlerLibrary: public AllStatic {
#ifndef PRODUCT
static void print_handler(CodeBlob* b);
static bool contains(CodeBlob* b);
static void print_statistics();
#endif /* PRODUCT */
};

View File

@ -33,6 +33,11 @@ int NMethodSweeper::_invocations = 0; // No. of invocations left until we
jint NMethodSweeper::_locked_seen = 0;
jint NMethodSweeper::_not_entrant_seen_on_stack = 0;
bool NMethodSweeper::_rescan = false;
bool NMethodSweeper::_was_full = false;
jint NMethodSweeper::_advise_to_sweep = 0;
jlong NMethodSweeper::_last_was_full = 0;
uint NMethodSweeper::_highest_marked = 0;
long NMethodSweeper::_was_full_traversal = 0;
class MarkActivationClosure: public CodeBlobClosure {
public:
@ -114,6 +119,40 @@ void NMethodSweeper::sweep() {
tty->print_cr("### Couldn't make progress on some nmethods so stopping sweep");
}
}
if (UseCodeCacheFlushing) {
if (!CodeCache::needs_flushing()) {
// In a safepoint, no race with setters
_advise_to_sweep = 0;
}
if (was_full()) {
// There was some progress so attempt to restart the compiler
jlong now = os::javaTimeMillis();
jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000;
jlong curr_interval = now - _last_was_full;
if ((!CodeCache::needs_flushing()) && (curr_interval > max_interval)) {
CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation);
set_was_full(false);
// Update the _last_was_full time so we can tell how fast the
// code cache is filling up
_last_was_full = os::javaTimeMillis();
if (PrintMethodFlushing) {
tty->print_cr("### sweeper: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes, restarting compiler",
CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("restart_compiler live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
xtty->stamp();
xtty->end_elem();
}
}
}
}
}
@ -137,12 +176,12 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
if (nm->is_marked_for_reclamation()) {
assert(!nm->is_locked_by_vm(), "must not flush locked nmethods");
if (PrintMethodFlushing && Verbose) {
tty->print_cr("### Nmethod 0x%x (marked for reclamation) being flushed", nm);
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm);
}
nm->flush();
} else {
if (PrintMethodFlushing && Verbose) {
tty->print_cr("### Nmethod 0x%x (zombie) being marked for reclamation", nm);
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm);
}
nm->mark_for_reclamation();
_rescan = true;
@ -152,7 +191,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
// stack we can safely convert it to a zombie method
if (nm->can_not_entrant_be_converted()) {
if (PrintMethodFlushing && Verbose) {
tty->print_cr("### Nmethod 0x%x (not entrant) being made zombie", nm);
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm);
}
nm->make_zombie();
_rescan = true;
@ -167,7 +206,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
} else if (nm->is_unloaded()) {
// Unloaded code, just make it a zombie
if (PrintMethodFlushing && Verbose)
tty->print_cr("### Nmethod 0x%x (unloaded) being made zombie", nm);
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), nm);
if (nm->is_osr_method()) {
// No inline caches will ever point to osr methods, so we can just remove it
nm->flush();
@ -177,7 +216,167 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
}
} else {
assert(nm->is_alive(), "should be alive");
if (UseCodeCacheFlushing) {
if ((nm->method()->code() != nm) && !(nm->is_locked_by_vm()) && !(nm->is_osr_method()) &&
(_traversals > _was_full_traversal+2) && (((uint)nm->compile_id()) < _highest_marked) &&
CodeCache::needs_flushing()) {
// This method has not been called since the forced cleanup happened
nm->make_not_entrant();
}
}
// Clean-up all inline caches that points to zombie/non-reentrant methods
nm->cleanup_inline_caches();
}
}
// Code cache unloading: when compilers notice the code cache is getting full,
// they will call a vm op that comes here. This code attempts to speculatively
// unload the oldest half of the nmethods (based on the compile job id) by
// saving the old code in a list in the CodeCache. Then
// execution resumes. If a method so marked is not called by the second
// safepoint from the current one, the nmethod will be marked non-entrant and
// got rid of by normal sweeping. If the method is called, the methodOop's
// _code field is restored and the methodOop/nmethod
// go back to their normal state.
void NMethodSweeper::handle_full_code_cache(bool is_full) {
// Only the first one to notice can advise us to start early cleaning
if (!is_full){
jint old = Atomic::cmpxchg( 1, &_advise_to_sweep, 0 );
if (old != 0) {
return;
}
}
if (is_full) {
// Since code cache is full, immediately stop new compiles
bool did_set = CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation);
if (!did_set) {
// only the first to notice can start the cleaning,
// others will go back and block
return;
}
set_was_full(true);
// If we run out within MinCodeCacheFlushingInterval of the last unload time, give up
jlong now = os::javaTimeMillis();
jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000;
jlong curr_interval = now - _last_was_full;
if (curr_interval < max_interval) {
_rescan = true;
if (PrintMethodFlushing) {
tty->print_cr("### handle full too often, turning off compiler");
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("disable_compiler flushing_interval='" UINT64_FORMAT "' live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
curr_interval/1000, CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
xtty->stamp();
xtty->end_elem();
}
return;
}
}
VM_HandleFullCodeCache op(is_full);
VMThread::execute(&op);
// rescan again as soon as possible
_rescan = true;
}
void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) {
// If there was a race in detecting full code cache, only run
// one vm op for it or keep the compiler shut off
debug_only(jlong start = os::javaTimeMillis();)
if ((!was_full()) && (is_full)) {
if (!CodeCache::needs_flushing()) {
if (PrintMethodFlushing) {
tty->print_cr("### sweeper: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes, restarting compiler",
CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("restart_compiler live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
xtty->stamp();
xtty->end_elem();
}
CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation);
return;
}
}
// Traverse the code cache trying to dump the oldest nmethods
uint curr_max_comp_id = CompileBroker::get_compilation_id();
uint flush_target = ((curr_max_comp_id - _highest_marked) >> 1) + _highest_marked;
if (PrintMethodFlushing && Verbose) {
tty->print_cr("### Cleaning code cache: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes",
CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("start_cleaning_code_cache live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
xtty->stamp();
xtty->end_elem();
}
nmethod* nm = CodeCache::alive_nmethod(CodeCache::first());
jint disconnected = 0;
jint made_not_entrant = 0;
while ((nm != NULL)){
uint curr_comp_id = nm->compile_id();
// OSR methods cannot be flushed like this. Also, don't flush native methods
// since they are part of the JDK in most cases
if (nm->is_in_use() && (!nm->is_osr_method()) && (!nm->is_locked_by_vm()) &&
(!nm->is_native_method()) && ((curr_comp_id < flush_target))) {
if ((nm->method()->code() == nm)) {
// This method has not been previously considered for
// unloading or it was restored already
CodeCache::speculatively_disconnect(nm);
disconnected++;
} else if (nm->is_speculatively_disconnected()) {
// This method was previously considered for preemptive unloading and was not called since then
nm->method()->invocation_counter()->decay();
nm->method()->backedge_counter()->decay();
nm->make_not_entrant();
made_not_entrant++;
}
if (curr_comp_id > _highest_marked) {
_highest_marked = curr_comp_id;
}
}
nm = CodeCache::alive_nmethod(CodeCache::next(nm));
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("stop_cleaning_code_cache disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "' live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
disconnected, made_not_entrant, CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
xtty->stamp();
xtty->end_elem();
}
// Shut off compiler. Sweeper will run exiting from this safepoint
// and turn it back on if it clears enough space
if (was_full()) {
_last_was_full = os::javaTimeMillis();
CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation);
}
// After two more traversals the sweeper will get rid of unrestored nmethods
_was_full_traversal = _traversals;
#ifdef ASSERT
jlong end = os::javaTimeMillis();
if(PrintMethodFlushing && Verbose) {
tty->print_cr("### sweeper: unload time: " INT64_FORMAT, end-start);
}
#endif
}

View File

@ -38,6 +38,11 @@ class NMethodSweeper : public AllStatic {
static int _locked_seen; // Number of locked nmethods encountered during the scan
static int _not_entrant_seen_on_stack; // Number of not entrant nmethod were are still on stack
static bool _was_full; // remember if we did emergency unloading
static jint _advise_to_sweep; // flag to indicate code cache getting full
static jlong _last_was_full; // timestamp of last emergency unloading
static uint _highest_marked; // highest compile id dumped at last emergency unloading
static long _was_full_traversal; // trav number at last emergency unloading
static void process_nmethod(nmethod *nm);
public:
@ -51,4 +56,10 @@ class NMethodSweeper : public AllStatic {
// changes to false at safepoint so we can never overwrite it with false.
_rescan = true;
}
static void handle_full_code_cache(bool is_full); // Called by compilers who fail to allocate
static void speculative_disconnect_nmethods(bool was_full); // Called by vm op to deal with alloc failure
static void set_was_full(bool state) { _was_full = state; }
static bool was_full() { return _was_full; }
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -1173,6 +1173,7 @@ void JavaThread::initialize() {
_exception_handler_pc = 0;
_exception_stack_size = 0;
_jvmti_thread_state= NULL;
_should_post_on_exceptions_flag = JNI_FALSE;
_jvmti_get_loaded_classes_closure = NULL;
_interp_only_mode = 0;
_special_runtime_exit_condition = _no_async_condition;

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. 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
@ -1193,6 +1193,9 @@ class JavaThread: public Thread {
static ByteSize suspend_flags_offset() { return byte_offset_of(JavaThread, _suspend_flags ); }
static ByteSize do_not_unlock_if_synchronized_offset() { return byte_offset_of(JavaThread, _do_not_unlock_if_synchronized); }
static ByteSize should_post_on_exceptions_flag_offset() {
return byte_offset_of(JavaThread, _should_post_on_exceptions_flag);
}
#ifndef SERIALGC
static ByteSize satb_mark_queue_offset() { return byte_offset_of(JavaThread, _satb_mark_queue); }
@ -1432,6 +1435,16 @@ public:
void increment_interp_only_mode() { ++_interp_only_mode; }
void decrement_interp_only_mode() { --_interp_only_mode; }
// support for cached flag that indicates whether exceptions need to be posted for this thread
// if this is false, we can avoid deoptimizing when events are thrown
// this gets set to reflect whether jvmtiExport::post_exception_throw would actually do anything
private:
int _should_post_on_exceptions_flag;
public:
int should_post_on_exceptions_flag() { return _should_post_on_exceptions_flag; }
void set_should_post_on_exceptions_flag(int val) { _should_post_on_exceptions_flag = val; }
private:
ThreadStatistics *_thread_stat;

View File

@ -151,6 +151,10 @@ void VM_ZombieAll::doit() {
#endif // !PRODUCT
void VM_HandleFullCodeCache::doit() {
NMethodSweeper::speculative_disconnect_nmethods(_is_full);
}
void VM_Verify::doit() {
Universe::verify();
}

View File

@ -41,6 +41,7 @@
template(DeoptimizeFrame) \
template(DeoptimizeAll) \
template(ZombieAll) \
template(HandleFullCodeCache) \
template(Verify) \
template(PrintJNI) \
template(HeapDumper) \
@ -241,6 +242,16 @@ class VM_DeoptimizeFrame: public VM_Operation {
bool allow_nested_vm_operations() const { return true; }
};
class VM_HandleFullCodeCache: public VM_Operation {
private:
bool _is_full;
public:
VM_HandleFullCodeCache(bool is_full) { _is_full = is_full; }
VMOp_Type type() const { return VMOp_HandleFullCodeCache; }
void doit();
bool allow_nested_vm_operations() const { return true; }
};
#ifndef PRODUCT
class VM_DeoptimizeAll: public VM_Operation {
private:

View File

@ -0,0 +1,49 @@
/*
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
/**
* @test
* @bug 6792161
* @summary assert("No dead instructions after post-alloc")
*
* @run main/othervm -Xcomp -XX:MaxInlineSize=120 Test6792161
*/
import java.lang.reflect.Constructor;
public class Test6792161 {
static Constructor test(Class cls) throws Exception {
Class[] args= { String.class };
try {
return cls.getConstructor(args);
} catch (NoSuchMethodException e) {}
return cls.getConstructor(new Class[0]);
}
public static void main(final String[] args) throws Exception {
try {
for (int i = 0; i < 100000; i++) {
Constructor ctor = test(Class.forName("Test6792161"));
}
} catch (NoSuchMethodException e) {}
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
/**
* @test
* @bug 6916644
* @summary C2 compiler crash on x86
*
* @run main/othervm -Xcomp -XX:CompileOnly=Test6916644.test Test6916644
*/
public class Test6916644 {
static int result;
static int i1;
static int i2;
static public void test(double d) {
result = (d <= 0.0D) ? i1 : i2;
}
public static void main(String[] args) {
for (int i = 0; i < 100000; i++) {
// use an alternating value so the test doesn't always go
// the same direction. Otherwise we won't transform it
// into a cmove.
test(i & 1);
}
}
}

View File

@ -0,0 +1,138 @@
/*
* Copyright 2010 Google, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
/*
* @test
* @bug 6921969
* @summary Tests shorter long multiply sequences when the high 32 bits of long operands are known to be zero on x86_32
* @run main/othervm -Xbatch -XX:-Inline -XX:CompileOnly=.testNormal,.testLeftOptimized,.testRightOptimized,.testOptimized,.testLeftOptimized_LoadUI2L,.testRightOptimized_LoadUI2L,.testOptimized_LoadUI2L TestMultiplyLongHiZero
*/
// This test must run without any command line arguments.
public class TestMultiplyLongHiZero {
private static void check(long leftFactor, long rightFactor, long optimizedProduct, long constantProduct) {
long normalProduct = leftFactor * rightFactor; // unaffected by the new optimization
if (optimizedProduct != constantProduct || normalProduct != constantProduct) {
throw new RuntimeException("Not all three products are equal: " +
Long.toHexString(normalProduct) + ", " +
Long.toHexString(optimizedProduct) + ", " +
Long.toHexString(constantProduct));
}
}
private static int initInt(String[] args, int v) {
if (args.length > 0) {
try {
return Integer.valueOf(args[0]);
} catch (NumberFormatException e) { }
}
return v;
}
private static final long mask32 = 0x00000000FFFFFFFFL;
private static void testNormal(int leftFactor, int rightFactor, long constantProduct) {
check((long) leftFactor,
(long) rightFactor,
(long) leftFactor * (long) rightFactor, // unaffected by the new optimization
constantProduct);
}
private static void testLeftOptimized(int leftFactor, int rightFactor, long constantProduct) {
check((leftFactor & mask32),
(long) rightFactor,
(leftFactor & mask32) * (long) rightFactor, // left factor optimized
constantProduct);
}
private static void testRightOptimized(int leftFactor, int rightFactor, long constantProduct) {
check((long) leftFactor,
(rightFactor & mask32),
(long) leftFactor * (rightFactor & mask32), // right factor optimized
constantProduct);
}
private static void testOptimized(int leftFactor, int rightFactor, long constantProduct) {
check((leftFactor & mask32),
(rightFactor & mask32),
(leftFactor & mask32) * (rightFactor & mask32), // both factors optimized
constantProduct);
}
private static void testLeftOptimized_LoadUI2L(int leftFactor, int rightFactor, long constantProduct, int[] factors) {
check((leftFactor & mask32),
(long) rightFactor,
(factors[0] & mask32) * (long) rightFactor, // left factor optimized
constantProduct);
}
private static void testRightOptimized_LoadUI2L(int leftFactor, int rightFactor, long constantProduct, int[] factors) {
check((long) leftFactor,
(rightFactor & mask32),
(long) leftFactor * (factors[1] & mask32), // right factor optimized
constantProduct);
}
private static void testOptimized_LoadUI2L(int leftFactor, int rightFactor, long constantProduct, int[] factors) {
check((leftFactor & mask32),
(rightFactor & mask32),
(factors[0] & mask32) * (factors[1] & mask32), // both factors optimized
constantProduct);
}
private static void test(int leftFactor, int rightFactor,
long normalConstantProduct,
long leftOptimizedConstantProduct,
long rightOptimizedConstantProduct,
long optimizedConstantProduct) {
int[] factors = new int[2];
factors[0] = leftFactor;
factors[1] = rightFactor;
testNormal(leftFactor, rightFactor, normalConstantProduct);
testLeftOptimized(leftFactor, rightFactor, leftOptimizedConstantProduct);
testRightOptimized(leftFactor, rightFactor, rightOptimizedConstantProduct);
testOptimized(leftFactor, rightFactor, optimizedConstantProduct);
testLeftOptimized_LoadUI2L(leftFactor, rightFactor, leftOptimizedConstantProduct, factors);
testRightOptimized_LoadUI2L(leftFactor, rightFactor, rightOptimizedConstantProduct, factors);
testOptimized_LoadUI2L(leftFactor, rightFactor, optimizedConstantProduct, factors);
}
public static void main(String[] args) {
for (int i = 0; i < 100000; ++i) { // Trigger compilation
int i0 = initInt(args, 1);
int i1 = initInt(args, 3);
int i2 = initInt(args, -1);
int i3 = initInt(args, 0x7FFFFFFF);
test(i0, i1, 3L, 3L, 3L, 3L);
test(i0, i2, -1L, -1L, 0xFFFFFFFFL, 0xFFFFFFFFL);
test(i0, i3, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL);
test(i1, i2, -3L, -3L, 0x2FFFFFFFDL, 0x2FFFFFFFDL);
test(i1, i3, 0x17FFFFFFDL, 0x17FFFFFFDL, 0x17FFFFFFDL, 0x17FFFFFFDL);
test(i2, i3, 0xFFFFFFFF80000001L, 0x7FFFFFFE80000001L,
0xFFFFFFFF80000001L, 0x7FFFFFFE80000001L);
}
}
}

View File

@ -56,3 +56,4 @@ bfadab8c7b1bf806a49d3e1bc19ec919717f057a jdk7-b77
b1005c504358c18694c84e95fec16b28cdce7ae1 jdk7-b79
9219574db5936367114b0f31469837f27d5a375a jdk7-b80
204e59d488cdaa9eafa8cb7164ea955b5a9d4a51 jdk7-b81
c876ad22e4bf9d3c6460080db7ace478e29a3ff9 jdk7-b82

View File

@ -56,3 +56,4 @@ fc1c72d1dfbb17db7d46bba8db9afc39cbbb9299 jdk7-b78
c08894f5b6e594b9b12993e256b96c1b38099632 jdk7-b79
447767dee56a0f8cb89acc8bf7be5f9be7d84e8b jdk7-b80
f051045fe94a48fae1097f90cbd9227e6aae6b7e jdk7-b81
31573ae8eed15a6c170f3f0d1abd0b9109c0e086 jdk7-b82

View File

@ -56,3 +56,4 @@ e6a5d095c356a547cf5b3c8885885aca5e91e09b jdk7-b77
918920710d65432a2d54fdf407c1524a5571c4ad jdk7-b79
049cfaaa9a7374e3768a79969a799e8b59ad52fa jdk7-b80
10b993d417fcdb40480dad7032ac241f4b87f1af jdk7-b81
69ef657320ad5c35cfa12e4d8322d877e778f8b3 jdk7-b82