Merge
This commit is contained in:
commit
8ca6367144
@ -958,7 +958,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||||||
|
|
||||||
// reset handle block
|
// reset handle block
|
||||||
__ ld_ptr(G2_thread, in_bytes(JavaThread::active_handles_offset()), G3_scratch);
|
__ ld_ptr(G2_thread, in_bytes(JavaThread::active_handles_offset()), G3_scratch);
|
||||||
__ st_ptr(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
|
__ st(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
|
||||||
|
|
||||||
|
|
||||||
// handle exceptions (exception handling will handle unlocking!)
|
// handle exceptions (exception handling will handle unlocking!)
|
||||||
|
@ -2687,7 +2687,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||||||
if (!is_critical_native) {
|
if (!is_critical_native) {
|
||||||
// reset handle block
|
// reset handle block
|
||||||
__ ld_ptr(G2_thread, in_bytes(JavaThread::active_handles_offset()), L5);
|
__ ld_ptr(G2_thread, in_bytes(JavaThread::active_handles_offset()), L5);
|
||||||
__ st_ptr(G0, L5, JNIHandleBlock::top_offset_in_bytes());
|
__ st(G0, L5, JNIHandleBlock::top_offset_in_bytes());
|
||||||
|
|
||||||
__ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), G3_scratch);
|
__ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), G3_scratch);
|
||||||
check_forward_pending_exception(masm, G3_scratch);
|
check_forward_pending_exception(masm, G3_scratch);
|
||||||
|
@ -1147,7 +1147,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||||||
|
|
||||||
// reset handle block
|
// reset handle block
|
||||||
__ ld_ptr(G2_thread, JavaThread::active_handles_offset(), G3_scratch);
|
__ ld_ptr(G2_thread, JavaThread::active_handles_offset(), G3_scratch);
|
||||||
__ st_ptr(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
|
__ st(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
|
||||||
|
|
||||||
// If we have an oop result store it where it will be safe for any further gc
|
// If we have an oop result store it where it will be safe for any further gc
|
||||||
// until we return now that we've released the handle it might be protected by
|
// until we return now that we've released the handle it might be protected by
|
||||||
|
@ -1358,7 +1358,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||||||
|
|
||||||
// reset handle block
|
// reset handle block
|
||||||
__ movptr(t, Address(thread, JavaThread::active_handles_offset()));
|
__ movptr(t, Address(thread, JavaThread::active_handles_offset()));
|
||||||
__ movptr(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
|
__ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
|
||||||
|
|
||||||
// If result was an oop then unbox and save it in the frame
|
// If result was an oop then unbox and save it in the frame
|
||||||
{ Label L;
|
{ Label L;
|
||||||
|
@ -162,7 +162,7 @@ define_pd_global(uintx, TypeProfileLevel, 111);
|
|||||||
"Number of milliseconds to wait before start calculating aborts " \
|
"Number of milliseconds to wait before start calculating aborts " \
|
||||||
"for RTM locking") \
|
"for RTM locking") \
|
||||||
\
|
\
|
||||||
experimental(bool, UseRTMXendForLockBusy, false, \
|
experimental(bool, UseRTMXendForLockBusy, true, \
|
||||||
"Use RTM Xend instead of Xabort when lock busy") \
|
"Use RTM Xend instead of Xabort when lock busy") \
|
||||||
\
|
\
|
||||||
/* assembler */ \
|
/* assembler */ \
|
||||||
|
@ -1488,11 +1488,10 @@ void MacroAssembler::rtm_stack_locking(Register objReg, Register tmpReg, Registe
|
|||||||
movl(retry_on_abort_count_Reg, RTMRetryCount); // Retry on abort
|
movl(retry_on_abort_count_Reg, RTMRetryCount); // Retry on abort
|
||||||
bind(L_rtm_retry);
|
bind(L_rtm_retry);
|
||||||
}
|
}
|
||||||
if (!UseRTMXendForLockBusy) {
|
movptr(tmpReg, Address(objReg, 0));
|
||||||
movptr(tmpReg, Address(objReg, 0));
|
testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased
|
||||||
testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased
|
jcc(Assembler::notZero, IsInflated);
|
||||||
jcc(Assembler::notZero, IsInflated);
|
|
||||||
}
|
|
||||||
if (PrintPreciseRTMLockingStatistics || profile_rtm) {
|
if (PrintPreciseRTMLockingStatistics || profile_rtm) {
|
||||||
Label L_noincrement;
|
Label L_noincrement;
|
||||||
if (RTMTotalCountIncrRate > 1) {
|
if (RTMTotalCountIncrRate > 1) {
|
||||||
@ -1512,10 +1511,7 @@ void MacroAssembler::rtm_stack_locking(Register objReg, Register tmpReg, Registe
|
|||||||
Register abort_status_Reg = tmpReg; // status of abort is stored in RAX
|
Register abort_status_Reg = tmpReg; // status of abort is stored in RAX
|
||||||
if (UseRTMXendForLockBusy) {
|
if (UseRTMXendForLockBusy) {
|
||||||
xend();
|
xend();
|
||||||
movptr(tmpReg, Address(objReg, 0));
|
movptr(abort_status_Reg, 0x2); // Set the abort status to 2 (so we can retry)
|
||||||
testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased
|
|
||||||
jcc(Assembler::notZero, IsInflated);
|
|
||||||
movptr(abort_status_Reg, 0x1); // Set the abort status to 1 (as xabort does)
|
|
||||||
jmp(L_decrement_retry);
|
jmp(L_decrement_retry);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -2266,7 +2266,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||||||
if (!is_critical_native) {
|
if (!is_critical_native) {
|
||||||
// reset handle block
|
// reset handle block
|
||||||
__ movptr(rcx, Address(thread, JavaThread::active_handles_offset()));
|
__ movptr(rcx, Address(thread, JavaThread::active_handles_offset()));
|
||||||
__ movptr(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD);
|
__ movl(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD);
|
||||||
|
|
||||||
// Any exception pending?
|
// Any exception pending?
|
||||||
__ cmpptr(Address(thread, in_bytes(Thread::pending_exception_offset())), (int32_t)NULL_WORD);
|
__ cmpptr(Address(thread, in_bytes(Thread::pending_exception_offset())), (int32_t)NULL_WORD);
|
||||||
|
@ -2509,7 +2509,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||||||
if (!is_critical_native) {
|
if (!is_critical_native) {
|
||||||
// reset handle block
|
// reset handle block
|
||||||
__ movptr(rcx, Address(r15_thread, JavaThread::active_handles_offset()));
|
__ movptr(rcx, Address(r15_thread, JavaThread::active_handles_offset()));
|
||||||
__ movptr(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
|
__ movl(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pop our frame
|
// pop our frame
|
||||||
|
@ -1287,7 +1287,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||||||
|
|
||||||
// reset handle block
|
// reset handle block
|
||||||
__ movptr(t, Address(thread, JavaThread::active_handles_offset()));
|
__ movptr(t, Address(thread, JavaThread::active_handles_offset()));
|
||||||
__ movptr(Address(t, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD);
|
__ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD);
|
||||||
|
|
||||||
// If result was an oop then unbox and save it in the frame
|
// If result was an oop then unbox and save it in the frame
|
||||||
{ Label L;
|
{ Label L;
|
||||||
|
@ -1259,7 +1259,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||||||
|
|
||||||
// reset handle block
|
// reset handle block
|
||||||
__ movptr(t, Address(r15_thread, JavaThread::active_handles_offset()));
|
__ movptr(t, Address(r15_thread, JavaThread::active_handles_offset()));
|
||||||
__ movptr(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
|
__ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
|
||||||
|
|
||||||
// If result is an oop unbox and store it in frame where gc will see it
|
// If result is an oop unbox and store it in frame where gc will see it
|
||||||
// and result handler will pick it up
|
// and result handler will pick it up
|
||||||
|
@ -3409,6 +3409,10 @@ static void purge_previous_versions_internal(InstanceKlass* ik, int emcp_method_
|
|||||||
("purge: %s(%s): prev method @%d in version @%d is alive",
|
("purge: %s(%s): prev method @%d in version @%d is alive",
|
||||||
method->name()->as_C_string(),
|
method->name()->as_C_string(),
|
||||||
method->signature()->as_C_string(), j, i));
|
method->signature()->as_C_string(), j, i));
|
||||||
|
if (method->method_data() != NULL) {
|
||||||
|
// Clean out any weak method links
|
||||||
|
method->method_data()->clean_weak_method_links();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3418,6 +3422,14 @@ static void purge_previous_versions_internal(InstanceKlass* ik, int emcp_method_
|
|||||||
("purge: previous version stats: live=%d, deleted=%d", live_count,
|
("purge: previous version stats: live=%d, deleted=%d", live_count,
|
||||||
deleted_count));
|
deleted_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Array<Method*>* methods = ik->methods();
|
||||||
|
int num_methods = methods->length();
|
||||||
|
for (int index2 = 0; index2 < num_methods; ++index2) {
|
||||||
|
if (methods->at(index2)->method_data() != NULL) {
|
||||||
|
methods->at(index2)->method_data()->clean_weak_method_links();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// External interface for use during class unloading.
|
// External interface for use during class unloading.
|
||||||
|
@ -1531,9 +1531,35 @@ void MethodData::clean_extra_data_helper(DataLayout* dp, int shift, bool reset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove SpeculativeTrapData entries that reference an unloaded
|
class CleanExtraDataClosure : public StackObj {
|
||||||
// method
|
public:
|
||||||
void MethodData::clean_extra_data(BoolObjectClosure* is_alive) {
|
virtual bool is_live(Method* m) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check for entries that reference an unloaded method
|
||||||
|
class CleanExtraDataKlassClosure : public CleanExtraDataClosure {
|
||||||
|
private:
|
||||||
|
BoolObjectClosure* _is_alive;
|
||||||
|
public:
|
||||||
|
CleanExtraDataKlassClosure(BoolObjectClosure* is_alive) : _is_alive(is_alive) {}
|
||||||
|
bool is_live(Method* m) {
|
||||||
|
return m->method_holder()->is_loader_alive(_is_alive);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check for entries that reference a redefined method
|
||||||
|
class CleanExtraDataMethodClosure : public CleanExtraDataClosure {
|
||||||
|
public:
|
||||||
|
CleanExtraDataMethodClosure() {}
|
||||||
|
bool is_live(Method* m) {
|
||||||
|
return m->on_stack();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Remove SpeculativeTrapData entries that reference an unloaded or
|
||||||
|
// redefined method
|
||||||
|
void MethodData::clean_extra_data(CleanExtraDataClosure* cl) {
|
||||||
DataLayout* dp = extra_data_base();
|
DataLayout* dp = extra_data_base();
|
||||||
DataLayout* end = extra_data_limit();
|
DataLayout* end = extra_data_limit();
|
||||||
|
|
||||||
@ -1544,7 +1570,7 @@ void MethodData::clean_extra_data(BoolObjectClosure* is_alive) {
|
|||||||
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
||||||
Method* m = data->method();
|
Method* m = data->method();
|
||||||
assert(m != NULL, "should have a method");
|
assert(m != NULL, "should have a method");
|
||||||
if (!m->method_holder()->is_loader_alive(is_alive)) {
|
if (!cl->is_live(m)) {
|
||||||
// "shift" accumulates the number of cells for dead
|
// "shift" accumulates the number of cells for dead
|
||||||
// SpeculativeTrapData entries that have been seen so
|
// SpeculativeTrapData entries that have been seen so
|
||||||
// far. Following entries must be shifted left by that many
|
// far. Following entries must be shifted left by that many
|
||||||
@ -1575,9 +1601,9 @@ void MethodData::clean_extra_data(BoolObjectClosure* is_alive) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify there's no unloaded method referenced by a
|
// Verify there's no unloaded or redefined method referenced by a
|
||||||
// SpeculativeTrapData entry
|
// SpeculativeTrapData entry
|
||||||
void MethodData::verify_extra_data_clean(BoolObjectClosure* is_alive) {
|
void MethodData::verify_extra_data_clean(CleanExtraDataClosure* cl) {
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
DataLayout* dp = extra_data_base();
|
DataLayout* dp = extra_data_base();
|
||||||
DataLayout* end = extra_data_limit();
|
DataLayout* end = extra_data_limit();
|
||||||
@ -1587,7 +1613,7 @@ void MethodData::verify_extra_data_clean(BoolObjectClosure* is_alive) {
|
|||||||
case DataLayout::speculative_trap_data_tag: {
|
case DataLayout::speculative_trap_data_tag: {
|
||||||
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
||||||
Method* m = data->method();
|
Method* m = data->method();
|
||||||
assert(m != NULL && m->method_holder()->is_loader_alive(is_alive), "Method should exist");
|
assert(m != NULL && cl->is_live(m), "Method should exist");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DataLayout::bit_data_tag:
|
case DataLayout::bit_data_tag:
|
||||||
@ -1613,6 +1639,19 @@ void MethodData::clean_method_data(BoolObjectClosure* is_alive) {
|
|||||||
parameters->clean_weak_klass_links(is_alive);
|
parameters->clean_weak_klass_links(is_alive);
|
||||||
}
|
}
|
||||||
|
|
||||||
clean_extra_data(is_alive);
|
CleanExtraDataKlassClosure cl(is_alive);
|
||||||
verify_extra_data_clean(is_alive);
|
clean_extra_data(&cl);
|
||||||
|
verify_extra_data_clean(&cl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MethodData::clean_weak_method_links() {
|
||||||
|
for (ProfileData* data = first_data();
|
||||||
|
is_valid(data);
|
||||||
|
data = next_data(data)) {
|
||||||
|
data->clean_weak_method_links();
|
||||||
|
}
|
||||||
|
|
||||||
|
CleanExtraDataMethodClosure cl;
|
||||||
|
clean_extra_data(&cl);
|
||||||
|
verify_extra_data_clean(&cl);
|
||||||
}
|
}
|
||||||
|
@ -251,6 +251,9 @@ public:
|
|||||||
|
|
||||||
// GC support
|
// GC support
|
||||||
void clean_weak_klass_links(BoolObjectClosure* cl);
|
void clean_weak_klass_links(BoolObjectClosure* cl);
|
||||||
|
|
||||||
|
// Redefinition support
|
||||||
|
void clean_weak_method_links();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -506,6 +509,9 @@ public:
|
|||||||
// GC support
|
// GC support
|
||||||
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {}
|
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {}
|
||||||
|
|
||||||
|
// Redefinition support
|
||||||
|
virtual void clean_weak_method_links() {}
|
||||||
|
|
||||||
// CI translation: ProfileData can represent both MethodDataOop data
|
// CI translation: ProfileData can represent both MethodDataOop data
|
||||||
// as well as CIMethodData data. This function is provided for translating
|
// as well as CIMethodData data. This function is provided for translating
|
||||||
// an oop in a ProfileData to the ci equivalent. Generally speaking,
|
// an oop in a ProfileData to the ci equivalent. Generally speaking,
|
||||||
@ -1989,6 +1995,7 @@ public:
|
|||||||
//
|
//
|
||||||
|
|
||||||
CC_INTERP_ONLY(class BytecodeInterpreter;)
|
CC_INTERP_ONLY(class BytecodeInterpreter;)
|
||||||
|
class CleanExtraDataClosure;
|
||||||
|
|
||||||
class MethodData : public Metadata {
|
class MethodData : public Metadata {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
@ -2146,9 +2153,9 @@ private:
|
|||||||
static bool profile_parameters_jsr292_only();
|
static bool profile_parameters_jsr292_only();
|
||||||
static bool profile_all_parameters();
|
static bool profile_all_parameters();
|
||||||
|
|
||||||
void clean_extra_data(BoolObjectClosure* is_alive);
|
void clean_extra_data(CleanExtraDataClosure* cl);
|
||||||
void clean_extra_data_helper(DataLayout* dp, int shift, bool reset = false);
|
void clean_extra_data_helper(DataLayout* dp, int shift, bool reset = false);
|
||||||
void verify_extra_data_clean(BoolObjectClosure* is_alive);
|
void verify_extra_data_clean(CleanExtraDataClosure* cl);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static int header_size() {
|
static int header_size() {
|
||||||
@ -2440,6 +2447,8 @@ public:
|
|||||||
static bool profile_return_jsr292_only();
|
static bool profile_return_jsr292_only();
|
||||||
|
|
||||||
void clean_method_data(BoolObjectClosure* is_alive);
|
void clean_method_data(BoolObjectClosure* is_alive);
|
||||||
|
|
||||||
|
void clean_weak_method_links();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_OOPS_METHODDATAOOP_HPP
|
#endif // SHARE_VM_OOPS_METHODDATAOOP_HPP
|
||||||
|
@ -70,6 +70,7 @@ public:
|
|||||||
|
|
||||||
JVMState* ParseGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
JVMState* ParseGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||||
Compile* C = Compile::current();
|
Compile* C = Compile::current();
|
||||||
|
C->print_inlining_update(this);
|
||||||
|
|
||||||
if (is_osr()) {
|
if (is_osr()) {
|
||||||
// The JVMS for a OSR has a single argument (see its TypeFunc).
|
// The JVMS for a OSR has a single argument (see its TypeFunc).
|
||||||
@ -126,6 +127,7 @@ class DirectCallGenerator : public CallGenerator {
|
|||||||
|
|
||||||
JVMState* DirectCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
JVMState* DirectCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||||
GraphKit kit(jvms);
|
GraphKit kit(jvms);
|
||||||
|
kit.C->print_inlining_update(this);
|
||||||
bool is_static = method()->is_static();
|
bool is_static = method()->is_static();
|
||||||
address target = is_static ? SharedRuntime::get_resolve_static_call_stub()
|
address target = is_static ? SharedRuntime::get_resolve_static_call_stub()
|
||||||
: SharedRuntime::get_resolve_opt_virtual_call_stub();
|
: SharedRuntime::get_resolve_opt_virtual_call_stub();
|
||||||
@ -178,6 +180,8 @@ JVMState* VirtualCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
|||||||
GraphKit kit(jvms);
|
GraphKit kit(jvms);
|
||||||
Node* receiver = kit.argument(0);
|
Node* receiver = kit.argument(0);
|
||||||
|
|
||||||
|
kit.C->print_inlining_update(this);
|
||||||
|
|
||||||
if (kit.C->log() != NULL) {
|
if (kit.C->log() != NULL) {
|
||||||
kit.C->log()->elem("virtual_call bci='%d'", jvms->bci());
|
kit.C->log()->elem("virtual_call bci='%d'", jvms->bci());
|
||||||
}
|
}
|
||||||
@ -271,14 +275,13 @@ class LateInlineCallGenerator : public DirectCallGenerator {
|
|||||||
LateInlineCallGenerator(ciMethod* method, CallGenerator* inline_cg) :
|
LateInlineCallGenerator(ciMethod* method, CallGenerator* inline_cg) :
|
||||||
DirectCallGenerator(method, true), _inline_cg(inline_cg) {}
|
DirectCallGenerator(method, true), _inline_cg(inline_cg) {}
|
||||||
|
|
||||||
virtual bool is_late_inline() const { return true; }
|
virtual bool is_late_inline() const { return true; }
|
||||||
|
|
||||||
// Convert the CallStaticJava into an inline
|
// Convert the CallStaticJava into an inline
|
||||||
virtual void do_late_inline();
|
virtual void do_late_inline();
|
||||||
|
|
||||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
||||||
Compile *C = Compile::current();
|
Compile *C = Compile::current();
|
||||||
C->print_inlining_skip(this);
|
|
||||||
|
|
||||||
// Record that this call site should be revisited once the main
|
// Record that this call site should be revisited once the main
|
||||||
// parse is finished.
|
// parse is finished.
|
||||||
@ -296,10 +299,11 @@ class LateInlineCallGenerator : public DirectCallGenerator {
|
|||||||
virtual void print_inlining_late(const char* msg) {
|
virtual void print_inlining_late(const char* msg) {
|
||||||
CallNode* call = call_node();
|
CallNode* call = call_node();
|
||||||
Compile* C = Compile::current();
|
Compile* C = Compile::current();
|
||||||
C->print_inlining_insert(this);
|
C->print_inlining_assert_ready();
|
||||||
C->print_inlining(method(), call->jvms()->depth()-1, call->jvms()->bci(), msg);
|
C->print_inlining(method(), call->jvms()->depth()-1, call->jvms()->bci(), msg);
|
||||||
|
C->print_inlining_move_to(this);
|
||||||
|
C->print_inlining_update_delayed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void LateInlineCallGenerator::do_late_inline() {
|
void LateInlineCallGenerator::do_late_inline() {
|
||||||
@ -360,6 +364,10 @@ void LateInlineCallGenerator::do_late_inline() {
|
|||||||
map->set_argument(jvms, i1, call->in(TypeFunc::Parms + i1));
|
map->set_argument(jvms, i1, call->in(TypeFunc::Parms + i1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
C->print_inlining_assert_ready();
|
||||||
|
|
||||||
|
C->print_inlining_move_to(this);
|
||||||
|
|
||||||
// This check is done here because for_method_handle_inline() method
|
// This check is done here because for_method_handle_inline() method
|
||||||
// needs jvms for inlined state.
|
// needs jvms for inlined state.
|
||||||
if (!do_late_inline_check(jvms)) {
|
if (!do_late_inline_check(jvms)) {
|
||||||
@ -367,8 +375,6 @@ void LateInlineCallGenerator::do_late_inline() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
C->print_inlining_insert(this);
|
|
||||||
|
|
||||||
CompileLog* log = C->log();
|
CompileLog* log = C->log();
|
||||||
if (log != NULL) {
|
if (log != NULL) {
|
||||||
log->head("late_inline method='%d'", log->identify(method()));
|
log->head("late_inline method='%d'", log->identify(method()));
|
||||||
@ -388,7 +394,7 @@ void LateInlineCallGenerator::do_late_inline() {
|
|||||||
C->set_default_node_notes(entry_nn);
|
C->set_default_node_notes(entry_nn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now perform the inling using the synthesized JVMState
|
// Now perform the inlining using the synthesized JVMState
|
||||||
JVMState* new_jvms = _inline_cg->generate(jvms, NULL);
|
JVMState* new_jvms = _inline_cg->generate(jvms, NULL);
|
||||||
if (new_jvms == NULL) return; // no change
|
if (new_jvms == NULL) return; // no change
|
||||||
if (C->failing()) return;
|
if (C->failing()) return;
|
||||||
@ -431,6 +437,7 @@ class LateInlineMHCallGenerator : public LateInlineCallGenerator {
|
|||||||
|
|
||||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
||||||
JVMState* new_jvms = LateInlineCallGenerator::generate(jvms, parent_parser);
|
JVMState* new_jvms = LateInlineCallGenerator::generate(jvms, parent_parser);
|
||||||
|
|
||||||
if (_input_not_const) {
|
if (_input_not_const) {
|
||||||
// inlining won't be possible so no need to enqueue right now.
|
// inlining won't be possible so no need to enqueue right now.
|
||||||
call_node()->set_generator(this);
|
call_node()->set_generator(this);
|
||||||
@ -439,17 +446,14 @@ class LateInlineMHCallGenerator : public LateInlineCallGenerator {
|
|||||||
}
|
}
|
||||||
return new_jvms;
|
return new_jvms;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void print_inlining_late(const char* msg) {
|
|
||||||
if (!_input_not_const) return;
|
|
||||||
LateInlineCallGenerator::print_inlining_late(msg);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool LateInlineMHCallGenerator::do_late_inline_check(JVMState* jvms) {
|
bool LateInlineMHCallGenerator::do_late_inline_check(JVMState* jvms) {
|
||||||
|
|
||||||
CallGenerator* cg = for_method_handle_inline(jvms, _caller, method(), _input_not_const);
|
CallGenerator* cg = for_method_handle_inline(jvms, _caller, method(), _input_not_const);
|
||||||
|
|
||||||
|
Compile::current()->print_inlining_update_delayed(this);
|
||||||
|
|
||||||
if (!_input_not_const) {
|
if (!_input_not_const) {
|
||||||
_attempt++;
|
_attempt++;
|
||||||
}
|
}
|
||||||
@ -479,8 +483,6 @@ class LateInlineStringCallGenerator : public LateInlineCallGenerator {
|
|||||||
|
|
||||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
||||||
Compile *C = Compile::current();
|
Compile *C = Compile::current();
|
||||||
C->print_inlining_skip(this);
|
|
||||||
|
|
||||||
C->add_string_late_inline(this);
|
C->add_string_late_inline(this);
|
||||||
|
|
||||||
JVMState* new_jvms = DirectCallGenerator::generate(jvms, parent_parser);
|
JVMState* new_jvms = DirectCallGenerator::generate(jvms, parent_parser);
|
||||||
@ -502,7 +504,6 @@ class LateInlineBoxingCallGenerator : public LateInlineCallGenerator {
|
|||||||
|
|
||||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
||||||
Compile *C = Compile::current();
|
Compile *C = Compile::current();
|
||||||
C->print_inlining_skip(this);
|
|
||||||
|
|
||||||
C->add_boxing_late_inline(this);
|
C->add_boxing_late_inline(this);
|
||||||
|
|
||||||
@ -554,6 +555,8 @@ CallGenerator* CallGenerator::for_warm_call(WarmCallInfo* ci,
|
|||||||
|
|
||||||
JVMState* WarmCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
JVMState* WarmCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||||
Compile* C = Compile::current();
|
Compile* C = Compile::current();
|
||||||
|
C->print_inlining_update(this);
|
||||||
|
|
||||||
if (C->log() != NULL) {
|
if (C->log() != NULL) {
|
||||||
C->log()->elem("warm_call bci='%d'", jvms->bci());
|
C->log()->elem("warm_call bci='%d'", jvms->bci());
|
||||||
}
|
}
|
||||||
@ -632,6 +635,7 @@ CallGenerator* CallGenerator::for_predicted_call(ciKlass* predicted_receiver,
|
|||||||
|
|
||||||
JVMState* PredictedCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
JVMState* PredictedCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||||
GraphKit kit(jvms);
|
GraphKit kit(jvms);
|
||||||
|
kit.C->print_inlining_update(this);
|
||||||
PhaseGVN& gvn = kit.gvn();
|
PhaseGVN& gvn = kit.gvn();
|
||||||
// We need an explicit receiver null_check before checking its type.
|
// We need an explicit receiver null_check before checking its type.
|
||||||
// We share a map with the caller, so his JVMS gets adjusted.
|
// We share a map with the caller, so his JVMS gets adjusted.
|
||||||
@ -779,6 +783,9 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
|
|||||||
assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
|
assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
|
||||||
if (cg != NULL && cg->is_inline())
|
if (cg != NULL && cg->is_inline())
|
||||||
return cg;
|
return cg;
|
||||||
|
} else {
|
||||||
|
const char* msg = "receiver not constant";
|
||||||
|
if (PrintInlining) C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -844,11 +851,13 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
|
|||||||
// provide us with a type
|
// provide us with a type
|
||||||
speculative_receiver_type = receiver_type->speculative_type();
|
speculative_receiver_type = receiver_type->speculative_type();
|
||||||
}
|
}
|
||||||
|
|
||||||
CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, true, PROB_ALWAYS, speculative_receiver_type, true, true);
|
CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, true, PROB_ALWAYS, speculative_receiver_type, true, true);
|
||||||
assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
|
assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
|
||||||
if (cg != NULL && cg->is_inline())
|
if (cg != NULL && cg->is_inline())
|
||||||
return cg;
|
return cg;
|
||||||
|
} else {
|
||||||
|
const char* msg = "member_name not constant";
|
||||||
|
if (PrintInlining) C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -904,6 +913,7 @@ JVMState* PredictedIntrinsicGenerator::generate(JVMState* jvms, Parse* parent_pa
|
|||||||
if (kit.failing())
|
if (kit.failing())
|
||||||
return NULL; // might happen because of NodeCountInliningCutoff
|
return NULL; // might happen because of NodeCountInliningCutoff
|
||||||
|
|
||||||
|
kit.C->print_inlining_update(this);
|
||||||
SafePointNode* slow_map = NULL;
|
SafePointNode* slow_map = NULL;
|
||||||
JVMState* slow_jvms;
|
JVMState* slow_jvms;
|
||||||
if (slow_ctl != NULL) {
|
if (slow_ctl != NULL) {
|
||||||
@ -1017,6 +1027,7 @@ CallGenerator::for_uncommon_trap(ciMethod* m,
|
|||||||
|
|
||||||
JVMState* UncommonTrapCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
JVMState* UncommonTrapCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||||
GraphKit kit(jvms);
|
GraphKit kit(jvms);
|
||||||
|
kit.C->print_inlining_update(this);
|
||||||
// Take the trap with arguments pushed on the stack. (Cf. null_check_receiver).
|
// Take the trap with arguments pushed on the stack. (Cf. null_check_receiver).
|
||||||
int nargs = method()->arg_size();
|
int nargs = method()->arg_size();
|
||||||
kit.inc_sp(nargs);
|
kit.inc_sp(nargs);
|
||||||
|
@ -662,6 +662,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
|
|||||||
_inlining_progress(false),
|
_inlining_progress(false),
|
||||||
_inlining_incrementally(false),
|
_inlining_incrementally(false),
|
||||||
_print_inlining_list(NULL),
|
_print_inlining_list(NULL),
|
||||||
|
_print_inlining_stream(NULL),
|
||||||
_print_inlining_idx(0),
|
_print_inlining_idx(0),
|
||||||
_preserve_jvm_state(0) {
|
_preserve_jvm_state(0) {
|
||||||
C = this;
|
C = this;
|
||||||
@ -723,9 +724,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
|
|||||||
PhaseGVN gvn(node_arena(), estimated_size);
|
PhaseGVN gvn(node_arena(), estimated_size);
|
||||||
set_initial_gvn(&gvn);
|
set_initial_gvn(&gvn);
|
||||||
|
|
||||||
if (print_inlining() || print_intrinsics()) {
|
print_inlining_init();
|
||||||
_print_inlining_list = new (comp_arena())GrowableArray<PrintInliningBuffer>(comp_arena(), 1, 1, PrintInliningBuffer());
|
|
||||||
}
|
|
||||||
{ // Scope for timing the parser
|
{ // Scope for timing the parser
|
||||||
TracePhase t3("parse", &_t_parser, true);
|
TracePhase t3("parse", &_t_parser, true);
|
||||||
|
|
||||||
@ -967,6 +966,7 @@ Compile::Compile( ciEnv* ci_env,
|
|||||||
_inlining_progress(false),
|
_inlining_progress(false),
|
||||||
_inlining_incrementally(false),
|
_inlining_incrementally(false),
|
||||||
_print_inlining_list(NULL),
|
_print_inlining_list(NULL),
|
||||||
|
_print_inlining_stream(NULL),
|
||||||
_print_inlining_idx(0),
|
_print_inlining_idx(0),
|
||||||
_preserve_jvm_state(0),
|
_preserve_jvm_state(0),
|
||||||
_allowed_reasons(0) {
|
_allowed_reasons(0) {
|
||||||
@ -2023,6 +2023,8 @@ void Compile::Optimize() {
|
|||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
int loop_opts_cnt;
|
int loop_opts_cnt;
|
||||||
|
|
||||||
|
print_inlining_reinit();
|
||||||
|
|
||||||
NOT_PRODUCT( verify_graph_edges(); )
|
NOT_PRODUCT( verify_graph_edges(); )
|
||||||
|
|
||||||
print_method(PHASE_AFTER_PARSING);
|
print_method(PHASE_AFTER_PARSING);
|
||||||
@ -3755,30 +3757,114 @@ void Compile::ConstantTable::fill_jump_table(CodeBuffer& cb, MachConstantNode* n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compile::dump_inlining() {
|
// The message about the current inlining is accumulated in
|
||||||
|
// _print_inlining_stream and transfered into the _print_inlining_list
|
||||||
|
// once we know whether inlining succeeds or not. For regular
|
||||||
|
// inlining, messages are appended to the buffer pointed by
|
||||||
|
// _print_inlining_idx in the _print_inlining_list. For late inlining,
|
||||||
|
// a new buffer is added after _print_inlining_idx in the list. This
|
||||||
|
// way we can update the inlining message for late inlining call site
|
||||||
|
// when the inlining is attempted again.
|
||||||
|
void Compile::print_inlining_init() {
|
||||||
if (print_inlining() || print_intrinsics()) {
|
if (print_inlining() || print_intrinsics()) {
|
||||||
|
_print_inlining_stream = new stringStream();
|
||||||
|
_print_inlining_list = new (comp_arena())GrowableArray<PrintInliningBuffer>(comp_arena(), 1, 1, PrintInliningBuffer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compile::print_inlining_reinit() {
|
||||||
|
if (print_inlining() || print_intrinsics()) {
|
||||||
|
// Re allocate buffer when we change ResourceMark
|
||||||
|
_print_inlining_stream = new stringStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compile::print_inlining_reset() {
|
||||||
|
_print_inlining_stream->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compile::print_inlining_commit() {
|
||||||
|
assert(print_inlining() || print_intrinsics(), "PrintInlining off?");
|
||||||
|
// Transfer the message from _print_inlining_stream to the current
|
||||||
|
// _print_inlining_list buffer and clear _print_inlining_stream.
|
||||||
|
_print_inlining_list->at(_print_inlining_idx).ss()->write(_print_inlining_stream->as_string(), _print_inlining_stream->size());
|
||||||
|
print_inlining_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compile::print_inlining_push() {
|
||||||
|
// Add new buffer to the _print_inlining_list at current position
|
||||||
|
_print_inlining_idx++;
|
||||||
|
_print_inlining_list->insert_before(_print_inlining_idx, PrintInliningBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
Compile::PrintInliningBuffer& Compile::print_inlining_current() {
|
||||||
|
return _print_inlining_list->at(_print_inlining_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compile::print_inlining_update(CallGenerator* cg) {
|
||||||
|
if (print_inlining() || print_intrinsics()) {
|
||||||
|
if (!cg->is_late_inline()) {
|
||||||
|
if (print_inlining_current().cg() != NULL) {
|
||||||
|
print_inlining_push();
|
||||||
|
}
|
||||||
|
print_inlining_commit();
|
||||||
|
} else {
|
||||||
|
if (print_inlining_current().cg() != cg &&
|
||||||
|
(print_inlining_current().cg() != NULL ||
|
||||||
|
print_inlining_current().ss()->size() != 0)) {
|
||||||
|
print_inlining_push();
|
||||||
|
}
|
||||||
|
print_inlining_commit();
|
||||||
|
print_inlining_current().set_cg(cg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compile::print_inlining_move_to(CallGenerator* cg) {
|
||||||
|
// We resume inlining at a late inlining call site. Locate the
|
||||||
|
// corresponding inlining buffer so that we can update it.
|
||||||
|
if (print_inlining()) {
|
||||||
|
for (int i = 0; i < _print_inlining_list->length(); i++) {
|
||||||
|
if (_print_inlining_list->adr_at(i)->cg() == cg) {
|
||||||
|
_print_inlining_idx = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ShouldNotReachHere();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compile::print_inlining_update_delayed(CallGenerator* cg) {
|
||||||
|
if (print_inlining()) {
|
||||||
|
assert(_print_inlining_stream->size() > 0, "missing inlining msg");
|
||||||
|
assert(print_inlining_current().cg() == cg, "wrong entry");
|
||||||
|
// replace message with new message
|
||||||
|
_print_inlining_list->at_put(_print_inlining_idx, PrintInliningBuffer());
|
||||||
|
print_inlining_commit();
|
||||||
|
print_inlining_current().set_cg(cg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compile::print_inlining_assert_ready() {
|
||||||
|
assert(!_print_inlining || _print_inlining_stream->size() == 0, "loosing data");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compile::dump_inlining() {
|
||||||
|
bool do_print_inlining = print_inlining() || print_intrinsics();
|
||||||
|
if (do_print_inlining) {
|
||||||
// Print inlining message for candidates that we couldn't inline
|
// Print inlining message for candidates that we couldn't inline
|
||||||
// for lack of space or non constant receiver
|
// for lack of space
|
||||||
for (int i = 0; i < _late_inlines.length(); i++) {
|
for (int i = 0; i < _late_inlines.length(); i++) {
|
||||||
CallGenerator* cg = _late_inlines.at(i);
|
CallGenerator* cg = _late_inlines.at(i);
|
||||||
cg->print_inlining_late("live nodes > LiveNodeCountInliningCutoff");
|
if (!cg->is_mh_late_inline()) {
|
||||||
}
|
const char* msg = "live nodes > LiveNodeCountInliningCutoff";
|
||||||
Unique_Node_List useful;
|
if (do_print_inlining) {
|
||||||
useful.push(root());
|
cg->print_inlining_late(msg);
|
||||||
for (uint next = 0; next < useful.size(); ++next) {
|
}
|
||||||
Node* n = useful.at(next);
|
|
||||||
if (n->is_Call() && n->as_Call()->generator() != NULL && n->as_Call()->generator()->call_node() == n) {
|
|
||||||
CallNode* call = n->as_Call();
|
|
||||||
CallGenerator* cg = call->generator();
|
|
||||||
cg->print_inlining_late("receiver not constant");
|
|
||||||
}
|
|
||||||
uint max = n->len();
|
|
||||||
for ( uint i = 0; i < max; ++i ) {
|
|
||||||
Node *m = n->in(i);
|
|
||||||
if ( m == NULL ) continue;
|
|
||||||
useful.push(m);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (do_print_inlining) {
|
||||||
for (int i = 0; i < _print_inlining_list->length(); i++) {
|
for (int i = 0; i < _print_inlining_list->length(); i++) {
|
||||||
tty->print(_print_inlining_list->adr_at(i)->ss()->as_string());
|
tty->print(_print_inlining_list->adr_at(i)->ss()->as_string());
|
||||||
}
|
}
|
||||||
|
@ -416,6 +416,7 @@ class Compile : public Phase {
|
|||||||
void set_cg(CallGenerator* cg) { _cg = cg; }
|
void set_cg(CallGenerator* cg) { _cg = cg; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
stringStream* _print_inlining_stream;
|
||||||
GrowableArray<PrintInliningBuffer>* _print_inlining_list;
|
GrowableArray<PrintInliningBuffer>* _print_inlining_list;
|
||||||
int _print_inlining_idx;
|
int _print_inlining_idx;
|
||||||
|
|
||||||
@ -433,33 +434,24 @@ class Compile : public Phase {
|
|||||||
|
|
||||||
void* _replay_inline_data; // Pointer to data loaded from file
|
void* _replay_inline_data; // Pointer to data loaded from file
|
||||||
|
|
||||||
|
void print_inlining_init();
|
||||||
|
void print_inlining_reinit();
|
||||||
|
void print_inlining_commit();
|
||||||
|
void print_inlining_push();
|
||||||
|
PrintInliningBuffer& print_inlining_current();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
outputStream* print_inlining_stream() const {
|
outputStream* print_inlining_stream() const {
|
||||||
return _print_inlining_list->adr_at(_print_inlining_idx)->ss();
|
assert(print_inlining() || print_intrinsics(), "PrintInlining off?");
|
||||||
|
return _print_inlining_stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_inlining_skip(CallGenerator* cg) {
|
void print_inlining_update(CallGenerator* cg);
|
||||||
if (_print_inlining) {
|
void print_inlining_update_delayed(CallGenerator* cg);
|
||||||
_print_inlining_list->adr_at(_print_inlining_idx)->set_cg(cg);
|
void print_inlining_move_to(CallGenerator* cg);
|
||||||
_print_inlining_idx++;
|
void print_inlining_assert_ready();
|
||||||
_print_inlining_list->insert_before(_print_inlining_idx, PrintInliningBuffer());
|
void print_inlining_reset();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_inlining_insert(CallGenerator* cg) {
|
|
||||||
if (_print_inlining) {
|
|
||||||
for (int i = 0; i < _print_inlining_list->length(); i++) {
|
|
||||||
if (_print_inlining_list->adr_at(i)->cg() == cg) {
|
|
||||||
_print_inlining_list->insert_before(i+1, PrintInliningBuffer());
|
|
||||||
_print_inlining_idx = i+1;
|
|
||||||
_print_inlining_list->adr_at(i)->set_cg(NULL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ShouldNotReachHere();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_inlining(ciMethod* method, int inline_level, int bci, const char* msg = NULL) {
|
void print_inlining(ciMethod* method, int inline_level, int bci, const char* msg = NULL) {
|
||||||
stringStream ss;
|
stringStream ss;
|
||||||
|
@ -294,6 +294,8 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
|
|||||||
// There was no special inlining tactic, or it bailed out.
|
// There was no special inlining tactic, or it bailed out.
|
||||||
// Use a more generic tactic, like a simple call.
|
// Use a more generic tactic, like a simple call.
|
||||||
if (call_does_dispatch) {
|
if (call_does_dispatch) {
|
||||||
|
const char* msg = "virtual call";
|
||||||
|
if (PrintInlining) print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg);
|
||||||
return CallGenerator::for_virtual_call(callee, vtable_index);
|
return CallGenerator::for_virtual_call(callee, vtable_index);
|
||||||
} else {
|
} else {
|
||||||
// Class Hierarchy Analysis or Type Profile reveals a unique target,
|
// Class Hierarchy Analysis or Type Profile reveals a unique target,
|
||||||
@ -396,6 +398,8 @@ void Parse::do_call() {
|
|||||||
// our contribution to it is cleaned up right here.
|
// our contribution to it is cleaned up right here.
|
||||||
kill_dead_locals();
|
kill_dead_locals();
|
||||||
|
|
||||||
|
C->print_inlining_assert_ready();
|
||||||
|
|
||||||
// Set frequently used booleans
|
// Set frequently used booleans
|
||||||
const bool is_virtual = bc() == Bytecodes::_invokevirtual;
|
const bool is_virtual = bc() == Bytecodes::_invokevirtual;
|
||||||
const bool is_virtual_or_interface = is_virtual || bc() == Bytecodes::_invokeinterface;
|
const bool is_virtual_or_interface = is_virtual || bc() == Bytecodes::_invokeinterface;
|
||||||
@ -531,7 +535,8 @@ void Parse::do_call() {
|
|||||||
// intrinsic was expecting to optimize. Should always be possible to
|
// intrinsic was expecting to optimize. Should always be possible to
|
||||||
// get a normal java call that may inline in that case
|
// get a normal java call that may inline in that case
|
||||||
cg = C->call_generator(cg->method(), vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), speculative_receiver_type, /* allow_intrinsics= */ false);
|
cg = C->call_generator(cg->method(), vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), speculative_receiver_type, /* allow_intrinsics= */ false);
|
||||||
if ((new_jvms = cg->generate(jvms, this)) == NULL) {
|
new_jvms = cg->generate(jvms, this);
|
||||||
|
if (new_jvms == NULL) {
|
||||||
guarantee(failing(), "call failed to generate: calls should work");
|
guarantee(failing(), "call failed to generate: calls should work");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -620,6 +620,7 @@ JVMState* LibraryIntrinsic::generate(JVMState* jvms, Parse* parent_parser) {
|
|||||||
}
|
}
|
||||||
// Push the result from the inlined method onto the stack.
|
// Push the result from the inlined method onto the stack.
|
||||||
kit.push_result();
|
kit.push_result();
|
||||||
|
C->print_inlining_update(this);
|
||||||
return kit.transfer_exceptions_into_jvms();
|
return kit.transfer_exceptions_into_jvms();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,6 +638,7 @@ JVMState* LibraryIntrinsic::generate(JVMState* jvms, Parse* parent_parser) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_failed);
|
C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_failed);
|
||||||
|
C->print_inlining_update(this);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,6 +438,30 @@ WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobjec
|
|||||||
return (mh->queued_for_compilation() || nm != NULL);
|
return (mh->queued_for_compilation() || nm != NULL);
|
||||||
WB_END
|
WB_END
|
||||||
|
|
||||||
|
class VM_WhiteBoxOperation : public VM_Operation {
|
||||||
|
public:
|
||||||
|
VM_WhiteBoxOperation() { }
|
||||||
|
VMOp_Type type() const { return VMOp_WhiteBoxOperation; }
|
||||||
|
bool allow_nested_vm_operations() const { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlwaysFalseClosure : public BoolObjectClosure {
|
||||||
|
public:
|
||||||
|
bool do_object_b(oop p) { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
static AlwaysFalseClosure always_false;
|
||||||
|
|
||||||
|
class VM_WhiteBoxCleanMethodData : public VM_WhiteBoxOperation {
|
||||||
|
public:
|
||||||
|
VM_WhiteBoxCleanMethodData(MethodData* mdo) : _mdo(mdo) { }
|
||||||
|
void doit() {
|
||||||
|
_mdo->clean_method_data(&always_false);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
MethodData* _mdo;
|
||||||
|
};
|
||||||
|
|
||||||
WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
|
WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
|
||||||
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
|
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
|
||||||
CHECK_JNI_EXCEPTION(env);
|
CHECK_JNI_EXCEPTION(env);
|
||||||
@ -453,6 +477,8 @@ WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
|
|||||||
for (int i = 0; i < arg_count; i++) {
|
for (int i = 0; i < arg_count; i++) {
|
||||||
mdo->set_arg_modified(i, 0);
|
mdo->set_arg_modified(i, 0);
|
||||||
}
|
}
|
||||||
|
VM_WhiteBoxCleanMethodData op(mdo);
|
||||||
|
VMThread::execute(&op);
|
||||||
}
|
}
|
||||||
|
|
||||||
mh->clear_not_c1_compilable();
|
mh->clear_not_c1_compilable();
|
||||||
|
@ -1268,8 +1268,6 @@ methodHandle SharedRuntime::resolve_sub_helper(JavaThread *thread,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (is_virtual) {
|
if (is_virtual) {
|
||||||
nmethod* nm = callee_nm;
|
|
||||||
if (nm == NULL) CodeCache::find_blob(caller_frame.pc());
|
|
||||||
CompiledIC* inline_cache = CompiledIC_before(caller_nm, caller_frame.pc());
|
CompiledIC* inline_cache = CompiledIC_before(caller_nm, caller_frame.pc());
|
||||||
if (inline_cache->is_clean()) {
|
if (inline_cache->is_clean()) {
|
||||||
inline_cache->set_to_monomorphic(virtual_call_info);
|
inline_cache->set_to_monomorphic(virtual_call_info);
|
||||||
|
@ -97,6 +97,7 @@
|
|||||||
template(Exit) \
|
template(Exit) \
|
||||||
template(LinuxDllLoad) \
|
template(LinuxDllLoad) \
|
||||||
template(RotateGCLog) \
|
template(RotateGCLog) \
|
||||||
|
template(WhiteBoxOperation) \
|
||||||
|
|
||||||
class VM_Operation: public CHeapObj<mtInternal> {
|
class VM_Operation: public CHeapObj<mtInternal> {
|
||||||
public:
|
public:
|
||||||
|
142
hotspot/test/compiler/profiling/spectrapredefineclass/Agent.java
Normal file
142
hotspot/test/compiler/profiling/spectrapredefineclass/Agent.java
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.security.*;
|
||||||
|
import java.lang.instrument.*;
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
import com.sun.tools.attach.VirtualMachine;
|
||||||
|
|
||||||
|
class A {
|
||||||
|
void m() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
void m() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends A {
|
||||||
|
void m() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
|
||||||
|
static public void m() throws Exception {
|
||||||
|
for (int i = 0; i < 20000; i++) {
|
||||||
|
m1(a);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
m1(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean m1(A a) {
|
||||||
|
boolean res = Agent.m2(a);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public A a = new A();
|
||||||
|
static public B b = new B();
|
||||||
|
static public C c = new C();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Agent implements ClassFileTransformer {
|
||||||
|
|
||||||
|
|
||||||
|
static class MemoryChunk {
|
||||||
|
MemoryChunk other;
|
||||||
|
long[] array;
|
||||||
|
MemoryChunk(MemoryChunk other) {
|
||||||
|
other = other;
|
||||||
|
array = new long[1024 * 1024 * 1024];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public boolean m2(A a) {
|
||||||
|
boolean res = false;
|
||||||
|
if (a.getClass() == B.class) {
|
||||||
|
a.m();
|
||||||
|
} else {
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void main(String[] args) throws Exception {
|
||||||
|
// Create speculative trap entries
|
||||||
|
Test.m();
|
||||||
|
|
||||||
|
String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
|
||||||
|
int p = nameOfRunningVM.indexOf('@');
|
||||||
|
String pid = nameOfRunningVM.substring(0, p);
|
||||||
|
|
||||||
|
// Make the nmethod go away
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
System.gc();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redefine class
|
||||||
|
try {
|
||||||
|
VirtualMachine vm = VirtualMachine.attach(pid);
|
||||||
|
vm.loadAgent(System.getProperty("test.classes",".") + "/agent.jar", "");
|
||||||
|
vm.detach();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Test.m();
|
||||||
|
// GC will hit dead method pointer
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
System.gc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized byte[] transform(final ClassLoader classLoader,
|
||||||
|
final String className,
|
||||||
|
Class<?> classBeingRedefined,
|
||||||
|
ProtectionDomain protectionDomain,
|
||||||
|
byte[] classfileBuffer) {
|
||||||
|
System.out.println("Transforming class " + className);
|
||||||
|
return classfileBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void redefine(String agentArgs, Instrumentation instrumentation, Class to_redefine) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
instrumentation.retransformClasses(to_redefine);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void agentmain(String agentArgs, Instrumentation instrumentation) throws Exception {
|
||||||
|
Agent transformer = new Agent();
|
||||||
|
instrumentation.addTransformer(transformer, true);
|
||||||
|
|
||||||
|
redefine(agentArgs, instrumentation, Test.class);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import com.oracle.java.testlibrary.*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8038636
|
||||||
|
* @library /testlibrary
|
||||||
|
* @build Agent
|
||||||
|
* @run main ClassFileInstaller Agent
|
||||||
|
* @run main Launcher
|
||||||
|
* @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -Xmx1M -XX:ReservedCodeCacheSize=3M Agent
|
||||||
|
*/
|
||||||
|
public class Launcher {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
PrintWriter pw = new PrintWriter("MANIFEST.MF");
|
||||||
|
pw.println("Agent-Class: Agent");
|
||||||
|
pw.println("Can-Retransform-Classes: true");
|
||||||
|
pw.close();
|
||||||
|
|
||||||
|
ProcessBuilder pb = new ProcessBuilder();
|
||||||
|
pb.command(new String[] { JDKToolFinder.getJDKTool("jar"), "cmf", "MANIFEST.MF", System.getProperty("test.classes",".") + "/agent.jar", "Agent.class"});
|
||||||
|
pb.start().waitFor();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user