This commit is contained in:
J. Duke 2017-07-05 17:01:48 +02:00
commit 2fc8097001
567 changed files with 16668 additions and 29811 deletions

View File

@ -47,3 +47,4 @@ e1b972ff53cd58f825791f8ed9b2deffd16e768c jdk7-b68
175cb3fe615998d1004c6d3fd96e6d2e86b6772d jdk7-b70
4c36e9853dda27bdac5ef4839a610509fbe31d34 jdk7-b71
0d7e03b426df27c21dcc44ffb9178eacd1b04f10 jdk7-b72
3ac6dcf7823205546fbbc3d4ea59f37358d0b0d4 jdk7-b73

View File

@ -47,3 +47,4 @@ a12ea7c7b497b4ba7830550095ef633bd6f43971 jdk7-b67
175bd68779546078dbdb6dacd7f0aced79ed22b1 jdk7-b70
3f1ef7f899ea2aec189c4fb67e5c8fa374437c50 jdk7-b71
c793a31209263fbb867c23c752599d85c21abb73 jdk7-b72
b751c528c55560cf2adeaeef24b39ca1f4d1cbf7 jdk7-b73

View File

@ -47,3 +47,4 @@ d07e68298d4e17ebf93d8299e43fcc3ded26472a jdk7-b68
0632c3e615a315ff11e2ab1d64f4d82ff9853461 jdk7-b70
50a95aa4a247f0cbbf66df285a8b1d78ffb153d9 jdk7-b71
a94714c550658fd6741793ef036cb9625dc2ab1a jdk7-b72
faf94d94786b621f8e13cbcc941ca69c6d967c3f jdk7-b73

View File

@ -33,6 +33,7 @@ import sun.jvm.hotspot.utilities.*;
public class CodeCache {
private static AddressField heapField;
private static AddressField scavengeRootNMethodsField;
private static VirtualConstructor virtualConstructor;
private CodeHeap heap;
@ -49,6 +50,7 @@ public class CodeCache {
Type type = db.lookupType("CodeCache");
heapField = type.getAddressField("_heap");
scavengeRootNMethodsField = type.getAddressField("_scavenge_root_nmethods");
virtualConstructor = new VirtualConstructor(db);
// Add mappings for all possible CodeBlob subclasses
@ -67,6 +69,10 @@ public class CodeCache {
heap = (CodeHeap) VMObjectFactory.newObject(CodeHeap.class, heapField.getValue());
}
public NMethod scavengeRootMethods() {
return (NMethod) VMObjectFactory.newObject(NMethod.class, scavengeRootNMethodsField.getValue());
}
public boolean contains(Address p) {
return getHeap().contains(p);
}

View File

@ -40,7 +40,10 @@ public class NMethod extends CodeBlob {
/** != InvocationEntryBci if this nmethod is an on-stack replacement method */
private static CIntegerField entryBCIField;
/** To support simple linked-list chaining of nmethods */
private static AddressField linkField;
private static AddressField osrLinkField;
private static AddressField scavengeRootLinkField;
private static CIntegerField scavengeRootStateField;
/** Offsets for different nmethod parts */
private static CIntegerField exceptionOffsetField;
private static CIntegerField deoptOffsetField;
@ -87,7 +90,10 @@ public class NMethod extends CodeBlob {
zombieInstructionSizeField = type.getCIntegerField("_zombie_instruction_size");
methodField = type.getOopField("_method");
entryBCIField = type.getCIntegerField("_entry_bci");
linkField = type.getAddressField("_link");
osrLinkField = type.getAddressField("_osr_link");
scavengeRootLinkField = type.getAddressField("_scavenge_root_link");
scavengeRootStateField = type.getCIntegerField("_scavenge_root_state");
exceptionOffsetField = type.getCIntegerField("_exception_offset");
deoptOffsetField = type.getCIntegerField("_deoptimize_offset");
origPCOffsetField = type.getCIntegerField("_orig_pc_offset");
@ -219,10 +225,19 @@ public class NMethod extends CodeBlob {
return getEntryBCI();
}
public NMethod getLink() {
return (NMethod) VMObjectFactory.newObject(NMethod.class, linkField.getValue(addr));
public NMethod getOSRLink() {
return (NMethod) VMObjectFactory.newObject(NMethod.class, osrLinkField.getValue(addr));
}
public NMethod getScavengeRootLink() {
return (NMethod) VMObjectFactory.newObject(NMethod.class, scavengeRootLinkField.getValue(addr));
}
public int getScavengeRootState() {
return (int) scavengeRootStateField.getValue(addr);
}
/** Tells whether frames described by this nmethod can be
deoptimized. Note: native wrappers cannot be deoptimized. */
public boolean canBeDeoptimized() { return isJavaMethod(); }

View File

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

View File

@ -4676,3 +4676,50 @@ void MacroAssembler::reinit_heapbase() {
load_ptr_contents(base, G6_heapbase);
}
}
// Compare char[] arrays aligned to 4 bytes.
void MacroAssembler::char_arrays_equals(Register ary1, Register ary2,
Register limit, Register result,
Register chr1, Register chr2, Label& Ldone) {
Label Lvector, Lloop;
assert(chr1 == result, "should be the same");
// Note: limit contains number of bytes (2*char_elements) != 0.
andcc(limit, 0x2, chr1); // trailing character ?
br(Assembler::zero, false, Assembler::pt, Lvector);
delayed()->nop();
// compare the trailing char
sub(limit, sizeof(jchar), limit);
lduh(ary1, limit, chr1);
lduh(ary2, limit, chr2);
cmp(chr1, chr2);
br(Assembler::notEqual, true, Assembler::pt, Ldone);
delayed()->mov(G0, result); // not equal
// only one char ?
br_on_reg_cond(rc_z, true, Assembler::pn, limit, Ldone);
delayed()->add(G0, 1, result); // zero-length arrays are equal
// word by word compare, dont't need alignment check
bind(Lvector);
// Shift ary1 and ary2 to the end of the arrays, negate limit
add(ary1, limit, ary1);
add(ary2, limit, ary2);
neg(limit, limit);
lduw(ary1, limit, chr1);
bind(Lloop);
lduw(ary2, limit, chr2);
cmp(chr1, chr2);
br(Assembler::notEqual, true, Assembler::pt, Ldone);
delayed()->mov(G0, result); // not equal
inccc(limit, 2*sizeof(jchar));
// annul LDUW if branch is not taken to prevent access past end of array
br(Assembler::notZero, true, Assembler::pt, Lloop);
delayed()->lduw(ary1, limit, chr1); // hoisted
// Caller should set it:
// add(G0, 1, result); // equals
}

View File

@ -2455,6 +2455,11 @@ public:
void inc_counter(address counter_addr, Register Rtmp1, Register Rtmp2);
void inc_counter(int* counter_addr, Register Rtmp1, Register Rtmp2);
// Compare char[] arrays aligned to 4 bytes.
void char_arrays_equals(Register ary1, Register ary2,
Register limit, Register result,
Register chr1, Register chr2, Label& Ldone);
#undef VIRTUAL
};

View File

@ -2171,7 +2171,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
// subtype which we can't check or src is the same array as dst
// but not necessarily exactly of type default_type.
Label known_ok, halt;
jobject2reg(op->expected_type()->encoding(), tmp);
jobject2reg(op->expected_type()->constant_encoding(), tmp);
__ ld_ptr(dst, oopDesc::klass_offset_in_bytes(), tmp2);
if (basic_type != T_OBJECT) {
__ cmp(tmp, tmp2);
@ -2429,7 +2429,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
assert(data->is_BitData(), "need BitData for checkcast");
Register mdo = k_RInfo;
Register data_val = Rtmp1;
jobject2reg(md->encoding(), mdo);
jobject2reg(md->constant_encoding(), mdo);
int mdo_offset_bias = 0;
if (!Assembler::is_simm13(md->byte_offset_of_slot(data, DataLayout::header_offset()) + data->size_in_bytes())) {
@ -2452,7 +2452,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
// patching may screw with our temporaries on sparc,
// so let's do it before loading the class
if (k->is_loaded()) {
jobject2reg(k->encoding(), k_RInfo);
jobject2reg(k->constant_encoding(), k_RInfo);
} else {
jobject2reg_with_patching(k_RInfo, op->info_for_patch());
}
@ -2513,7 +2513,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
// patching may screw with our temporaries on sparc,
// so let's do it before loading the class
if (k->is_loaded()) {
jobject2reg(k->encoding(), k_RInfo);
jobject2reg(k->constant_encoding(), k_RInfo);
} else {
jobject2reg_with_patching(k_RInfo, op->info_for_patch());
}
@ -2717,7 +2717,7 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
assert(op->tmp1()->is_single_cpu(), "tmp1 must be allocated");
Register mdo = op->mdo()->as_register();
Register tmp1 = op->tmp1()->as_register();
jobject2reg(md->encoding(), mdo);
jobject2reg(md->constant_encoding(), mdo);
int mdo_offset_bias = 0;
if (!Assembler::is_simm13(md->byte_offset_of_slot(data, CounterData::count_offset()) +
data->size_in_bytes())) {
@ -2774,7 +2774,7 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
if (receiver == NULL) {
Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)) -
mdo_offset_bias);
jobject2reg(known_klass->encoding(), tmp1);
jobject2reg(known_klass->constant_encoding(), tmp1);
__ st_ptr(tmp1, recv_addr);
Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) -
mdo_offset_bias);

View File

@ -668,7 +668,7 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) {
__ add(obj.result(), offset.result(), addr);
if (type == objectType) { // Write-barrier needed for Object fields.
pre_barrier(obj.result(), false, NULL);
pre_barrier(addr, false, NULL);
}
if (type == objectType)
@ -896,7 +896,7 @@ void LIRGenerator::do_NewTypeArray(NewTypeArray* x) {
LIR_Opr len = length.result();
BasicType elem_type = x->elt_type();
__ oop2reg(ciTypeArrayKlass::make(elem_type)->encoding(), klass_reg);
__ oop2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg);
CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info);
__ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path);

View File

@ -2838,63 +2838,41 @@ enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{
%}
enc_class enc_String_Compare(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result) %{
enc_class enc_String_Compare(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result) %{
Label Ldone, Lloop;
MacroAssembler _masm(&cbuf);
Register str1_reg = reg_to_register_object($str1$$reg);
Register str2_reg = reg_to_register_object($str2$$reg);
Register tmp1_reg = reg_to_register_object($tmp1$$reg);
Register tmp2_reg = reg_to_register_object($tmp2$$reg);
Register cnt1_reg = reg_to_register_object($cnt1$$reg);
Register cnt2_reg = reg_to_register_object($cnt2$$reg);
Register result_reg = reg_to_register_object($result$$reg);
// Get the first character position in both strings
// [8] char array, [12] offset, [16] count
int value_offset = java_lang_String:: value_offset_in_bytes();
int offset_offset = java_lang_String::offset_offset_in_bytes();
int count_offset = java_lang_String:: count_offset_in_bytes();
// load str1 (jchar*) base address into tmp1_reg
__ load_heap_oop(str1_reg, value_offset, tmp1_reg);
__ ld(str1_reg, offset_offset, result_reg);
__ add(tmp1_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp1_reg);
__ ld(str1_reg, count_offset, str1_reg); // hoisted
__ sll(result_reg, exact_log2(sizeof(jchar)), result_reg);
__ load_heap_oop(str2_reg, value_offset, tmp2_reg); // hoisted
__ add(result_reg, tmp1_reg, tmp1_reg);
// load str2 (jchar*) base address into tmp2_reg
// __ ld_ptr(str2_reg, value_offset, tmp2_reg); // hoisted
__ ld(str2_reg, offset_offset, result_reg);
__ add(tmp2_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp2_reg);
__ ld(str2_reg, count_offset, str2_reg); // hoisted
__ sll(result_reg, exact_log2(sizeof(jchar)), result_reg);
__ subcc(str1_reg, str2_reg, O7); // hoisted
__ add(result_reg, tmp2_reg, tmp2_reg);
assert(result_reg != str1_reg &&
result_reg != str2_reg &&
result_reg != cnt1_reg &&
result_reg != cnt2_reg ,
"need different registers");
// Compute the minimum of the string lengths(str1_reg) and the
// difference of the string lengths (stack)
// discard string base pointers, after loading up the lengths
// __ ld(str1_reg, count_offset, str1_reg); // hoisted
// __ ld(str2_reg, count_offset, str2_reg); // hoisted
// See if the lengths are different, and calculate min in str1_reg.
// Stash diff in O7 in case we need it for a tie-breaker.
Label Lskip;
// __ subcc(str1_reg, str2_reg, O7); // hoisted
__ sll(str1_reg, exact_log2(sizeof(jchar)), str1_reg); // scale the limit
__ subcc(cnt1_reg, cnt2_reg, O7);
__ sll(cnt1_reg, exact_log2(sizeof(jchar)), cnt1_reg); // scale the limit
__ br(Assembler::greater, true, Assembler::pt, Lskip);
// str2 is shorter, so use its count:
__ delayed()->sll(str2_reg, exact_log2(sizeof(jchar)), str1_reg); // scale the limit
// cnt2 is shorter, so use its count:
__ delayed()->sll(cnt2_reg, exact_log2(sizeof(jchar)), cnt1_reg); // scale the limit
__ bind(Lskip);
// reallocate str1_reg, str2_reg, result_reg
// reallocate cnt1_reg, cnt2_reg, result_reg
// Note: limit_reg holds the string length pre-scaled by 2
Register limit_reg = str1_reg;
Register chr2_reg = str2_reg;
Register limit_reg = cnt1_reg;
Register chr2_reg = cnt2_reg;
Register chr1_reg = result_reg;
// tmp{12} are the base pointers
// str{12} are the base pointers
// Is the minimum length zero?
__ cmp(limit_reg, (int)(0 * sizeof(jchar))); // use cast to resolve overloading ambiguity
@ -2902,8 +2880,8 @@ enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{
__ delayed()->mov(O7, result_reg); // result is difference in lengths
// Load first characters
__ lduh(tmp1_reg, 0, chr1_reg);
__ lduh(tmp2_reg, 0, chr2_reg);
__ lduh(str1_reg, 0, chr1_reg);
__ lduh(str2_reg, 0, chr2_reg);
// Compare first characters
__ subcc(chr1_reg, chr2_reg, chr1_reg);
@ -2915,7 +2893,7 @@ enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{
// Check after comparing first character to see if strings are equivalent
Label LSkip2;
// Check if the strings start at same location
__ cmp(tmp1_reg, tmp2_reg);
__ cmp(str1_reg, str2_reg);
__ brx(Assembler::notEqual, true, Assembler::pt, LSkip2);
__ delayed()->nop();
@ -2932,23 +2910,23 @@ enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{
__ br(Assembler::equal, true, Assembler::pn, Ldone);
__ delayed()->mov(O7, result_reg); // result is difference in lengths
// Shift tmp1_reg and tmp2_reg to the end of the arrays, negate limit
__ add(tmp1_reg, limit_reg, tmp1_reg);
__ add(tmp2_reg, limit_reg, tmp2_reg);
// Shift str1_reg and str2_reg to the end of the arrays, negate limit
__ add(str1_reg, limit_reg, str1_reg);
__ add(str2_reg, limit_reg, str2_reg);
__ neg(chr1_reg, limit_reg); // limit = -(limit-2)
// Compare the rest of the characters
__ lduh(tmp1_reg, limit_reg, chr1_reg);
__ lduh(str1_reg, limit_reg, chr1_reg);
__ bind(Lloop);
// __ lduh(tmp1_reg, limit_reg, chr1_reg); // hoisted
__ lduh(tmp2_reg, limit_reg, chr2_reg);
// __ lduh(str1_reg, limit_reg, chr1_reg); // hoisted
__ lduh(str2_reg, limit_reg, chr2_reg);
__ subcc(chr1_reg, chr2_reg, chr1_reg);
__ br(Assembler::notZero, false, Assembler::pt, Ldone);
assert(chr1_reg == result_reg, "result must be pre-placed");
__ delayed()->inccc(limit_reg, sizeof(jchar));
// annul LDUH if branch is not taken to prevent access past end of string
__ br(Assembler::notZero, true, Assembler::pt, Lloop);
__ delayed()->lduh(tmp1_reg, limit_reg, chr1_reg); // hoisted
__ delayed()->lduh(str1_reg, limit_reg, chr1_reg); // hoisted
// If strings are equal up to min length, return the length difference.
__ mov(O7, result_reg);
@ -2957,125 +2935,80 @@ enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{
__ bind(Ldone);
%}
enc_class enc_String_Equals(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result) %{
Label Lword, Lword_loop, Lpost_word, Lchar, Lchar_loop, Ldone;
enc_class enc_String_Equals(o0RegP str1, o1RegP str2, g3RegI cnt, notemp_iRegI result) %{
Label Lword_loop, Lpost_word, Lchar, Lchar_loop, Ldone;
MacroAssembler _masm(&cbuf);
Register str1_reg = reg_to_register_object($str1$$reg);
Register str2_reg = reg_to_register_object($str2$$reg);
Register tmp1_reg = reg_to_register_object($tmp1$$reg);
Register tmp2_reg = reg_to_register_object($tmp2$$reg);
Register cnt_reg = reg_to_register_object($cnt$$reg);
Register tmp1_reg = O7;
Register result_reg = reg_to_register_object($result$$reg);
// Get the first character position in both strings
// [8] char array, [12] offset, [16] count
int value_offset = java_lang_String:: value_offset_in_bytes();
int offset_offset = java_lang_String::offset_offset_in_bytes();
int count_offset = java_lang_String:: count_offset_in_bytes();
assert(result_reg != str1_reg &&
result_reg != str2_reg &&
result_reg != cnt_reg &&
result_reg != tmp1_reg ,
"need different registers");
// load str1 (jchar*) base address into tmp1_reg
__ load_heap_oop(Address(str1_reg, value_offset), tmp1_reg);
__ ld(Address(str1_reg, offset_offset), result_reg);
__ add(tmp1_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp1_reg);
__ ld(Address(str1_reg, count_offset), str1_reg); // hoisted
__ sll(result_reg, exact_log2(sizeof(jchar)), result_reg);
__ load_heap_oop(Address(str2_reg, value_offset), tmp2_reg); // hoisted
__ add(result_reg, tmp1_reg, tmp1_reg);
// load str2 (jchar*) base address into tmp2_reg
// __ ld_ptr(Address(str2_reg, value_offset), tmp2_reg); // hoisted
__ ld(Address(str2_reg, offset_offset), result_reg);
__ add(tmp2_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp2_reg);
__ ld(Address(str2_reg, count_offset), str2_reg); // hoisted
__ sll(result_reg, exact_log2(sizeof(jchar)), result_reg);
__ cmp(str1_reg, str2_reg); // hoisted
__ add(result_reg, tmp2_reg, tmp2_reg);
__ sll(str1_reg, exact_log2(sizeof(jchar)), str1_reg);
__ br(Assembler::notEqual, true, Assembler::pt, Ldone);
__ delayed()->mov(G0, result_reg); // not equal
__ br_zero(Assembler::equal, true, Assembler::pn, str1_reg, Ldone);
__ delayed()->add(G0, 1, result_reg); //equals
__ cmp(tmp1_reg, tmp2_reg); //same string ?
__ cmp(str1_reg, str2_reg); //same char[] ?
__ brx(Assembler::equal, true, Assembler::pn, Ldone);
__ delayed()->add(G0, 1, result_reg);
__ br_on_reg_cond(Assembler::rc_z, true, Assembler::pn, cnt_reg, Ldone);
__ delayed()->add(G0, 1, result_reg); // count == 0
//rename registers
Register limit_reg = str1_reg;
Register chr2_reg = str2_reg;
Register limit_reg = cnt_reg;
Register chr1_reg = result_reg;
// tmp{12} are the base pointers
Register chr2_reg = tmp1_reg;
//check for alignment and position the pointers to the ends
__ or3(tmp1_reg, tmp2_reg, chr1_reg);
__ andcc(chr1_reg, 0x3, chr1_reg); // notZero means at least one not 4-byte aligned
__ br(Assembler::notZero, false, Assembler::pn, Lchar);
__ delayed()->nop();
__ or3(str1_reg, str2_reg, chr1_reg);
__ andcc(chr1_reg, 0x3, chr1_reg);
// notZero means at least one not 4-byte aligned.
// We could optimize the case when both arrays are not aligned
// but it is not frequent case and it requires additional checks.
__ br(Assembler::notZero, false, Assembler::pn, Lchar); // char by char compare
__ delayed()->sll(limit_reg, exact_log2(sizeof(jchar)), limit_reg); // set byte count
__ bind(Lword);
__ and3(limit_reg, 0x2, O7); //remember the remainder (either 0 or 2)
__ andn(limit_reg, 0x3, limit_reg);
__ br_zero(Assembler::zero, false, Assembler::pn, limit_reg, Lpost_word);
__ delayed()->nop();
__ add(tmp1_reg, limit_reg, tmp1_reg);
__ add(tmp2_reg, limit_reg, tmp2_reg);
__ neg(limit_reg);
__ lduw(tmp1_reg, limit_reg, chr1_reg);
__ bind(Lword_loop);
__ lduw(tmp2_reg, limit_reg, chr2_reg);
__ cmp(chr1_reg, chr2_reg);
__ br(Assembler::notEqual, true, Assembler::pt, Ldone);
__ delayed()->mov(G0, result_reg);
__ inccc(limit_reg, 2*sizeof(jchar));
// annul LDUW if branch i s not taken to prevent access past end of string
__ br(Assembler::notZero, true, Assembler::pt, Lword_loop); //annul on taken
__ delayed()->lduw(tmp1_reg, limit_reg, chr1_reg); // hoisted
__ bind(Lpost_word);
__ br_zero(Assembler::zero, true, Assembler::pt, O7, Ldone);
__ delayed()->add(G0, 1, result_reg);
__ lduh(tmp1_reg, 0, chr1_reg);
__ lduh(tmp2_reg, 0, chr2_reg);
__ cmp (chr1_reg, chr2_reg);
__ br(Assembler::notEqual, true, Assembler::pt, Ldone);
__ delayed()->mov(G0, result_reg);
// Compare char[] arrays aligned to 4 bytes.
__ char_arrays_equals(str1_reg, str2_reg, limit_reg, result_reg,
chr1_reg, chr2_reg, Ldone);
__ ba(false,Ldone);
__ delayed()->add(G0, 1, result_reg);
// char by char compare
__ bind(Lchar);
__ add(tmp1_reg, limit_reg, tmp1_reg);
__ add(tmp2_reg, limit_reg, tmp2_reg);
__ add(str1_reg, limit_reg, str1_reg);
__ add(str2_reg, limit_reg, str2_reg);
__ neg(limit_reg); //negate count
__ lduh(tmp1_reg, limit_reg, chr1_reg);
__ lduh(str1_reg, limit_reg, chr1_reg);
// Lchar_loop
__ bind(Lchar_loop);
__ lduh(tmp2_reg, limit_reg, chr2_reg);
__ lduh(str2_reg, limit_reg, chr2_reg);
__ cmp(chr1_reg, chr2_reg);
__ br(Assembler::notEqual, true, Assembler::pt, Ldone);
__ delayed()->mov(G0, result_reg); //not equal
__ inccc(limit_reg, sizeof(jchar));
// annul LDUH if branch is not taken to prevent access past end of string
__ br(Assembler::notZero, true, Assembler::pt, Lchar_loop); //annul on taken
__ delayed()->lduh(tmp1_reg, limit_reg, chr1_reg); // hoisted
__ br(Assembler::notZero, true, Assembler::pt, Lchar_loop);
__ delayed()->lduh(str1_reg, limit_reg, chr1_reg); // hoisted
__ add(G0, 1, result_reg); //equal
__ bind(Ldone);
%}
enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result) %{
enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, notemp_iRegI result) %{
Label Lvector, Ldone, Lloop;
MacroAssembler _masm(&cbuf);
Register ary1_reg = reg_to_register_object($ary1$$reg);
Register ary2_reg = reg_to_register_object($ary2$$reg);
Register tmp1_reg = reg_to_register_object($tmp1$$reg);
Register tmp2_reg = reg_to_register_object($tmp2$$reg);
Register tmp2_reg = O7;
Register result_reg = reg_to_register_object($result$$reg);
int length_offset = arrayOopDesc::length_offset_in_bytes();
@ -3101,7 +3034,7 @@ enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, g4RegP tmp2, n
__ br(Assembler::notEqual, true, Assembler::pn, Ldone);
__ delayed()->mov(G0, result_reg); // not equal
__ br_zero(Assembler::zero, true, Assembler::pn, tmp1_reg, Ldone);
__ br_on_reg_cond(Assembler::rc_z, true, Assembler::pn, tmp1_reg, Ldone);
__ delayed()->add(G0, 1, result_reg); // zero-length arrays are equal
// load array addresses
@ -3109,45 +3042,16 @@ enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, g4RegP tmp2, n
__ add(ary2_reg, base_offset, ary2_reg);
// renaming registers
Register chr1_reg = tmp2_reg; // for characters in ary1
Register chr2_reg = result_reg; // for characters in ary2
Register chr1_reg = result_reg; // for characters in ary1
Register chr2_reg = tmp2_reg; // for characters in ary2
Register limit_reg = tmp1_reg; // length
// set byte count
__ sll(limit_reg, exact_log2(sizeof(jchar)), limit_reg);
__ andcc(limit_reg, 0x2, chr1_reg); //trailing character ?
__ br(Assembler::zero, false, Assembler::pt, Lvector);
__ delayed()->nop();
//compare the trailing char
__ sub(limit_reg, sizeof(jchar), limit_reg);
__ lduh(ary1_reg, limit_reg, chr1_reg);
__ lduh(ary2_reg, limit_reg, chr2_reg);
__ cmp(chr1_reg, chr2_reg);
__ br(Assembler::notEqual, true, Assembler::pt, Ldone);
__ delayed()->mov(G0, result_reg); // not equal
// only one char ?
__ br_zero(Assembler::zero, true, Assembler::pn, limit_reg, Ldone);
__ delayed()->add(G0, 1, result_reg); // zero-length arrays are equal
__ bind(Lvector);
// Shift ary1_reg and ary2_reg to the end of the arrays, negate limit
__ add(ary1_reg, limit_reg, ary1_reg);
__ add(ary2_reg, limit_reg, ary2_reg);
__ neg(limit_reg, limit_reg);
__ lduw(ary1_reg, limit_reg, chr1_reg);
__ bind(Lloop);
__ lduw(ary2_reg, limit_reg, chr2_reg);
__ cmp(chr1_reg, chr2_reg);
__ br(Assembler::notEqual, false, Assembler::pt, Ldone);
__ delayed()->mov(G0, result_reg); // not equal
__ inccc(limit_reg, 2*sizeof(jchar));
// annul LDUW if branch is not taken to prevent access past end of string
__ br(Assembler::notZero, true, Assembler::pt, Lloop); //annul on taken
__ delayed()->lduw(ary1_reg, limit_reg, chr1_reg); // hoisted
// Compare char[] arrays aligned to 4 bytes.
__ char_arrays_equals(ary1_reg, ary2_reg, limit_reg, result_reg,
chr1_reg, chr2_reg, Ldone);
__ add(G0, 1, result_reg); // equals
__ bind(Ldone);
@ -9471,33 +9375,33 @@ instruct clear_array(iRegX cnt, iRegP base, iRegX temp, Universe dummy, flagsReg
ins_pipe(long_memory_op);
%}
instruct string_compare(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result,
o7RegI tmp3, flagsReg ccr) %{
match(Set result (StrComp str1 str2));
effect(USE_KILL str1, USE_KILL str2, KILL tmp1, KILL tmp2, KILL ccr, KILL tmp3);
instruct string_compare(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result,
o7RegI tmp, flagsReg ccr) %{
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, KILL tmp);
ins_cost(300);
format %{ "String Compare $str1,$str2 -> $result" %}
ins_encode( enc_String_Compare(str1, str2, tmp1, tmp2, result) );
format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp" %}
ins_encode( enc_String_Compare(str1, str2, cnt1, cnt2, result) );
ins_pipe(long_memory_op);
%}
instruct string_equals(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result,
o7RegI tmp3, flagsReg ccr) %{
match(Set result (StrEquals str1 str2));
effect(USE_KILL str1, USE_KILL str2, KILL tmp1, KILL tmp2, KILL ccr, KILL tmp3);
instruct string_equals(o0RegP str1, o1RegP str2, g3RegI cnt, notemp_iRegI result,
o7RegI tmp, flagsReg ccr) %{
match(Set result (StrEquals (Binary str1 str2) cnt));
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp, KILL ccr);
ins_cost(300);
format %{ "String Equals $str1,$str2 -> $result" %}
ins_encode( enc_String_Equals(str1, str2, tmp1, tmp2, result) );
format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp" %}
ins_encode( enc_String_Equals(str1, str2, cnt, result) );
ins_pipe(long_memory_op);
%}
instruct array_equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result,
flagsReg ccr) %{
instruct array_equals(o0RegP ary1, o1RegP ary2, g3RegI tmp1, notemp_iRegI result,
o7RegI tmp2, flagsReg ccr) %{
match(Set result (AryEq ary1 ary2));
effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL ccr);
ins_cost(300);
format %{ "Array Equals $ary1,$ary2 -> $result" %}
ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result));
format %{ "Array Equals $ary1,$ary2 -> $result // KILL $tmp1,$tmp2" %}
ins_encode( enc_Array_Equals(ary1, ary2, tmp1, result));
ins_pipe(long_memory_op);
%}

View File

@ -8404,6 +8404,319 @@ void MacroAssembler::reinit_heapbase() {
}
#endif // _LP64
// IndexOf substring.
void MacroAssembler::string_indexof(Register str1, Register str2,
Register cnt1, Register cnt2, Register result,
XMMRegister vec, Register tmp) {
assert(UseSSE42Intrinsics, "SSE4.2 is required");
Label RELOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR,
SCAN_SUBSTR, RET_NOT_FOUND, CLEANUP;
push(str1); // string addr
push(str2); // substr addr
push(cnt2); // substr count
jmpb(PREP_FOR_SCAN);
// Substr count saved at sp
// Substr saved at sp+1*wordSize
// String saved at sp+2*wordSize
// Reload substr for rescan
bind(RELOAD_SUBSTR);
movl(cnt2, Address(rsp, 0));
movptr(str2, Address(rsp, wordSize));
// We came here after the beginninig of the substring was
// matched but the rest of it was not so we need to search
// again. Start from the next element after the previous match.
subptr(str1, result); // Restore counter
shrl(str1, 1);
addl(cnt1, str1);
lea(str1, Address(result, 2)); // Reload string
// Load substr
bind(PREP_FOR_SCAN);
movdqu(vec, Address(str2, 0));
addl(cnt1, 8); // prime the loop
subptr(str1, 16);
// Scan string for substr in 16-byte vectors
bind(SCAN_TO_SUBSTR);
subl(cnt1, 8);
addptr(str1, 16);
// pcmpestri
// inputs:
// xmm - substring
// rax - substring length (elements count)
// mem - scaned string
// rdx - string length (elements count)
// 0xd - mode: 1100 (substring search) + 01 (unsigned shorts)
// outputs:
// rcx - matched index in string
assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri");
pcmpestri(vec, Address(str1, 0), 0x0d);
jcc(Assembler::above, SCAN_TO_SUBSTR); // CF == 0 && ZF == 0
jccb(Assembler::aboveEqual, RET_NOT_FOUND); // CF == 0
// Fallthrough: found a potential substr
// Make sure string is still long enough
subl(cnt1, tmp);
cmpl(cnt1, cnt2);
jccb(Assembler::negative, RET_NOT_FOUND);
// Compute start addr of substr
lea(str1, Address(str1, tmp, Address::times_2));
movptr(result, str1); // save
// Compare potential substr
addl(cnt1, 8); // prime the loop
addl(cnt2, 8);
subptr(str1, 16);
subptr(str2, 16);
// Scan 16-byte vectors of string and substr
bind(SCAN_SUBSTR);
subl(cnt1, 8);
subl(cnt2, 8);
addptr(str1, 16);
addptr(str2, 16);
movdqu(vec, Address(str2, 0));
pcmpestri(vec, Address(str1, 0), 0x0d);
jcc(Assembler::noOverflow, RELOAD_SUBSTR); // OF == 0
jcc(Assembler::positive, SCAN_SUBSTR); // SF == 0
// Compute substr offset
subptr(result, Address(rsp, 2*wordSize));
shrl(result, 1); // index
jmpb(CLEANUP);
bind(RET_NOT_FOUND);
movl(result, -1);
bind(CLEANUP);
addptr(rsp, 3*wordSize);
}
// Compare strings.
void MacroAssembler::string_compare(Register str1, Register str2,
Register cnt1, Register cnt2, Register result,
XMMRegister vec1, XMMRegister vec2) {
Label LENGTH_DIFF_LABEL, POP_LABEL, DONE_LABEL, WHILE_HEAD_LABEL;
// Compute the minimum of the string lengths and the
// difference of the string lengths (stack).
// Do the conditional move stuff
movl(result, cnt1);
subl(cnt1, cnt2);
push(cnt1);
if (VM_Version::supports_cmov()) {
cmovl(Assembler::lessEqual, cnt2, result);
} else {
Label GT_LABEL;
jccb(Assembler::greater, GT_LABEL);
movl(cnt2, result);
bind(GT_LABEL);
}
// Is the minimum length zero?
testl(cnt2, cnt2);
jcc(Assembler::zero, LENGTH_DIFF_LABEL);
// Load first characters
load_unsigned_short(result, Address(str1, 0));
load_unsigned_short(cnt1, Address(str2, 0));
// Compare first characters
subl(result, cnt1);
jcc(Assembler::notZero, POP_LABEL);
decrementl(cnt2);
jcc(Assembler::zero, LENGTH_DIFF_LABEL);
{
// Check after comparing first character to see if strings are equivalent
Label LSkip2;
// Check if the strings start at same location
cmpptr(str1, str2);
jccb(Assembler::notEqual, LSkip2);
// Check if the length difference is zero (from stack)
cmpl(Address(rsp, 0), 0x0);
jcc(Assembler::equal, LENGTH_DIFF_LABEL);
// Strings might not be equivalent
bind(LSkip2);
}
// Advance to next character
addptr(str1, 2);
addptr(str2, 2);
if (UseSSE42Intrinsics) {
// With SSE4.2, use double quad vector compare
Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL;
// Setup to compare 16-byte vectors
movl(cnt1, cnt2);
andl(cnt2, 0xfffffff8); // cnt2 holds the vector count
andl(cnt1, 0x00000007); // cnt1 holds the tail count
testl(cnt2, cnt2);
jccb(Assembler::zero, COMPARE_TAIL);
lea(str2, Address(str2, cnt2, Address::times_2));
lea(str1, Address(str1, cnt2, Address::times_2));
negptr(cnt2);
bind(COMPARE_VECTORS);
movdqu(vec1, Address(str1, cnt2, Address::times_2));
movdqu(vec2, Address(str2, cnt2, Address::times_2));
pxor(vec1, vec2);
ptest(vec1, vec1);
jccb(Assembler::notZero, VECTOR_NOT_EQUAL);
addptr(cnt2, 8);
jcc(Assembler::notZero, COMPARE_VECTORS);
jmpb(COMPARE_TAIL);
// Mismatched characters in the vectors
bind(VECTOR_NOT_EQUAL);
lea(str1, Address(str1, cnt2, Address::times_2));
lea(str2, Address(str2, cnt2, Address::times_2));
movl(cnt1, 8);
// Compare tail (< 8 chars), or rescan last vectors to
// find 1st mismatched characters
bind(COMPARE_TAIL);
testl(cnt1, cnt1);
jccb(Assembler::zero, LENGTH_DIFF_LABEL);
movl(cnt2, cnt1);
// Fallthru to tail compare
}
// Shift str2 and str1 to the end of the arrays, negate min
lea(str1, Address(str1, cnt2, Address::times_2, 0));
lea(str2, Address(str2, cnt2, Address::times_2, 0));
negptr(cnt2);
// Compare the rest of the characters
bind(WHILE_HEAD_LABEL);
load_unsigned_short(result, Address(str1, cnt2, Address::times_2, 0));
load_unsigned_short(cnt1, Address(str2, cnt2, Address::times_2, 0));
subl(result, cnt1);
jccb(Assembler::notZero, POP_LABEL);
increment(cnt2);
jcc(Assembler::notZero, WHILE_HEAD_LABEL);
// Strings are equal up to min length. Return the length difference.
bind(LENGTH_DIFF_LABEL);
pop(result);
jmpb(DONE_LABEL);
// Discard the stored length difference
bind(POP_LABEL);
addptr(rsp, wordSize);
// That's it
bind(DONE_LABEL);
}
// Compare char[] arrays aligned to 4 bytes or substrings.
void MacroAssembler::char_arrays_equals(bool is_array_equ, Register ary1, Register ary2,
Register limit, Register result, Register chr,
XMMRegister vec1, XMMRegister vec2) {
Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR;
int length_offset = arrayOopDesc::length_offset_in_bytes();
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
// Check the input args
cmpptr(ary1, ary2);
jcc(Assembler::equal, TRUE_LABEL);
if (is_array_equ) {
// Need additional checks for arrays_equals.
andptr(ary1, ary2);
jcc(Assembler::zero, FALSE_LABEL); // One pointer is NULL
// Check the lengths
movl(limit, Address(ary1, length_offset));
cmpl(limit, Address(ary2, length_offset));
jcc(Assembler::notEqual, FALSE_LABEL);
}
// count == 0
testl(limit, limit);
jcc(Assembler::zero, TRUE_LABEL);
if (is_array_equ) {
// Load array address
lea(ary1, Address(ary1, base_offset));
lea(ary2, Address(ary2, base_offset));
}
shll(limit, 1); // byte count != 0
movl(result, limit); // copy
if (UseSSE42Intrinsics) {
// With SSE4.2, use double quad vector compare
Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
// Compare 16-byte vectors
andl(result, 0x0000000e); // tail count (in bytes)
andl(limit, 0xfffffff0); // vector count (in bytes)
jccb(Assembler::zero, COMPARE_TAIL);
lea(ary1, Address(ary1, limit, Address::times_1));
lea(ary2, Address(ary2, limit, Address::times_1));
negptr(limit);
bind(COMPARE_WIDE_VECTORS);
movdqu(vec1, Address(ary1, limit, Address::times_1));
movdqu(vec2, Address(ary2, limit, Address::times_1));
pxor(vec1, vec2);
ptest(vec1, vec1);
jccb(Assembler::notZero, FALSE_LABEL);
addptr(limit, 16);
jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
bind(COMPARE_TAIL); // limit is zero
movl(limit, result);
// Fallthru to tail compare
}
// Compare 4-byte vectors
andl(limit, 0xfffffffc); // vector count (in bytes)
jccb(Assembler::zero, COMPARE_CHAR);
lea(ary1, Address(ary1, limit, Address::times_1));
lea(ary2, Address(ary2, limit, Address::times_1));
negptr(limit);
bind(COMPARE_VECTORS);
movl(chr, Address(ary1, limit, Address::times_1));
cmpl(chr, Address(ary2, limit, Address::times_1));
jccb(Assembler::notEqual, FALSE_LABEL);
addptr(limit, 4);
jcc(Assembler::notZero, COMPARE_VECTORS);
// Compare trailing char (final 2 bytes), if any
bind(COMPARE_CHAR);
testl(result, 0x2); // tail char
jccb(Assembler::zero, TRUE_LABEL);
load_unsigned_short(chr, Address(ary1, 0));
load_unsigned_short(limit, Address(ary2, 0));
cmpl(chr, limit);
jccb(Assembler::notEqual, FALSE_LABEL);
bind(TRUE_LABEL);
movl(result, 1); // return true
jmpb(DONE);
bind(FALSE_LABEL);
xorl(result, result); // return false
// That's it
bind(DONE);
}
Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) {
switch (cond) {
// Note some conditions are synonyms for others

View File

@ -2206,6 +2206,20 @@ public:
void movl2ptr(Register dst, Address src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(movl(dst, src)); }
void movl2ptr(Register dst, Register src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(if (dst != src) movl(dst, src)); }
// IndexOf strings.
void string_indexof(Register str1, Register str2,
Register cnt1, Register cnt2, Register result,
XMMRegister vec, Register tmp);
// Compare strings.
void string_compare(Register str1, Register str2,
Register cnt1, Register cnt2, Register result,
XMMRegister vec1, XMMRegister vec2);
// Compare char[] arrays.
void char_arrays_equals(bool is_array_equ, Register ary1, Register ary2,
Register limit, Register result, Register chr,
XMMRegister vec1, XMMRegister vec2);
#undef VIRTUAL

View File

@ -1638,7 +1638,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
jobject2reg_with_patching(k_RInfo, op->info_for_patch());
} else {
#ifdef _LP64
__ movoop(k_RInfo, k->encoding());
__ movoop(k_RInfo, k->constant_encoding());
#else
k_RInfo = noreg;
#endif // _LP64
@ -1661,7 +1661,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
assert(data != NULL, "need data for checkcast");
assert(data->is_BitData(), "need BitData for checkcast");
Register mdo = klass_RInfo;
__ movoop(mdo, md->encoding());
__ movoop(mdo, md->constant_encoding());
Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::header_offset()));
int header_bits = DataLayout::flag_mask_to_header_mask(BitData::null_seen_byte_constant());
__ orl(data_addr, header_bits);
@ -1679,7 +1679,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
#ifdef _LP64
__ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes()));
#else
__ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->encoding());
__ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->constant_encoding());
#endif // _LP64
} else {
__ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes()));
@ -1696,7 +1696,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
#ifdef _LP64
__ cmpptr(k_RInfo, Address(klass_RInfo, k->super_check_offset()));
#else
__ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->encoding());
__ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->constant_encoding());
#endif // _LP64
if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() != k->super_check_offset()) {
__ jcc(Assembler::notEqual, *stub->entry());
@ -1707,7 +1707,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
#ifdef _LP64
__ cmpptr(klass_RInfo, k_RInfo);
#else
__ cmpoop(klass_RInfo, k->encoding());
__ cmpoop(klass_RInfo, k->constant_encoding());
#endif // _LP64
__ jcc(Assembler::equal, done);
@ -1715,7 +1715,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
#ifdef _LP64
__ push(k_RInfo);
#else
__ pushoop(k->encoding());
__ pushoop(k->constant_encoding());
#endif // _LP64
__ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
__ pop(klass_RInfo);
@ -1763,7 +1763,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
if (!k->is_loaded()) {
jobject2reg_with_patching(k_RInfo, op->info_for_patch());
} else {
LP64_ONLY(__ movoop(k_RInfo, k->encoding()));
LP64_ONLY(__ movoop(k_RInfo, k->constant_encoding()));
}
assert(obj != k_RInfo, "must be different");
@ -1774,7 +1774,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
// get object class
// not a safepoint as obj null check happens earlier
if (LP64_ONLY(false &&) k->is_loaded()) {
NOT_LP64(__ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->encoding()));
NOT_LP64(__ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->constant_encoding()));
k_RInfo = noreg;
} else {
__ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes()));
@ -1791,14 +1791,14 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
#ifndef _LP64
if (k->is_loaded()) {
// See if we get an immediate positive hit
__ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->encoding());
__ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->constant_encoding());
__ jcc(Assembler::equal, one);
if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() == k->super_check_offset()) {
// check for self
__ cmpoop(klass_RInfo, k->encoding());
__ cmpoop(klass_RInfo, k->constant_encoding());
__ jcc(Assembler::equal, one);
__ push(klass_RInfo);
__ pushoop(k->encoding());
__ pushoop(k->constant_encoding());
__ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
__ pop(klass_RInfo);
__ pop(dst);
@ -3112,7 +3112,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
// subtype which we can't check or src is the same array as dst
// but not necessarily exactly of type default_type.
Label known_ok, halt;
__ movoop(tmp, default_type->encoding());
__ movoop(tmp, default_type->constant_encoding());
if (basic_type != T_OBJECT) {
__ cmpptr(tmp, dst_klass_addr);
__ jcc(Assembler::notEqual, halt);
@ -3200,7 +3200,7 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
assert(data->is_CounterData(), "need CounterData for calls");
assert(op->mdo()->is_single_cpu(), "mdo must be allocated");
Register mdo = op->mdo()->as_register();
__ movoop(mdo, md->encoding());
__ 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);
@ -3240,7 +3240,7 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
ciKlass* receiver = vc_data->receiver(i);
if (receiver == NULL) {
Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)));
__ movoop(recv_addr, known_klass->encoding());
__ movoop(recv_addr, known_klass->constant_encoding());
Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)));
__ addl(data_addr, DataLayout::counter_increment);
return;

View File

@ -994,7 +994,7 @@ void LIRGenerator::do_NewTypeArray(NewTypeArray* x) {
LIR_Opr len = length.result();
BasicType elem_type = x->elt_type();
__ oop2reg(ciTypeArrayKlass::make(elem_type)->encoding(), klass_reg);
__ oop2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg);
CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info);
__ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path);

View File

@ -379,7 +379,7 @@ void emit_d32_reloc(CodeBuffer &cbuf, int d32, RelocationHolder const& rspec,
int format) {
#ifdef ASSERT
if (rspec.reloc()->type() == relocInfo::oop_type && d32 != 0 && d32 != (int)Universe::non_oop_word()) {
assert(oop(d32)->is_oop() && oop(d32)->is_perm(), "cannot embed non-perm oops in code");
assert(oop(d32)->is_oop() && (ScavengeRootsInCode || !oop(d32)->is_scavengable()), "cannot embed scavengable oops in code");
}
#endif
cbuf.relocate(cbuf.inst_mark(), rspec, format);
@ -3701,458 +3701,6 @@ encode %{
}
%}
enc_class enc_String_Compare(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2,
eAXRegI tmp3, eBXRegI tmp4, eCXRegI result) %{
Label ECX_GOOD_LABEL, LENGTH_DIFF_LABEL,
POP_LABEL, DONE_LABEL, CONT_LABEL,
WHILE_HEAD_LABEL;
MacroAssembler masm(&cbuf);
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg);
// Get the first character position in both strings
// [8] char array, [12] offset, [16] count
int value_offset = java_lang_String::value_offset_in_bytes();
int offset_offset = java_lang_String::offset_offset_in_bytes();
int count_offset = java_lang_String::count_offset_in_bytes();
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
masm.movptr(rax, Address(rsi, value_offset));
masm.movl(rcx, Address(rsi, offset_offset));
masm.lea(rax, Address(rax, rcx, Address::times_2, base_offset));
masm.movptr(rbx, Address(rdi, value_offset));
masm.movl(rcx, Address(rdi, offset_offset));
masm.lea(rbx, Address(rbx, rcx, Address::times_2, base_offset));
// Compute the minimum of the string lengths(rsi) and the
// difference of the string lengths (stack)
if (VM_Version::supports_cmov()) {
masm.movl(rdi, Address(rdi, count_offset));
masm.movl(rsi, Address(rsi, count_offset));
masm.movl(rcx, rdi);
masm.subl(rdi, rsi);
masm.push(rdi);
masm.cmovl(Assembler::lessEqual, rsi, rcx);
} else {
masm.movl(rdi, Address(rdi, count_offset));
masm.movl(rcx, Address(rsi, count_offset));
masm.movl(rsi, rdi);
masm.subl(rdi, rcx);
masm.push(rdi);
masm.jccb(Assembler::lessEqual, ECX_GOOD_LABEL);
masm.movl(rsi, rcx);
// rsi holds min, rcx is unused
}
// Is the minimum length zero?
masm.bind(ECX_GOOD_LABEL);
masm.testl(rsi, rsi);
masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL);
// Load first characters
masm.load_unsigned_short(rcx, Address(rbx, 0));
masm.load_unsigned_short(rdi, Address(rax, 0));
// Compare first characters
masm.subl(rcx, rdi);
masm.jcc(Assembler::notZero, POP_LABEL);
masm.decrementl(rsi);
masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL);
{
// Check after comparing first character to see if strings are equivalent
Label LSkip2;
// Check if the strings start at same location
masm.cmpptr(rbx,rax);
masm.jccb(Assembler::notEqual, LSkip2);
// Check if the length difference is zero (from stack)
masm.cmpl(Address(rsp, 0), 0x0);
masm.jcc(Assembler::equal, LENGTH_DIFF_LABEL);
// Strings might not be equivalent
masm.bind(LSkip2);
}
// Advance to next character
masm.addptr(rax, 2);
masm.addptr(rbx, 2);
if (UseSSE42Intrinsics) {
// With SSE4.2, use double quad vector compare
Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL;
// Setup to compare 16-byte vectors
masm.movl(rdi, rsi);
masm.andl(rsi, 0xfffffff8); // rsi holds the vector count
masm.andl(rdi, 0x00000007); // rdi holds the tail count
masm.testl(rsi, rsi);
masm.jccb(Assembler::zero, COMPARE_TAIL);
masm.lea(rax, Address(rax, rsi, Address::times_2));
masm.lea(rbx, Address(rbx, rsi, Address::times_2));
masm.negl(rsi);
masm.bind(COMPARE_VECTORS);
masm.movdqu(tmp1Reg, Address(rax, rsi, Address::times_2));
masm.movdqu(tmp2Reg, Address(rbx, rsi, Address::times_2));
masm.pxor(tmp1Reg, tmp2Reg);
masm.ptest(tmp1Reg, tmp1Reg);
masm.jccb(Assembler::notZero, VECTOR_NOT_EQUAL);
masm.addl(rsi, 8);
masm.jcc(Assembler::notZero, COMPARE_VECTORS);
masm.jmpb(COMPARE_TAIL);
// Mismatched characters in the vectors
masm.bind(VECTOR_NOT_EQUAL);
masm.lea(rax, Address(rax, rsi, Address::times_2));
masm.lea(rbx, Address(rbx, rsi, Address::times_2));
masm.movl(rdi, 8);
// Compare tail (< 8 chars), or rescan last vectors to
// find 1st mismatched characters
masm.bind(COMPARE_TAIL);
masm.testl(rdi, rdi);
masm.jccb(Assembler::zero, LENGTH_DIFF_LABEL);
masm.movl(rsi, rdi);
// Fallthru to tail compare
}
//Shift rax, and rbx, to the end of the arrays, negate min
masm.lea(rax, Address(rax, rsi, Address::times_2, 0));
masm.lea(rbx, Address(rbx, rsi, Address::times_2, 0));
masm.negl(rsi);
// Compare the rest of the characters
masm.bind(WHILE_HEAD_LABEL);
masm.load_unsigned_short(rcx, Address(rbx, rsi, Address::times_2, 0));
masm.load_unsigned_short(rdi, Address(rax, rsi, Address::times_2, 0));
masm.subl(rcx, rdi);
masm.jccb(Assembler::notZero, POP_LABEL);
masm.incrementl(rsi);
masm.jcc(Assembler::notZero, WHILE_HEAD_LABEL);
// Strings are equal up to min length. Return the length difference.
masm.bind(LENGTH_DIFF_LABEL);
masm.pop(rcx);
masm.jmpb(DONE_LABEL);
// Discard the stored length difference
masm.bind(POP_LABEL);
masm.addptr(rsp, 4);
// That's it
masm.bind(DONE_LABEL);
%}
enc_class enc_String_Equals(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2,
eBXRegI tmp3, eCXRegI tmp4, eAXRegI result) %{
Label RET_TRUE, RET_FALSE, DONE, COMPARE_VECTORS, COMPARE_CHAR;
MacroAssembler masm(&cbuf);
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg);
int value_offset = java_lang_String::value_offset_in_bytes();
int offset_offset = java_lang_String::offset_offset_in_bytes();
int count_offset = java_lang_String::count_offset_in_bytes();
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
// does source == target string?
masm.cmpptr(rdi, rsi);
masm.jcc(Assembler::equal, RET_TRUE);
// get and compare counts
masm.movl(rcx, Address(rdi, count_offset));
masm.movl(rax, Address(rsi, count_offset));
masm.cmpl(rcx, rax);
masm.jcc(Assembler::notEqual, RET_FALSE);
masm.testl(rax, rax);
masm.jcc(Assembler::zero, RET_TRUE);
// get source string offset and value
masm.movptr(rbx, Address(rsi, value_offset));
masm.movl(rax, Address(rsi, offset_offset));
masm.leal(rsi, Address(rbx, rax, Address::times_2, base_offset));
// get compare string offset and value
masm.movptr(rbx, Address(rdi, value_offset));
masm.movl(rax, Address(rdi, offset_offset));
masm.leal(rdi, Address(rbx, rax, Address::times_2, base_offset));
// Set byte count
masm.shll(rcx, 1);
masm.movl(rax, rcx);
if (UseSSE42Intrinsics) {
// With SSE4.2, use double quad vector compare
Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
// Compare 16-byte vectors
masm.andl(rcx, 0xfffffff0); // vector count (in bytes)
masm.andl(rax, 0x0000000e); // tail count (in bytes)
masm.testl(rcx, rcx);
masm.jccb(Assembler::zero, COMPARE_TAIL);
masm.lea(rdi, Address(rdi, rcx, Address::times_1));
masm.lea(rsi, Address(rsi, rcx, Address::times_1));
masm.negl(rcx);
masm.bind(COMPARE_WIDE_VECTORS);
masm.movdqu(tmp1Reg, Address(rdi, rcx, Address::times_1));
masm.movdqu(tmp2Reg, Address(rsi, rcx, Address::times_1));
masm.pxor(tmp1Reg, tmp2Reg);
masm.ptest(tmp1Reg, tmp1Reg);
masm.jccb(Assembler::notZero, RET_FALSE);
masm.addl(rcx, 16);
masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
masm.bind(COMPARE_TAIL);
masm.movl(rcx, rax);
// Fallthru to tail compare
}
// Compare 4-byte vectors
masm.andl(rcx, 0xfffffffc); // vector count (in bytes)
masm.andl(rax, 0x00000002); // tail char (in bytes)
masm.testl(rcx, rcx);
masm.jccb(Assembler::zero, COMPARE_CHAR);
masm.lea(rdi, Address(rdi, rcx, Address::times_1));
masm.lea(rsi, Address(rsi, rcx, Address::times_1));
masm.negl(rcx);
masm.bind(COMPARE_VECTORS);
masm.movl(rbx, Address(rdi, rcx, Address::times_1));
masm.cmpl(rbx, Address(rsi, rcx, Address::times_1));
masm.jccb(Assembler::notEqual, RET_FALSE);
masm.addl(rcx, 4);
masm.jcc(Assembler::notZero, COMPARE_VECTORS);
// Compare trailing char (final 2 bytes), if any
masm.bind(COMPARE_CHAR);
masm.testl(rax, rax);
masm.jccb(Assembler::zero, RET_TRUE);
masm.load_unsigned_short(rbx, Address(rdi, 0));
masm.load_unsigned_short(rcx, Address(rsi, 0));
masm.cmpl(rbx, rcx);
masm.jccb(Assembler::notEqual, RET_FALSE);
masm.bind(RET_TRUE);
masm.movl(rax, 1); // return true
masm.jmpb(DONE);
masm.bind(RET_FALSE);
masm.xorl(rax, rax); // return false
masm.bind(DONE);
%}
enc_class enc_String_IndexOf(eSIRegP str1, eDIRegP str2, regXD tmp1, eAXRegI tmp2,
eCXRegI tmp3, eDXRegI tmp4, eBXRegI result) %{
// SSE4.2 version
Label LOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR,
SCAN_SUBSTR, RET_NEG_ONE, RET_NOT_FOUND, CLEANUP, DONE;
MacroAssembler masm(&cbuf);
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
// Get the first character position in both strings
// [8] char array, [12] offset, [16] count
int value_offset = java_lang_String::value_offset_in_bytes();
int offset_offset = java_lang_String::offset_offset_in_bytes();
int count_offset = java_lang_String::count_offset_in_bytes();
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
// Get counts for string and substr
masm.movl(rdx, Address(rsi, count_offset));
masm.movl(rax, Address(rdi, count_offset));
// Check for substr count > string count
masm.cmpl(rax, rdx);
masm.jcc(Assembler::greater, RET_NEG_ONE);
// Start the indexOf operation
// Get start addr of string
masm.movptr(rbx, Address(rsi, value_offset));
masm.movl(rcx, Address(rsi, offset_offset));
masm.lea(rsi, Address(rbx, rcx, Address::times_2, base_offset));
masm.push(rsi);
// Get start addr of substr
masm.movptr(rbx, Address(rdi, value_offset));
masm.movl(rcx, Address(rdi, offset_offset));
masm.lea(rdi, Address(rbx, rcx, Address::times_2, base_offset));
masm.push(rdi);
masm.push(rax);
masm.jmpb(PREP_FOR_SCAN);
// Substr count saved at sp
// Substr saved at sp+4
// String saved at sp+8
// Prep to load substr for scan
masm.bind(LOAD_SUBSTR);
masm.movptr(rdi, Address(rsp, 4));
masm.movl(rax, Address(rsp, 0));
// Load substr
masm.bind(PREP_FOR_SCAN);
masm.movdqu(tmp1Reg, Address(rdi, 0));
masm.addl(rdx, 8); // prime the loop
masm.subptr(rsi, 16);
// Scan string for substr in 16-byte vectors
masm.bind(SCAN_TO_SUBSTR);
masm.subl(rdx, 8);
masm.addptr(rsi, 16);
masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d);
masm.jcc(Assembler::above, SCAN_TO_SUBSTR); // CF == 0 && ZF == 0
masm.jccb(Assembler::aboveEqual, RET_NOT_FOUND); // CF == 0
// Fallthru: found a potential substr
// Make sure string is still long enough
masm.subl(rdx, rcx);
masm.cmpl(rdx, rax);
masm.jccb(Assembler::negative, RET_NOT_FOUND);
// Compute start addr of substr
masm.lea(rsi, Address(rsi, rcx, Address::times_2));
masm.movptr(rbx, rsi);
// Compare potential substr
masm.addl(rdx, 8); // prime the loop
masm.addl(rax, 8);
masm.subptr(rsi, 16);
masm.subptr(rdi, 16);
// Scan 16-byte vectors of string and substr
masm.bind(SCAN_SUBSTR);
masm.subl(rax, 8);
masm.subl(rdx, 8);
masm.addptr(rsi, 16);
masm.addptr(rdi, 16);
masm.movdqu(tmp1Reg, Address(rdi, 0));
masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d);
masm.jcc(Assembler::noOverflow, LOAD_SUBSTR); // OF == 0
masm.jcc(Assembler::positive, SCAN_SUBSTR); // SF == 0
// Compute substr offset
masm.movptr(rsi, Address(rsp, 8));
masm.subptr(rbx, rsi);
masm.shrl(rbx, 1);
masm.jmpb(CLEANUP);
masm.bind(RET_NEG_ONE);
masm.movl(rbx, -1);
masm.jmpb(DONE);
masm.bind(RET_NOT_FOUND);
masm.movl(rbx, -1);
masm.bind(CLEANUP);
masm.addptr(rsp, 12);
masm.bind(DONE);
%}
enc_class enc_Array_Equals(eDIRegP ary1, eSIRegP ary2, regXD tmp1, regXD tmp2,
eBXRegI tmp3, eDXRegI tmp4, eAXRegI result) %{
Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR;
MacroAssembler masm(&cbuf);
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg);
Register ary1Reg = as_Register($ary1$$reg);
Register ary2Reg = as_Register($ary2$$reg);
Register tmp3Reg = as_Register($tmp3$$reg);
Register tmp4Reg = as_Register($tmp4$$reg);
Register resultReg = as_Register($result$$reg);
int length_offset = arrayOopDesc::length_offset_in_bytes();
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
// Check the input args
masm.cmpptr(ary1Reg, ary2Reg);
masm.jcc(Assembler::equal, TRUE_LABEL);
masm.testptr(ary1Reg, ary1Reg);
masm.jcc(Assembler::zero, FALSE_LABEL);
masm.testptr(ary2Reg, ary2Reg);
masm.jcc(Assembler::zero, FALSE_LABEL);
// Check the lengths
masm.movl(tmp4Reg, Address(ary1Reg, length_offset));
masm.movl(resultReg, Address(ary2Reg, length_offset));
masm.cmpl(tmp4Reg, resultReg);
masm.jcc(Assembler::notEqual, FALSE_LABEL);
masm.testl(resultReg, resultReg);
masm.jcc(Assembler::zero, TRUE_LABEL);
// Load array addrs
masm.lea(ary1Reg, Address(ary1Reg, base_offset));
masm.lea(ary2Reg, Address(ary2Reg, base_offset));
// Set byte count
masm.shll(tmp4Reg, 1);
masm.movl(resultReg, tmp4Reg);
if (UseSSE42Intrinsics) {
// With SSE4.2, use double quad vector compare
Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
// Compare 16-byte vectors
masm.andl(tmp4Reg, 0xfffffff0); // vector count (in bytes)
masm.andl(resultReg, 0x0000000e); // tail count (in bytes)
masm.testl(tmp4Reg, tmp4Reg);
masm.jccb(Assembler::zero, COMPARE_TAIL);
masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
masm.negl(tmp4Reg);
masm.bind(COMPARE_WIDE_VECTORS);
masm.movdqu(tmp1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
masm.movdqu(tmp2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
masm.pxor(tmp1Reg, tmp2Reg);
masm.ptest(tmp1Reg, tmp1Reg);
masm.jccb(Assembler::notZero, FALSE_LABEL);
masm.addl(tmp4Reg, 16);
masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
masm.bind(COMPARE_TAIL);
masm.movl(tmp4Reg, resultReg);
// Fallthru to tail compare
}
// Compare 4-byte vectors
masm.andl(tmp4Reg, 0xfffffffc); // vector count (in bytes)
masm.andl(resultReg, 0x00000002); // tail char (in bytes)
masm.testl(tmp4Reg, tmp4Reg);
masm.jccb(Assembler::zero, COMPARE_CHAR);
masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
masm.negl(tmp4Reg);
masm.bind(COMPARE_VECTORS);
masm.movl(tmp3Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
masm.cmpl(tmp3Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
masm.jccb(Assembler::notEqual, FALSE_LABEL);
masm.addl(tmp4Reg, 4);
masm.jcc(Assembler::notZero, COMPARE_VECTORS);
// Compare trailing char (final 2 bytes), if any
masm.bind(COMPARE_CHAR);
masm.testl(resultReg, resultReg);
masm.jccb(Assembler::zero, TRUE_LABEL);
masm.load_unsigned_short(tmp3Reg, Address(ary1Reg, 0));
masm.load_unsigned_short(tmp4Reg, Address(ary2Reg, 0));
masm.cmpl(tmp3Reg, tmp4Reg);
masm.jccb(Assembler::notEqual, FALSE_LABEL);
masm.bind(TRUE_LABEL);
masm.movl(resultReg, 1); // return true
masm.jmpb(DONE);
masm.bind(FALSE_LABEL);
masm.xorl(resultReg, resultReg); // return false
// That's it
masm.bind(DONE);
%}
enc_class enc_pop_rdx() %{
emit_opcode(cbuf,0x5A);
@ -12718,48 +12266,64 @@ instruct rep_stos(eCXRegI cnt, eDIRegP base, eAXRegI zero, Universe dummy, eFlag
ins_pipe( pipe_slow );
%}
instruct string_compare(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2,
eAXRegI tmp3, eBXRegI tmp4, eCXRegI result, eFlagsReg cr) %{
match(Set result (StrComp str1 str2));
effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr);
//ins_cost(300);
instruct string_compare(eDIRegP str1, eCXRegI cnt1, eSIRegP str2, eBXRegI cnt2,
eAXRegI result, regXD tmp1, regXD tmp2, eFlagsReg cr) %{
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
format %{ "String Compare $str1,$str2 -> $result // KILL EAX, EBX" %}
ins_encode( enc_String_Compare(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1, $tmp2" %}
ins_encode %{
__ string_compare($str1$$Register, $str2$$Register,
$cnt1$$Register, $cnt2$$Register, $result$$Register,
$tmp1$$XMMRegister, $tmp2$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
// fast string equals
instruct string_equals(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2,
eBXRegI tmp3, eCXRegI tmp4, eAXRegI result, eFlagsReg cr) %{
match(Set result (StrEquals str1 str2));
effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr);
instruct string_equals(eDIRegP str1, eSIRegP str2, eCXRegI cnt, eAXRegI result,
regXD tmp1, regXD tmp2, eBXRegI tmp3, eFlagsReg cr) %{
match(Set result (StrEquals (Binary str1 str2) cnt));
effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp3, KILL cr);
format %{ "String Equals $str1,$str2 -> $result // KILL EBX, ECX" %}
ins_encode( enc_String_Equals(tmp1, tmp2, str1, str2, tmp3, tmp4, result) );
format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp1, $tmp2, $tmp3" %}
ins_encode %{
__ char_arrays_equals(false, $str1$$Register, $str2$$Register,
$cnt$$Register, $result$$Register, $tmp3$$Register,
$tmp1$$XMMRegister, $tmp2$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
instruct string_indexof(eSIRegP str1, eDIRegP str2, regXD tmp1, eAXRegI tmp2,
eCXRegI tmp3, eDXRegI tmp4, eBXRegI result, eFlagsReg cr) %{
instruct string_indexof(eDIRegP str1, eDXRegI cnt1, eSIRegP str2, eAXRegI cnt2,
eBXRegI result, regXD tmp1, eCXRegI tmp2, eFlagsReg cr) %{
predicate(UseSSE42Intrinsics);
match(Set result (StrIndexOf str1 str2));
effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, KILL tmp2, KILL tmp3, KILL tmp4, KILL cr);
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)));
effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL tmp2, KILL cr);
format %{ "String IndexOf $str1,$str2 -> $result // KILL EAX, ECX, EDX" %}
ins_encode( enc_String_IndexOf(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp2, $tmp1" %}
ins_encode %{
__ string_indexof($str1$$Register, $str2$$Register,
$cnt1$$Register, $cnt2$$Register, $result$$Register,
$tmp1$$XMMRegister, $tmp2$$Register);
%}
ins_pipe( pipe_slow );
%}
// fast array equals
instruct array_equals(eDIRegP ary1, eSIRegP ary2, regXD tmp1, regXD tmp2, eBXRegI tmp3,
eDXRegI tmp4, eAXRegI result, eFlagsReg cr) %{
instruct array_equals(eDIRegP ary1, eSIRegP ary2, eAXRegI result,
regXD tmp1, regXD tmp2, eCXRegI tmp3, eBXRegI tmp4, eFlagsReg cr)
%{
match(Set result (AryEq ary1 ary2));
effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr);
//ins_cost(300);
format %{ "Array Equals $ary1,$ary2 -> $result // KILL EBX, EDX" %}
ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, tmp3, tmp4, result) );
format %{ "Array Equals $ary1,$ary2 -> $result // KILL $tmp1, $tmp2, $tmp3, $tmp4" %}
ins_encode %{
__ char_arrays_equals(true, $ary1$$Register, $ary2$$Register,
$tmp3$$Register, $result$$Register, $tmp4$$Register,
$tmp1$$XMMRegister, $tmp2$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}

View File

@ -683,7 +683,7 @@ void emit_d32_reloc(CodeBuffer& cbuf,
#ifdef ASSERT
if (rspec.reloc()->type() == relocInfo::oop_type &&
d32 != 0 && d32 != (intptr_t) Universe::non_oop_word()) {
assert(oop((intptr_t)d32)->is_oop() && oop((intptr_t)d32)->is_perm(), "cannot embed non-perm oops in code");
assert(oop((intptr_t)d32)->is_oop() && (ScavengeRootsInCode || !oop((intptr_t)d32)->is_scavengable()), "cannot embed scavengable oops in code");
}
#endif
cbuf.relocate(cbuf.inst_mark(), rspec, format);
@ -721,8 +721,8 @@ void emit_d64_reloc(CodeBuffer& cbuf,
#ifdef ASSERT
if (rspec.reloc()->type() == relocInfo::oop_type &&
d64 != 0 && d64 != (int64_t) Universe::non_oop_word()) {
assert(oop(d64)->is_oop() && oop(d64)->is_perm(),
"cannot embed non-perm oops in code");
assert(oop(d64)->is_oop() && (ScavengeRootsInCode || !oop(d64)->is_scavengable()),
"cannot embed scavengable oops in code");
}
#endif
cbuf.relocate(cbuf.inst_mark(), rspec, format);
@ -3701,448 +3701,6 @@ encode %{
}
%}
enc_class enc_String_Compare(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2,
rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result) %{
Label RCX_GOOD_LABEL, LENGTH_DIFF_LABEL,
POP_LABEL, DONE_LABEL, CONT_LABEL,
WHILE_HEAD_LABEL;
MacroAssembler masm(&cbuf);
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg);
// Get the first character position in both strings
// [8] char array, [12] offset, [16] count
int value_offset = java_lang_String::value_offset_in_bytes();
int offset_offset = java_lang_String::offset_offset_in_bytes();
int count_offset = java_lang_String::count_offset_in_bytes();
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
masm.load_heap_oop(rax, Address(rsi, value_offset));
masm.movl(rcx, Address(rsi, offset_offset));
masm.lea(rax, Address(rax, rcx, Address::times_2, base_offset));
masm.load_heap_oop(rbx, Address(rdi, value_offset));
masm.movl(rcx, Address(rdi, offset_offset));
masm.lea(rbx, Address(rbx, rcx, Address::times_2, base_offset));
// Compute the minimum of the string lengths(rsi) and the
// difference of the string lengths (stack)
// do the conditional move stuff
masm.movl(rdi, Address(rdi, count_offset));
masm.movl(rsi, Address(rsi, count_offset));
masm.movl(rcx, rdi);
masm.subl(rdi, rsi);
masm.push(rdi);
masm.cmov(Assembler::lessEqual, rsi, rcx);
// Is the minimum length zero?
masm.bind(RCX_GOOD_LABEL);
masm.testl(rsi, rsi);
masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL);
// Load first characters
masm.load_unsigned_short(rcx, Address(rbx, 0));
masm.load_unsigned_short(rdi, Address(rax, 0));
// Compare first characters
masm.subl(rcx, rdi);
masm.jcc(Assembler::notZero, POP_LABEL);
masm.decrementl(rsi);
masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL);
{
// Check after comparing first character to see if strings are equivalent
Label LSkip2;
// Check if the strings start at same location
masm.cmpptr(rbx, rax);
masm.jccb(Assembler::notEqual, LSkip2);
// Check if the length difference is zero (from stack)
masm.cmpl(Address(rsp, 0), 0x0);
masm.jcc(Assembler::equal, LENGTH_DIFF_LABEL);
// Strings might not be equivalent
masm.bind(LSkip2);
}
// Advance to next character
masm.addptr(rax, 2);
masm.addptr(rbx, 2);
if (UseSSE42Intrinsics) {
// With SSE4.2, use double quad vector compare
Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL;
// Setup to compare 16-byte vectors
masm.movl(rdi, rsi);
masm.andl(rsi, 0xfffffff8); // rsi holds the vector count
masm.andl(rdi, 0x00000007); // rdi holds the tail count
masm.testl(rsi, rsi);
masm.jccb(Assembler::zero, COMPARE_TAIL);
masm.lea(rax, Address(rax, rsi, Address::times_2));
masm.lea(rbx, Address(rbx, rsi, Address::times_2));
masm.negptr(rsi);
masm.bind(COMPARE_VECTORS);
masm.movdqu(tmp1Reg, Address(rax, rsi, Address::times_2));
masm.movdqu(tmp2Reg, Address(rbx, rsi, Address::times_2));
masm.pxor(tmp1Reg, tmp2Reg);
masm.ptest(tmp1Reg, tmp1Reg);
masm.jccb(Assembler::notZero, VECTOR_NOT_EQUAL);
masm.addptr(rsi, 8);
masm.jcc(Assembler::notZero, COMPARE_VECTORS);
masm.jmpb(COMPARE_TAIL);
// Mismatched characters in the vectors
masm.bind(VECTOR_NOT_EQUAL);
masm.lea(rax, Address(rax, rsi, Address::times_2));
masm.lea(rbx, Address(rbx, rsi, Address::times_2));
masm.movl(rdi, 8);
// Compare tail (< 8 chars), or rescan last vectors to
// find 1st mismatched characters
masm.bind(COMPARE_TAIL);
masm.testl(rdi, rdi);
masm.jccb(Assembler::zero, LENGTH_DIFF_LABEL);
masm.movl(rsi, rdi);
// Fallthru to tail compare
}
// Shift RAX and RBX to the end of the arrays, negate min
masm.lea(rax, Address(rax, rsi, Address::times_2, 0));
masm.lea(rbx, Address(rbx, rsi, Address::times_2, 0));
masm.negptr(rsi);
// Compare the rest of the characters
masm.bind(WHILE_HEAD_LABEL);
masm.load_unsigned_short(rcx, Address(rbx, rsi, Address::times_2, 0));
masm.load_unsigned_short(rdi, Address(rax, rsi, Address::times_2, 0));
masm.subl(rcx, rdi);
masm.jccb(Assembler::notZero, POP_LABEL);
masm.increment(rsi);
masm.jcc(Assembler::notZero, WHILE_HEAD_LABEL);
// Strings are equal up to min length. Return the length difference.
masm.bind(LENGTH_DIFF_LABEL);
masm.pop(rcx);
masm.jmpb(DONE_LABEL);
// Discard the stored length difference
masm.bind(POP_LABEL);
masm.addptr(rsp, 8);
// That's it
masm.bind(DONE_LABEL);
%}
enc_class enc_String_IndexOf(rsi_RegP str1, rdi_RegP str2, regD tmp1, rax_RegI tmp2,
rcx_RegI tmp3, rdx_RegI tmp4, rbx_RegI result) %{
// SSE4.2 version
Label LOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR,
SCAN_SUBSTR, RET_NEG_ONE, RET_NOT_FOUND, CLEANUP, DONE;
MacroAssembler masm(&cbuf);
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
// Get the first character position in both strings
// [8] char array, [12] offset, [16] count
int value_offset = java_lang_String::value_offset_in_bytes();
int offset_offset = java_lang_String::offset_offset_in_bytes();
int count_offset = java_lang_String::count_offset_in_bytes();
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
// Get counts for string and substr
masm.movl(rdx, Address(rsi, count_offset));
masm.movl(rax, Address(rdi, count_offset));
// Check for substr count > string count
masm.cmpl(rax, rdx);
masm.jcc(Assembler::greater, RET_NEG_ONE);
// Start the indexOf operation
// Get start addr of string
masm.load_heap_oop(rbx, Address(rsi, value_offset));
masm.movl(rcx, Address(rsi, offset_offset));
masm.lea(rsi, Address(rbx, rcx, Address::times_2, base_offset));
masm.push(rsi);
// Get start addr of substr
masm.load_heap_oop(rbx, Address(rdi, value_offset));
masm.movl(rcx, Address(rdi, offset_offset));
masm.lea(rdi, Address(rbx, rcx, Address::times_2, base_offset));
masm.push(rdi);
masm.push(rax);
masm.jmpb(PREP_FOR_SCAN);
// Substr count saved at sp
// Substr saved at sp+8
// String saved at sp+16
// Prep to load substr for scan
masm.bind(LOAD_SUBSTR);
masm.movptr(rdi, Address(rsp, 8));
masm.movl(rax, Address(rsp, 0));
// Load substr
masm.bind(PREP_FOR_SCAN);
masm.movdqu(tmp1Reg, Address(rdi, 0));
masm.addq(rdx, 8); // prime the loop
masm.subptr(rsi, 16);
// Scan string for substr in 16-byte vectors
masm.bind(SCAN_TO_SUBSTR);
masm.subq(rdx, 8);
masm.addptr(rsi, 16);
masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d);
masm.jcc(Assembler::above, SCAN_TO_SUBSTR);
masm.jccb(Assembler::aboveEqual, RET_NOT_FOUND);
// Fallthru: found a potential substr
//Make sure string is still long enough
masm.subl(rdx, rcx);
masm.cmpl(rdx, rax);
masm.jccb(Assembler::negative, RET_NOT_FOUND);
// Compute start addr of substr
masm.lea(rsi, Address(rsi, rcx, Address::times_2));
masm.movptr(rbx, rsi);
// Compare potential substr
masm.addq(rdx, 8); // prime the loop
masm.addq(rax, 8);
masm.subptr(rsi, 16);
masm.subptr(rdi, 16);
// Scan 16-byte vectors of string and substr
masm.bind(SCAN_SUBSTR);
masm.subq(rax, 8);
masm.subq(rdx, 8);
masm.addptr(rsi, 16);
masm.addptr(rdi, 16);
masm.movdqu(tmp1Reg, Address(rdi, 0));
masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d);
masm.jcc(Assembler::noOverflow, LOAD_SUBSTR); // OF == 0
masm.jcc(Assembler::positive, SCAN_SUBSTR); // SF == 0
// Compute substr offset
masm.movptr(rsi, Address(rsp, 16));
masm.subptr(rbx, rsi);
masm.shrl(rbx, 1);
masm.jmpb(CLEANUP);
masm.bind(RET_NEG_ONE);
masm.movl(rbx, -1);
masm.jmpb(DONE);
masm.bind(RET_NOT_FOUND);
masm.movl(rbx, -1);
masm.bind(CLEANUP);
masm.addptr(rsp, 24);
masm.bind(DONE);
%}
enc_class enc_String_Equals(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2,
rbx_RegI tmp3, rcx_RegI tmp2, rax_RegI result) %{
Label RET_TRUE, RET_FALSE, DONE, COMPARE_VECTORS, COMPARE_CHAR;
MacroAssembler masm(&cbuf);
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg);
int value_offset = java_lang_String::value_offset_in_bytes();
int offset_offset = java_lang_String::offset_offset_in_bytes();
int count_offset = java_lang_String::count_offset_in_bytes();
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
// does source == target string?
masm.cmpptr(rdi, rsi);
masm.jcc(Assembler::equal, RET_TRUE);
// get and compare counts
masm.movl(rcx, Address(rdi, count_offset));
masm.movl(rax, Address(rsi, count_offset));
masm.cmpl(rcx, rax);
masm.jcc(Assembler::notEqual, RET_FALSE);
masm.testl(rax, rax);
masm.jcc(Assembler::zero, RET_TRUE);
// get source string offset and value
masm.load_heap_oop(rbx, Address(rsi, value_offset));
masm.movl(rax, Address(rsi, offset_offset));
masm.lea(rsi, Address(rbx, rax, Address::times_2, base_offset));
// get compare string offset and value
masm.load_heap_oop(rbx, Address(rdi, value_offset));
masm.movl(rax, Address(rdi, offset_offset));
masm.lea(rdi, Address(rbx, rax, Address::times_2, base_offset));
// Set byte count
masm.shll(rcx, 1);
masm.movl(rax, rcx);
if (UseSSE42Intrinsics) {
// With SSE4.2, use double quad vector compare
Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
// Compare 16-byte vectors
masm.andl(rcx, 0xfffffff0); // vector count (in bytes)
masm.andl(rax, 0x0000000e); // tail count (in bytes)
masm.testl(rcx, rcx);
masm.jccb(Assembler::zero, COMPARE_TAIL);
masm.lea(rdi, Address(rdi, rcx, Address::times_1));
masm.lea(rsi, Address(rsi, rcx, Address::times_1));
masm.negptr(rcx);
masm.bind(COMPARE_WIDE_VECTORS);
masm.movdqu(tmp1Reg, Address(rdi, rcx, Address::times_1));
masm.movdqu(tmp2Reg, Address(rsi, rcx, Address::times_1));
masm.pxor(tmp1Reg, tmp2Reg);
masm.ptest(tmp1Reg, tmp1Reg);
masm.jccb(Assembler::notZero, RET_FALSE);
masm.addptr(rcx, 16);
masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
masm.bind(COMPARE_TAIL);
masm.movl(rcx, rax);
// Fallthru to tail compare
}
// Compare 4-byte vectors
masm.andl(rcx, 0xfffffffc); // vector count (in bytes)
masm.andl(rax, 0x00000002); // tail char (in bytes)
masm.testl(rcx, rcx);
masm.jccb(Assembler::zero, COMPARE_CHAR);
masm.lea(rdi, Address(rdi, rcx, Address::times_1));
masm.lea(rsi, Address(rsi, rcx, Address::times_1));
masm.negptr(rcx);
masm.bind(COMPARE_VECTORS);
masm.movl(rbx, Address(rdi, rcx, Address::times_1));
masm.cmpl(rbx, Address(rsi, rcx, Address::times_1));
masm.jccb(Assembler::notEqual, RET_FALSE);
masm.addptr(rcx, 4);
masm.jcc(Assembler::notZero, COMPARE_VECTORS);
// Compare trailing char (final 2 bytes), if any
masm.bind(COMPARE_CHAR);
masm.testl(rax, rax);
masm.jccb(Assembler::zero, RET_TRUE);
masm.load_unsigned_short(rbx, Address(rdi, 0));
masm.load_unsigned_short(rcx, Address(rsi, 0));
masm.cmpl(rbx, rcx);
masm.jccb(Assembler::notEqual, RET_FALSE);
masm.bind(RET_TRUE);
masm.movl(rax, 1); // return true
masm.jmpb(DONE);
masm.bind(RET_FALSE);
masm.xorl(rax, rax); // return false
masm.bind(DONE);
%}
enc_class enc_Array_Equals(rdi_RegP ary1, rsi_RegP ary2, regD tmp1, regD tmp2,
rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result) %{
Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR;
MacroAssembler masm(&cbuf);
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg);
Register ary1Reg = as_Register($ary1$$reg);
Register ary2Reg = as_Register($ary2$$reg);
Register tmp3Reg = as_Register($tmp3$$reg);
Register tmp4Reg = as_Register($tmp4$$reg);
Register resultReg = as_Register($result$$reg);
int length_offset = arrayOopDesc::length_offset_in_bytes();
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
// Check the input args
masm.cmpq(ary1Reg, ary2Reg);
masm.jcc(Assembler::equal, TRUE_LABEL);
masm.testq(ary1Reg, ary1Reg);
masm.jcc(Assembler::zero, FALSE_LABEL);
masm.testq(ary2Reg, ary2Reg);
masm.jcc(Assembler::zero, FALSE_LABEL);
// Check the lengths
masm.movl(tmp4Reg, Address(ary1Reg, length_offset));
masm.movl(resultReg, Address(ary2Reg, length_offset));
masm.cmpl(tmp4Reg, resultReg);
masm.jcc(Assembler::notEqual, FALSE_LABEL);
masm.testl(resultReg, resultReg);
masm.jcc(Assembler::zero, TRUE_LABEL);
//load array address
masm.lea(ary1Reg, Address(ary1Reg, base_offset));
masm.lea(ary2Reg, Address(ary2Reg, base_offset));
//set byte count
masm.shll(tmp4Reg, 1);
masm.movl(resultReg,tmp4Reg);
if (UseSSE42Intrinsics){
// With SSE4.2, use double quad vector compare
Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
// Compare 16-byte vectors
masm.andl(tmp4Reg, 0xfffffff0); // vector count (in bytes)
masm.andl(resultReg, 0x0000000e); // tail count (in bytes)
masm.testl(tmp4Reg, tmp4Reg);
masm.jccb(Assembler::zero, COMPARE_TAIL);
masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
masm.negptr(tmp4Reg);
masm.bind(COMPARE_WIDE_VECTORS);
masm.movdqu(tmp1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
masm.movdqu(tmp2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
masm.pxor(tmp1Reg, tmp2Reg);
masm.ptest(tmp1Reg, tmp1Reg);
masm.jccb(Assembler::notZero, FALSE_LABEL);
masm.addptr(tmp4Reg, 16);
masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
masm.bind(COMPARE_TAIL);
masm.movl(tmp4Reg, resultReg);
// Fallthru to tail compare
}
// Compare 4-byte vectors
masm.andl(tmp4Reg, 0xfffffffc); // vector count (in bytes)
masm.andl(resultReg, 0x00000002); // tail char (in bytes)
masm.testl(tmp4Reg, tmp4Reg); //if tmp2 == 0, only compare char
masm.jccb(Assembler::zero, COMPARE_CHAR);
masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
masm.negptr(tmp4Reg);
masm.bind(COMPARE_VECTORS);
masm.movl(tmp3Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
masm.cmpl(tmp3Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
masm.jccb(Assembler::notEqual, FALSE_LABEL);
masm.addptr(tmp4Reg, 4);
masm.jcc(Assembler::notZero, COMPARE_VECTORS);
// Compare trailing char (final 2 bytes), if any
masm.bind(COMPARE_CHAR);
masm.testl(resultReg, resultReg);
masm.jccb(Assembler::zero, TRUE_LABEL);
masm.load_unsigned_short(tmp3Reg, Address(ary1Reg, 0));
masm.load_unsigned_short(tmp4Reg, Address(ary2Reg, 0));
masm.cmpl(tmp3Reg, tmp4Reg);
masm.jccb(Assembler::notEqual, FALSE_LABEL);
masm.bind(TRUE_LABEL);
masm.movl(resultReg, 1); // return true
masm.jmpb(DONE);
masm.bind(FALSE_LABEL);
masm.xorl(resultReg, resultReg); // return false
// That's it
masm.bind(DONE);
%}
enc_class enc_rethrow()
%{
@ -12096,52 +11654,67 @@ instruct rep_stos(rcx_RegL cnt, rdi_RegP base, rax_RegI zero, Universe dummy,
ins_pipe(pipe_slow);
%}
instruct string_compare(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2,
rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result, rFlagsReg cr)
instruct string_compare(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rbx_RegI cnt2,
rax_RegI result, regD tmp1, regD tmp2, rFlagsReg cr)
%{
match(Set result (StrComp str1 str2));
effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr);
//ins_cost(300);
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
format %{ "String Compare $str1, $str2 -> $result // XXX KILL RAX, RBX" %}
ins_encode( enc_String_Compare(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1, $tmp2" %}
ins_encode %{
__ string_compare($str1$$Register, $str2$$Register,
$cnt1$$Register, $cnt2$$Register, $result$$Register,
$tmp1$$XMMRegister, $tmp2$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
instruct string_indexof(rsi_RegP str1, rdi_RegP str2, regD tmp1, rax_RegI tmp2,
rcx_RegI tmp3, rdx_RegI tmp4, rbx_RegI result, rFlagsReg cr)
instruct string_indexof(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI cnt2,
rbx_RegI result, regD tmp1, rcx_RegI tmp2, rFlagsReg cr)
%{
predicate(UseSSE42Intrinsics);
match(Set result (StrIndexOf str1 str2));
effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, KILL tmp2, KILL tmp3, KILL tmp4, KILL cr);
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)));
effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL tmp2, KILL cr);
format %{ "String IndexOf $str1,$str2 -> $result // KILL RAX, RCX, RDX" %}
ins_encode( enc_String_IndexOf(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1, $tmp2" %}
ins_encode %{
__ string_indexof($str1$$Register, $str2$$Register,
$cnt1$$Register, $cnt2$$Register, $result$$Register,
$tmp1$$XMMRegister, $tmp2$$Register);
%}
ins_pipe( pipe_slow );
%}
// fast string equals
instruct string_equals(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2, rbx_RegI tmp3,
rcx_RegI tmp4, rax_RegI result, rFlagsReg cr)
instruct string_equals(rdi_RegP str1, rsi_RegP str2, rcx_RegI cnt, rax_RegI result,
regD tmp1, regD tmp2, rbx_RegI tmp3, rFlagsReg cr)
%{
match(Set result (StrEquals str1 str2));
effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr);
match(Set result (StrEquals (Binary str1 str2) cnt));
effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp3, KILL cr);
format %{ "String Equals $str1,$str2 -> $result // KILL RBX, RCX" %}
ins_encode( enc_String_Equals(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp1, $tmp2, $tmp3" %}
ins_encode %{
__ char_arrays_equals(false, $str1$$Register, $str2$$Register,
$cnt$$Register, $result$$Register, $tmp3$$Register,
$tmp1$$XMMRegister, $tmp2$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}
// fast array equals
instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, regD tmp1, regD tmp2, rax_RegI tmp3,
rbx_RegI tmp4, rcx_RegI result, rFlagsReg cr)
instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result,
regD tmp1, regD tmp2, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr)
%{
match(Set result (AryEq ary1 ary2));
effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr);
//ins_cost(300);
format %{ "Array Equals $ary1,$ary2 -> $result // KILL RAX, RBX" %}
ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, tmp3, tmp4, result) );
format %{ "Array Equals $ary1,$ary2 -> $result // KILL $tmp1, $tmp2, $tmp3, $tmp4" %}
ins_encode %{
__ char_arrays_equals(true, $ary1$$Register, $ary2$$Register,
$tmp3$$Register, $result$$Register, $tmp4$$Register,
$tmp1$$XMMRegister, $tmp2$$XMMRegister);
%}
ins_pipe( pipe_slow );
%}

View File

@ -828,11 +828,13 @@ uint InstructForm::oper_input_base(FormDict &globals) {
return AdlcVMDeps::Parms; // Skip the machine-state edges
if( _matrule->_rChild &&
( strcmp(_matrule->_rChild->_opType,"StrComp" )==0 ||
( strcmp(_matrule->_rChild->_opType,"AryEq" )==0 ||
strcmp(_matrule->_rChild->_opType,"StrComp" )==0 ||
strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 ||
strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 )) {
// String.(compareTo/equals/indexOf) take 1 control and 4 memory edges.
return 5;
// String.(compareTo/equals/indexOf) and Arrays.equals
// take 1 control and 1 memory edges.
return 2;
}
// Check for handling of 'Memory' input/edge in the ideal world.

View File

@ -1442,7 +1442,7 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
switch (field_type) {
case T_ARRAY:
case T_OBJECT:
if (field_val.as_object()->has_encoding()) {
if (field_val.as_object()->should_be_constant()) {
constant = new Constant(as_ValueType(field_val));
}
break;

View File

@ -133,12 +133,12 @@ void InstructionPrinter::print_object(Value obj) {
ciMethod* m = (ciMethod*)value;
output()->print("<method %s.%s>", m->holder()->name()->as_utf8(), m->name()->as_utf8());
} else {
output()->print("<object 0x%x>", value->encoding());
output()->print("<object 0x%x>", value->constant_encoding());
}
} else if (type->as_InstanceConstant() != NULL) {
output()->print("<instance 0x%x>", type->as_InstanceConstant()->value()->encoding());
output()->print("<instance 0x%x>", type->as_InstanceConstant()->value()->constant_encoding());
} else if (type->as_ArrayConstant() != NULL) {
output()->print("<array 0x%x>", type->as_ArrayConstant()->value()->encoding());
output()->print("<array 0x%x>", type->as_ArrayConstant()->value()->constant_encoding());
} else if (type->as_ClassConstant() != NULL) {
ciInstanceKlass* klass = type->as_ClassConstant()->value();
if (!klass->is_loaded()) {

View File

@ -440,7 +440,7 @@ void LIRGenerator::jobject2reg_with_patching(LIR_Opr r, ciObject* obj, CodeEmitI
__ oop2reg_patch(NULL, r, info);
} else {
// no patching needed
__ oop2reg(obj->encoding(), r);
__ oop2reg(obj->constant_encoding(), r);
}
}
@ -831,7 +831,7 @@ void LIRGenerator::profile_branch(If* if_instr, If::Condition cond) {
int taken_count_offset = md->byte_offset_of_slot(data, BranchData::taken_offset());
int not_taken_count_offset = md->byte_offset_of_slot(data, BranchData::not_taken_offset());
LIR_Opr md_reg = new_register(T_OBJECT);
__ move(LIR_OprFact::oopConst(md->encoding()), md_reg);
__ move(LIR_OprFact::oopConst(md->constant_encoding()), md_reg);
LIR_Opr data_offset_reg = new_register(T_INT);
__ cmove(lir_cond(cond),
LIR_OprFact::intConst(taken_count_offset),
@ -1071,7 +1071,7 @@ void LIRGenerator::do_Return(Return* x) {
LIR_OprList* args = new LIR_OprList();
args->append(getThreadPointer());
LIR_Opr meth = new_register(T_OBJECT);
__ oop2reg(method()->encoding(), meth);
__ oop2reg(method()->constant_encoding(), meth);
args->append(meth);
call_runtime(&signature, args, CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), voidType, NULL);
}
@ -1784,7 +1784,7 @@ void LIRGenerator::do_Throw(Throw* x) {
LIR_OprList* args = new LIR_OprList();
args->append(getThreadPointer());
LIR_Opr meth = new_register(T_OBJECT);
__ oop2reg(method()->encoding(), meth);
__ oop2reg(method()->constant_encoding(), meth);
args->append(meth);
call_runtime(&signature, args, CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), voidType, NULL);
}
@ -2207,7 +2207,7 @@ void LIRGenerator::do_Base(Base* x) {
LIR_OprList* args = new LIR_OprList();
args->append(getThreadPointer());
LIR_Opr meth = new_register(T_OBJECT);
__ oop2reg(method()->encoding(), meth);
__ oop2reg(method()->constant_encoding(), meth);
args->append(meth);
call_runtime(&signature, args, CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), voidType, NULL);
}
@ -2216,7 +2216,7 @@ void LIRGenerator::do_Base(Base* x) {
LIR_Opr obj;
if (method()->is_static()) {
obj = new_register(T_OBJECT);
__ oop2reg(method()->holder()->java_mirror()->encoding(), obj);
__ oop2reg(method()->holder()->java_mirror()->constant_encoding(), obj);
} else {
Local* receiver = x->state()->local_at(0)->as_Local();
assert(receiver != NULL, "must already exist");
@ -2660,7 +2660,7 @@ void LIRGenerator::increment_invocation_counter(CodeEmitInfo* info, bool backedg
}
LIR_Opr meth = new_register(T_OBJECT);
__ oop2reg(method()->encoding(), meth);
__ oop2reg(method()->constant_encoding(), meth);
LIR_Opr result = increment_and_return_counter(meth, offset, InvocationCounter::count_increment);
__ cmp(lir_cond_aboveEqual, result, LIR_OprFact::intConst(limit));
CodeStub* overflow = new CounterOverflowStub(info, info->bci());

View File

@ -86,7 +86,7 @@ ValueType* ValueType::join(ValueType* y) const {
jobject ObjectType::encoding() const {
assert(is_constant(), "must be");
return constant_value()->encoding();
return constant_value()->constant_encoding();
}
bool ObjectType::is_loaded() const {

View File

@ -257,7 +257,7 @@ ciMethod* ciEnv::get_method_from_handle(jobject method) {
// ------------------------------------------------------------------
// ciEnv::make_array
ciArray* ciEnv::make_array(GrowableArray<ciObject*>* objects) {
ciArray* ciEnv::make_system_array(GrowableArray<ciObject*>* objects) {
VM_ENTRY_MARK;
int length = objects->length();
objArrayOop a = oopFactory::new_system_objArray(length, THREAD);

View File

@ -339,8 +339,8 @@ public:
// but consider adding to vmSymbols.hpp instead.
// Use this to make a holder for non-perm compile time constants.
// The resulting array is guaranteed to satisfy "has_encoding".
ciArray* make_array(GrowableArray<ciObject*>* objects);
// The resulting array is guaranteed to satisfy "can_be_constant".
ciArray* make_system_array(GrowableArray<ciObject*>* objects);
// converts the ciKlass* representing the holder of a method into a
// ciInstanceKlass*. This is needed since the holder of a method in

View File

@ -325,10 +325,10 @@ ciTypeFlow* ciMethod::get_osr_flow_analysis(int osr_bci) {
}
// ------------------------------------------------------------------
// ciMethod::liveness_at_bci
// ciMethod::raw_liveness_at_bci
//
// Which local variables are live at a specific bci?
MethodLivenessResult ciMethod::liveness_at_bci(int bci) {
MethodLivenessResult ciMethod::raw_liveness_at_bci(int bci) {
check_is_loaded();
if (_liveness == NULL) {
// Create the liveness analyzer.
@ -336,7 +336,17 @@ MethodLivenessResult ciMethod::liveness_at_bci(int bci) {
_liveness = new (arena) MethodLiveness(arena, this);
_liveness->compute_liveness();
}
MethodLivenessResult result = _liveness->get_liveness_at(bci);
return _liveness->get_liveness_at(bci);
}
// ------------------------------------------------------------------
// ciMethod::liveness_at_bci
//
// Which local variables are live at a specific bci? When debugging
// will return true for all locals in some cases to improve debug
// information.
MethodLivenessResult ciMethod::liveness_at_bci(int bci) {
MethodLivenessResult result = raw_liveness_at_bci(bci);
if (CURRENT_ENV->jvmti_can_access_local_variables() || DeoptimizeALot || CompileTheWorld) {
// Keep all locals live for the user's edification and amusement.
result.at_put_range(0, result.size(), true);

View File

@ -149,6 +149,12 @@ class ciMethod : public ciObject {
bool has_monitor_bytecodes() const { return _uses_monitors; }
bool has_balanced_monitors();
// Returns a bitmap indicating which locals are required to be
// maintained as live for deopt. raw_liveness_at_bci is always the
// direct output of the liveness computation while liveness_at_bci
// may mark all locals as live to improve support for debugging Java
// code by maintaining the state of as many locals as possible.
MethodLivenessResult raw_liveness_at_bci(int bci);
MethodLivenessResult liveness_at_bci(int bci);
// Get the interpreters viewpoint on oop liveness. MethodLiveness is

View File

@ -55,6 +55,7 @@ ciObject::ciObject(oop o) {
}
_klass = NULL;
_ident = 0;
init_flags_from(o);
}
// ------------------------------------------------------------------
@ -69,6 +70,7 @@ ciObject::ciObject(Handle h) {
}
_klass = NULL;
_ident = 0;
init_flags_from(h());
}
// ------------------------------------------------------------------
@ -158,7 +160,7 @@ int ciObject::hash() {
}
// ------------------------------------------------------------------
// ciObject::encoding
// ciObject::constant_encoding
//
// The address which the compiler should embed into the
// generated code to represent this oop. This address
@ -172,16 +174,24 @@ int ciObject::hash() {
//
// This method should be changed to return an generified address
// to discourage use of the JNI handle.
jobject ciObject::encoding() {
jobject ciObject::constant_encoding() {
assert(is_null_object() || handle() != NULL, "cannot embed null pointer");
assert(has_encoding(), "oop must be NULL or perm");
assert(can_be_constant(), "oop must be NULL or perm");
return handle();
}
// ------------------------------------------------------------------
// ciObject::has_encoding
bool ciObject::has_encoding() {
return handle() == NULL || is_perm();
// ciObject::can_be_constant
bool ciObject::can_be_constant() {
if (ScavengeRootsInCode >= 1) return true; // now everybody can encode as a constant
return handle() == NULL || !is_scavengable();
}
// ------------------------------------------------------------------
// ciObject::should_be_constant()
bool ciObject::should_be_constant() {
if (ScavengeRootsInCode >= 2) return true; // force everybody to be a constant
return handle() == NULL || !is_scavengable();
}
@ -195,8 +205,9 @@ bool ciObject::has_encoding() {
void ciObject::print(outputStream* st) {
st->print("<%s", type_string());
GUARDED_VM_ENTRY(print_impl(st);)
st->print(" ident=%d %s address=0x%x>", ident(),
st->print(" ident=%d %s%s address=0x%x>", ident(),
is_perm() ? "PERM" : "",
is_scavengable() ? "SCAVENGABLE" : "",
(address)this);
}

View File

@ -51,9 +51,10 @@ private:
ciKlass* _klass;
uint _ident;
enum { FLAG_BITS = 1};
enum { FLAG_BITS = 2 };
enum {
PERM_FLAG = 1
PERM_FLAG = 1,
SCAVENGABLE_FLAG = 2
};
protected:
ciObject();
@ -68,8 +69,15 @@ protected:
return JNIHandles::resolve_non_null(_handle);
}
void set_perm() {
_ident |= PERM_FLAG;
void init_flags_from(oop x) {
int flags = 0;
if (x != NULL) {
if (x->is_perm())
flags |= PERM_FLAG;
if (x->is_scavengable())
flags |= SCAVENGABLE_FLAG;
}
_ident |= flags;
}
// Virtual behavior of the print() method.
@ -91,17 +99,27 @@ public:
// A hash value for the convenience of compilers.
int hash();
// Tells if this oop has an encoding. (I.e., is it null or perm?)
// Tells if this oop has an encoding as a constant.
// True if is_scavengable is false.
// Also true if ScavengeRootsInCode is non-zero.
// If it does not have an encoding, the compiler is responsible for
// making other arrangements for dealing with the oop.
// See ciEnv::make_perm_array
bool has_encoding();
// See ciEnv::make_array
bool can_be_constant();
// Tells if this oop should be made a constant.
// True if is_scavengable is false or ScavengeRootsInCode > 1.
bool should_be_constant();
// Is this object guaranteed to be in the permanent part of the heap?
// If so, CollectedHeap::can_elide_permanent_oop_store_barriers is relevant.
// If the answer is false, no guarantees are made.
bool is_perm() { return (_ident & PERM_FLAG) != 0; }
// Might this object possibly move during a scavenge operation?
// If the answer is true and ScavengeRootsInCode==0, the oop cannot be embedded in code.
bool is_scavengable() { return (_ident & SCAVENGABLE_FLAG) != 0; }
// The address which the compiler should embed into the
// generated code to represent this oop. This address
// is not the true address of the oop -- it will get patched
@ -109,7 +127,7 @@ public:
//
// Usage note: no address arithmetic allowed. Oop must
// be registered with the oopRecorder.
jobject encoding();
jobject constant_encoding();
// What kind of ciObject is this?
virtual bool is_null_object() const { return false; }

View File

@ -261,12 +261,11 @@ ciObject* ciObjectFactory::get(oop key) {
ciObject* new_object = create_new_object(keyHandle());
assert(keyHandle() == new_object->get_oop(), "must be properly recorded");
init_ident_of(new_object);
if (!keyHandle->is_perm()) {
if (!new_object->is_perm()) {
// Not a perm-space object.
insert_non_perm(bucket, keyHandle(), new_object);
return new_object;
}
new_object->set_perm();
if (len != _ci_objects->length()) {
// creating the new object has recursively entered new objects
// into the table. We need to recompute our index.

View File

@ -2486,8 +2486,13 @@ void ciTypeFlow::build_loop_tree(Block* blk) {
// Assume irreducible entries need more data flow
add_to_work_list(succ);
}
lp = lp->parent();
assert(lp != NULL, "nested loop must have parent by now");
Loop* plp = lp->parent();
if (plp == NULL) {
// This only happens for some irreducible cases. The parent
// will be updated during a later pass.
break;
}
lp = plp;
}
// Merge loop tree branch for all successors.

View File

@ -2417,6 +2417,8 @@ Handle SystemDictionary::make_dynamic_call_site(KlassHandle caller,
vmSymbols::makeSite_name(), vmSymbols::makeSite_signature(),
&args, CHECK_(empty));
oop call_site_oop = (oop) result.get_jobject();
assert(call_site_oop->is_oop()
/*&& sun_dyn_CallSiteImpl::is_instance(call_site_oop)*/, "must be sane");
sun_dyn_CallSiteImpl::set_vmmethod(call_site_oop, mh_invdyn());
if (TraceMethodHandles) {
tty->print_cr("Linked invokedynamic bci=%d site="INTPTR_FORMAT":", caller_bci, call_site_oop);
@ -2453,6 +2455,8 @@ Handle SystemDictionary::find_bootstrap_method(KlassHandle caller,
oop boot_method_oop = (oop) result.get_jobject();
if (boot_method_oop != NULL) {
assert(boot_method_oop->is_oop()
&& java_dyn_MethodHandle::is_instance(boot_method_oop), "must be sane");
// probably no race conditions, but let's be careful:
if (Atomic::cmpxchg_ptr(boot_method_oop, ik->adr_bootstrap_method(), NULL) == NULL)
ik->set_bootstrap_method(boot_method_oop);

View File

@ -175,6 +175,8 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
OopClosure* keep_alive,
bool unloading_occurred);
virtual void oops_do(OopClosure* f) = 0;
// (All CodeBlob subtypes other than NMethod currently have
// an empty oops_do() method.
// OopMap for frame
OopMapSet* oop_maps() const { return _oop_maps; }

View File

@ -95,6 +95,7 @@ CodeHeap * CodeCache::_heap = new CodeHeap();
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;
CodeBlob* CodeCache::first() {
@ -148,10 +149,7 @@ CodeBlob* CodeCache::allocate(int size) {
}
}
verify_if_often();
if (PrintCodeCache2) { // Need to add a new flag
ResourceMark rm;
tty->print_cr("CodeCache allocation: addr: " INTPTR_FORMAT ", size: 0x%x\n", cb, size);
}
print_trace("allocation", cb, size);
return cb;
}
@ -159,10 +157,7 @@ void CodeCache::free(CodeBlob* cb) {
assert_locked_or_safepoint(CodeCache_lock);
verify_if_often();
if (PrintCodeCache2) { // Need to add a new flag
ResourceMark rm;
tty->print_cr("CodeCache free: addr: " INTPTR_FORMAT ", size: 0x%x\n", cb, cb->size());
}
print_trace("free", cb);
if (cb->is_nmethod() && ((nmethod *)cb)->has_dependencies()) {
_number_of_nmethods_with_dependencies--;
}
@ -260,14 +255,148 @@ void CodeCache::do_unloading(BoolObjectClosure* is_alive,
}
}
void CodeCache::oops_do(OopClosure* f) {
void CodeCache::blobs_do(CodeBlobClosure* f) {
assert_locked_or_safepoint(CodeCache_lock);
FOR_ALL_ALIVE_BLOBS(cb) {
cb->oops_do(f);
f->do_code_blob(cb);
#ifdef ASSERT
if (cb->is_nmethod())
((nmethod*)cb)->verify_scavenge_root_oops();
#endif //ASSERT
}
}
// Walk the list of methods which might contain non-perm oops.
void CodeCache::scavenge_root_nmethods_do(CodeBlobClosure* f) {
assert_locked_or_safepoint(CodeCache_lock);
debug_only(mark_scavenge_root_nmethods());
for (nmethod* cur = scavenge_root_nmethods(); cur != NULL; cur = cur->scavenge_root_link()) {
debug_only(cur->clear_scavenge_root_marked());
assert(cur->scavenge_root_not_marked(), "");
assert(cur->on_scavenge_root_list(), "else shouldn't be on this list");
bool is_live = (!cur->is_zombie() && !cur->is_unloaded());
#ifndef PRODUCT
if (TraceScavenge) {
cur->print_on(tty, is_live ? "scavenge root" : "dead scavenge root"); tty->cr();
}
#endif //PRODUCT
if (is_live)
// Perform cur->oops_do(f), maybe just once per nmethod.
f->do_code_blob(cur);
}
// Check for stray marks.
debug_only(verify_perm_nmethods(NULL));
}
void CodeCache::add_scavenge_root_nmethod(nmethod* nm) {
assert_locked_or_safepoint(CodeCache_lock);
nm->set_on_scavenge_root_list();
nm->set_scavenge_root_link(_scavenge_root_nmethods);
set_scavenge_root_nmethods(nm);
print_trace("add_scavenge_root", nm);
}
void CodeCache::drop_scavenge_root_nmethod(nmethod* nm) {
assert_locked_or_safepoint(CodeCache_lock);
print_trace("drop_scavenge_root", nm);
nmethod* last = NULL;
nmethod* cur = scavenge_root_nmethods();
while (cur != NULL) {
nmethod* next = cur->scavenge_root_link();
if (cur == nm) {
if (last != NULL)
last->set_scavenge_root_link(next);
else set_scavenge_root_nmethods(next);
nm->set_scavenge_root_link(NULL);
nm->clear_on_scavenge_root_list();
return;
}
last = cur;
cur = next;
}
assert(false, "should have been on list");
}
void CodeCache::prune_scavenge_root_nmethods() {
assert_locked_or_safepoint(CodeCache_lock);
debug_only(mark_scavenge_root_nmethods());
nmethod* last = NULL;
nmethod* cur = scavenge_root_nmethods();
while (cur != NULL) {
nmethod* next = cur->scavenge_root_link();
debug_only(cur->clear_scavenge_root_marked());
assert(cur->scavenge_root_not_marked(), "");
assert(cur->on_scavenge_root_list(), "else shouldn't be on this list");
if (!cur->is_zombie() && !cur->is_unloaded()
&& cur->detect_scavenge_root_oops()) {
// Keep it. Advance 'last' to prevent deletion.
last = cur;
} else {
// Prune it from the list, so we don't have to look at it any more.
print_trace("prune_scavenge_root", cur);
cur->set_scavenge_root_link(NULL);
cur->clear_on_scavenge_root_list();
if (last != NULL)
last->set_scavenge_root_link(next);
else set_scavenge_root_nmethods(next);
}
cur = next;
}
// Check for stray marks.
debug_only(verify_perm_nmethods(NULL));
}
#ifndef PRODUCT
void CodeCache::asserted_non_scavengable_nmethods_do(CodeBlobClosure* f) {
// While we are here, verify the integrity of the list.
mark_scavenge_root_nmethods();
for (nmethod* cur = scavenge_root_nmethods(); cur != NULL; cur = cur->scavenge_root_link()) {
assert(cur->on_scavenge_root_list(), "else shouldn't be on this list");
cur->clear_scavenge_root_marked();
}
verify_perm_nmethods(f);
}
// Temporarily mark nmethods that are claimed to be on the non-perm list.
void CodeCache::mark_scavenge_root_nmethods() {
FOR_ALL_ALIVE_BLOBS(cb) {
if (cb->is_nmethod()) {
nmethod *nm = (nmethod*)cb;
assert(nm->scavenge_root_not_marked(), "clean state");
if (nm->on_scavenge_root_list())
nm->set_scavenge_root_marked();
}
}
}
// If the closure is given, run it on the unlisted nmethods.
// Also make sure that the effects of mark_scavenge_root_nmethods is gone.
void CodeCache::verify_perm_nmethods(CodeBlobClosure* f_or_null) {
FOR_ALL_ALIVE_BLOBS(cb) {
bool call_f = (f_or_null != NULL);
if (cb->is_nmethod()) {
nmethod *nm = (nmethod*)cb;
assert(nm->scavenge_root_not_marked(), "must be already processed");
if (nm->on_scavenge_root_list())
call_f = false; // don't show this one to the client
nm->verify_scavenge_root_oops();
} else {
call_f = false; // not an nmethod
}
if (call_f) f_or_null->do_code_blob(cb);
}
}
#endif //PRODUCT
void CodeCache::gc_prologue() {
assert(!nmethod::oops_do_marking_is_active(), "oops_do_marking_epilogue must be called");
}
@ -285,6 +414,8 @@ void CodeCache::gc_epilogue() {
cb->fix_oop_relocations();
}
set_needs_cache_clean(false);
prune_scavenge_root_nmethods();
assert(!nmethod::oops_do_marking_is_active(), "oops_do_marking_prologue must be called");
}
@ -508,6 +639,14 @@ void CodeCache::verify_if_often() {
}
}
void CodeCache::print_trace(const char* event, CodeBlob* cb, int size) {
if (PrintCodeCache2) { // Need to add a new flag
ResourceMark rm;
if (size == 0) size = cb->size();
tty->print_cr("CodeCache %s: addr: " INTPTR_FORMAT ", size: 0x%x", event, cb, size);
}
}
void CodeCache::print_internals() {
int nmethodCount = 0;
int runtimeStubCount = 0;

View File

@ -45,8 +45,13 @@ class CodeCache : AllStatic {
static int _number_of_blobs;
static int _number_of_nmethods_with_dependencies;
static bool _needs_cache_clean;
static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link()
static void verify_if_often() PRODUCT_RETURN;
static void mark_scavenge_root_nmethods() PRODUCT_RETURN;
static void verify_perm_nmethods(CodeBlobClosure* f_or_null) PRODUCT_RETURN;
public:
// Initialization
@ -61,6 +66,7 @@ class CodeCache : AllStatic {
static void flush(); // flushes all CodeBlobs
static bool contains(void *p); // returns whether p is included
static void blobs_do(void f(CodeBlob* cb)); // iterates over all CodeBlobs
static void blobs_do(CodeBlobClosure* f); // iterates over all CodeBlobs
static void nmethods_do(void f(nmethod* nm)); // iterates over all nmethods
// Lookup
@ -106,12 +112,24 @@ class CodeCache : AllStatic {
static void do_unloading(BoolObjectClosure* is_alive,
OopClosure* keep_alive,
bool unloading_occurred);
static void oops_do(OopClosure* f);
static void oops_do(OopClosure* f) {
CodeBlobToOopClosure oopc(f, /*do_marking=*/ false);
blobs_do(&oopc);
}
static void asserted_non_scavengable_nmethods_do(CodeBlobClosure* f = NULL) PRODUCT_RETURN;
static void scavenge_root_nmethods_do(CodeBlobClosure* f);
static nmethod* scavenge_root_nmethods() { return _scavenge_root_nmethods; }
static void set_scavenge_root_nmethods(nmethod* nm) { _scavenge_root_nmethods = nm; }
static void add_scavenge_root_nmethod(nmethod* nm);
static void drop_scavenge_root_nmethod(nmethod* nm);
static void prune_scavenge_root_nmethods();
// Printing/debugging
static void print() PRODUCT_RETURN; // prints summary
static void print_internals();
static void verify(); // verifies the code cache
static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN;
// The full limits of the codeCache
static address low_bound() { return (address) _heap->low_boundary(); }

View File

@ -299,7 +299,7 @@ void DebugInformationRecorder::describe_scope(int pc_offset,
stream()->write_int(sender_stream_offset);
// serialize scope
jobject method_enc = (method == NULL)? NULL: method->encoding();
jobject method_enc = (method == NULL)? NULL: method->constant_encoding();
stream()->write_int(oop_recorder()->find_index(method_enc));
stream()->write_bci(bci);
assert(method == NULL ||

View File

@ -302,7 +302,7 @@ void Dependencies::encode_content_bytes() {
bytes.write_byte(code_byte);
for (int j = 0; j < stride; j++) {
if (j == skipj) continue;
bytes.write_int(_oop_recorder->find_index(deps->at(i+j)->encoding()));
bytes.write_int(_oop_recorder->find_index(deps->at(i+j)->constant_encoding()));
}
}
}

View File

@ -581,10 +581,13 @@ nmethod::nmethod(
debug_only(No_Safepoint_Verifier nsv;)
assert_locked_or_safepoint(CodeCache_lock);
NOT_PRODUCT(_has_debug_info = false; )
NOT_PRODUCT(_has_debug_info = false);
_oops_do_mark_link = NULL;
_method = method;
_entry_bci = InvocationEntryBci;
_link = NULL;
_osr_link = NULL;
_scavenge_root_link = NULL;
_scavenge_root_state = 0;
_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
@ -618,7 +621,7 @@ nmethod::nmethod(
_stack_traversal_mark = 0;
code_buffer->copy_oops_to(this);
debug_only(check_store();)
debug_only(verify_scavenge_root_oops());
CodeCache::commit(this);
VTune::create_nmethod(this);
}
@ -668,10 +671,13 @@ nmethod::nmethod(
debug_only(No_Safepoint_Verifier nsv;)
assert_locked_or_safepoint(CodeCache_lock);
NOT_PRODUCT(_has_debug_info = false; )
NOT_PRODUCT(_has_debug_info = false);
_oops_do_mark_link = NULL;
_method = method;
_entry_bci = InvocationEntryBci;
_link = NULL;
_osr_link = NULL;
_scavenge_root_link = NULL;
_scavenge_root_state = 0;
_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
@ -703,7 +709,7 @@ nmethod::nmethod(
_stack_traversal_mark = 0;
code_buffer->copy_oops_to(this);
debug_only(check_store();)
debug_only(verify_scavenge_root_oops());
CodeCache::commit(this);
VTune::create_nmethod(this);
}
@ -770,12 +776,15 @@ nmethod::nmethod(
debug_only(No_Safepoint_Verifier nsv;)
assert_locked_or_safepoint(CodeCache_lock);
NOT_PRODUCT(_has_debug_info = false; )
NOT_PRODUCT(_has_debug_info = false);
_oops_do_mark_link = NULL;
_method = method;
_compile_id = compile_id;
_comp_level = comp_level;
_entry_bci = entry_bci;
_link = NULL;
_osr_link = NULL;
_scavenge_root_link = NULL;
_scavenge_root_state = 0;
_compiler = compiler;
_orig_pc_offset = orig_pc_offset;
#ifdef HAVE_DTRACE_H
@ -813,7 +822,10 @@ nmethod::nmethod(
code_buffer->copy_oops_to(this);
debug_info->copy_to(this);
dependencies->copy_to(this);
debug_only(check_store();)
if (ScavengeRootsInCode && detect_scavenge_root_oops()) {
CodeCache::add_scavenge_root_nmethod(this);
}
debug_only(verify_scavenge_root_oops());
CodeCache::commit(this);
@ -902,23 +914,30 @@ void nmethod::print_on(outputStream* st, const char* title) const {
if (st != NULL) {
ttyLocker ttyl;
// Print a little tag line that looks like +PrintCompilation output:
st->print("%3d%c %s",
int tlen = (int) strlen(title);
bool do_nl = false;
if (tlen > 0 && title[tlen-1] == '\n') { tlen--; do_nl = true; }
st->print("%3d%c %.*s",
compile_id(),
is_osr_method() ? '%' :
method() != NULL &&
is_native_method() ? 'n' : ' ',
title);
tlen, title);
#ifdef TIERED
st->print(" (%d) ", comp_level());
#endif // TIERED
if (WizardMode) st->print(" (" INTPTR_FORMAT ")", this);
if (method() != NULL) {
method()->print_short_name(st);
if (Universe::heap()->is_gc_active() && method() != NULL) {
st->print("(method)");
} else if (method() != NULL) {
method()->print_short_name(st);
if (is_osr_method())
st->print(" @ %d", osr_entry_bci());
if (method()->code_size() > 0)
st->print(" (%d bytes)", method()->code_size());
}
if (do_nl) st->cr();
}
}
@ -1033,6 +1052,7 @@ void nmethod::cleanup_inline_caches() {
}
}
// This is a private interface with the sweeper.
void nmethod::mark_as_seen_on_stack() {
assert(is_not_entrant(), "must be a non-entrant method");
set_stack_traversal_mark(NMethodSweeper::traversal_count());
@ -1077,7 +1097,8 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) {
" unloadable], methodOop(" INTPTR_FORMAT
"), cause(" INTPTR_FORMAT ")",
this, (address)_method, (address)cause);
cause->klass()->print();
if (!Universe::heap()->is_gc_active())
cause->klass()->print();
}
// Unlink the osr method, so we do not look this up again
if (is_osr_method()) {
@ -1109,7 +1130,8 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) {
// The methodOop is gone at this point
assert(_method == NULL, "Tautology");
set_link(NULL);
set_osr_link(NULL);
//set_scavenge_root_link(NULL); // done by prune_scavenge_root_nmethods
NMethodSweeper::notify(this);
}
@ -1295,6 +1317,10 @@ void nmethod::flush() {
ec = next;
}
if (on_scavenge_root_list()) {
CodeCache::drop_scavenge_root_nmethod(this);
}
((CodeBlob*)(this))->flush();
CodeCache::free(this);
@ -1354,7 +1380,10 @@ bool nmethod::can_unload(BoolObjectClosure* is_alive,
return false;
}
}
assert(unloading_occurred, "Inconsistency in unloading");
// If ScavengeRootsInCode is true, an nmethod might be unloaded
// simply because one of its constant oops has gone dead.
// No actual classes need to be unloaded in order for this to occur.
assert(unloading_occurred || ScavengeRootsInCode, "Inconsistency in unloading");
make_unloaded(is_alive, obj);
return true;
}
@ -1529,13 +1558,12 @@ void nmethod::do_unloading(BoolObjectClosure* is_alive,
// the (strong) marking phase, and then again when walking
// the code cache contents during the weak roots processing
// phase. The two uses are distinguished by means of the
// do_nmethods() method in the closure "f" below -- which
// answers "yes" in the first case, and "no" in the second
// 'do_strong_roots_only' flag, which is true in the first
// case. We want to walk the weak roots in the nmethod
// only in the second case. The weak roots in the nmethod
// are the oops in the ExceptionCache and the InlineCache
// oops.
void nmethod::oops_do(OopClosure* f) {
void nmethod::oops_do(OopClosure* f, bool do_strong_roots_only) {
// make sure the oops ready to receive visitors
assert(!is_zombie() && !is_unloaded(),
"should not call follow on zombie or unloaded nmethod");
@ -1553,7 +1581,7 @@ void nmethod::oops_do(OopClosure* f) {
// Compiled code
f->do_oop((oop*) &_method);
if (!f->do_nmethods()) {
if (!do_strong_roots_only) {
// weak roots processing phase -- update ExceptionCache oops
ExceptionCache* ec = exception_cache();
while(ec != NULL) {
@ -1579,12 +1607,108 @@ void nmethod::oops_do(OopClosure* f) {
}
// Scopes
// This includes oop constants not inlined in the code stream.
for (oop* p = oops_begin(); p < oops_end(); p++) {
if (*p == Universe::non_oop_word()) continue; // skip non-oops
f->do_oop(p);
}
}
#define NMETHOD_SENTINEL ((nmethod*)badAddress)
nmethod* volatile nmethod::_oops_do_mark_nmethods;
// An nmethod is "marked" if its _mark_link is set non-null.
// Even if it is the end of the linked list, it will have a non-null link value,
// as long as it is on the list.
// This code must be MP safe, because it is used from parallel GC passes.
bool nmethod::test_set_oops_do_mark() {
assert(nmethod::oops_do_marking_is_active(), "oops_do_marking_prologue must be called");
nmethod* observed_mark_link = _oops_do_mark_link;
if (observed_mark_link == NULL) {
// Claim this nmethod for this thread to mark.
observed_mark_link = (nmethod*)
Atomic::cmpxchg_ptr(NMETHOD_SENTINEL, &_oops_do_mark_link, NULL);
if (observed_mark_link == NULL) {
// Atomically append this nmethod (now claimed) to the head of the list:
nmethod* observed_mark_nmethods = _oops_do_mark_nmethods;
for (;;) {
nmethod* required_mark_nmethods = observed_mark_nmethods;
_oops_do_mark_link = required_mark_nmethods;
observed_mark_nmethods = (nmethod*)
Atomic::cmpxchg_ptr(this, &_oops_do_mark_nmethods, required_mark_nmethods);
if (observed_mark_nmethods == required_mark_nmethods)
break;
}
// Mark was clear when we first saw this guy.
NOT_PRODUCT(if (TraceScavenge) print_on(tty, "oops_do, mark\n"));
return false;
}
}
// On fall through, another racing thread marked this nmethod before we did.
return true;
}
void nmethod::oops_do_marking_prologue() {
NOT_PRODUCT(if (TraceScavenge) tty->print_cr("[oops_do_marking_prologue"));
assert(_oops_do_mark_nmethods == NULL, "must not call oops_do_marking_prologue twice in a row");
// We use cmpxchg_ptr instead of regular assignment here because the user
// may fork a bunch of threads, and we need them all to see the same state.
void* observed = Atomic::cmpxchg_ptr(NMETHOD_SENTINEL, &_oops_do_mark_nmethods, NULL);
guarantee(observed == NULL, "no races in this sequential code");
}
void nmethod::oops_do_marking_epilogue() {
assert(_oops_do_mark_nmethods != NULL, "must not call oops_do_marking_epilogue twice in a row");
nmethod* cur = _oops_do_mark_nmethods;
while (cur != NMETHOD_SENTINEL) {
assert(cur != NULL, "not NULL-terminated");
nmethod* next = cur->_oops_do_mark_link;
cur->_oops_do_mark_link = NULL;
NOT_PRODUCT(if (TraceScavenge) cur->print_on(tty, "oops_do, unmark\n"));
cur = next;
}
void* required = _oops_do_mark_nmethods;
void* observed = Atomic::cmpxchg_ptr(NULL, &_oops_do_mark_nmethods, required);
guarantee(observed == required, "no races in this sequential code");
NOT_PRODUCT(if (TraceScavenge) tty->print_cr("oops_do_marking_epilogue]"));
}
class DetectScavengeRoot: public OopClosure {
bool _detected_scavenge_root;
public:
DetectScavengeRoot() : _detected_scavenge_root(false)
{ NOT_PRODUCT(_print_nm = NULL); }
bool detected_scavenge_root() { return _detected_scavenge_root; }
virtual void do_oop(oop* p) {
if ((*p) != NULL && (*p)->is_scavengable()) {
NOT_PRODUCT(maybe_print(p));
_detected_scavenge_root = true;
}
}
virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
#ifndef PRODUCT
nmethod* _print_nm;
void maybe_print(oop* p) {
if (_print_nm == NULL) return;
if (!_detected_scavenge_root) _print_nm->print_on(tty, "new scavenge root");
tty->print_cr(""PTR_FORMAT"[offset=%d] detected non-perm oop "PTR_FORMAT" (found at "PTR_FORMAT")",
_print_nm, (int)((intptr_t)p - (intptr_t)_print_nm),
(intptr_t)(*p), (intptr_t)p);
(*p)->print();
}
#endif //PRODUCT
};
bool nmethod::detect_scavenge_root_oops() {
DetectScavengeRoot detect_scavenge_root;
NOT_PRODUCT(if (TraceScavenge) detect_scavenge_root._print_nm = this);
oops_do(&detect_scavenge_root);
return detect_scavenge_root.detected_scavenge_root();
}
// Method that knows how to preserve outgoing arguments at call. This method must be
// called with a frame corresponding to a Java invoke
void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) {
@ -1899,6 +2023,24 @@ bool nmethod::is_deopt_pc(address pc) {
// -----------------------------------------------------------------------------
// Verification
class VerifyOopsClosure: public OopClosure {
nmethod* _nm;
bool _ok;
public:
VerifyOopsClosure(nmethod* nm) : _nm(nm), _ok(true) { }
bool ok() { return _ok; }
virtual void do_oop(oop* p) {
if ((*p) == NULL || (*p)->is_oop()) return;
if (_ok) {
_nm->print_nmethod(true);
_ok = false;
}
tty->print_cr("*** non-oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)",
(intptr_t)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm));
}
virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
};
void nmethod::verify() {
// Hmm. OSR methods can be deopted but not marked as zombie or not_entrant
@ -1932,6 +2074,11 @@ void nmethod::verify() {
}
}
VerifyOopsClosure voc(this);
oops_do(&voc);
assert(voc.ok(), "embedded oops must be OK");
verify_scavenge_root_oops();
verify_scopes();
}
@ -1995,19 +2142,34 @@ void nmethod::verify_scopes() {
// Non-product code
#ifndef PRODUCT
void nmethod::check_store() {
// Make sure all oops in the compiled code are tenured
RelocIterator iter(this);
while (iter.next()) {
if (iter.type() == relocInfo::oop_type) {
oop_Relocation* reloc = iter.oop_reloc();
oop obj = reloc->oop_value();
if (obj != NULL && !obj->is_perm()) {
fatal("must be permanent oop in compiled code");
}
class DebugScavengeRoot: public OopClosure {
nmethod* _nm;
bool _ok;
public:
DebugScavengeRoot(nmethod* nm) : _nm(nm), _ok(true) { }
bool ok() { return _ok; }
virtual void do_oop(oop* p) {
if ((*p) == NULL || !(*p)->is_scavengable()) return;
if (_ok) {
_nm->print_nmethod(true);
_ok = false;
}
tty->print_cr("*** non-perm oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)",
(intptr_t)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm));
(*p)->print();
}
virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
};
void nmethod::verify_scavenge_root_oops() {
if (!on_scavenge_root_list()) {
// Actually look inside, to verify the claim that it's clean.
DebugScavengeRoot debug_scavenge_root(this);
oops_do(&debug_scavenge_root);
if (!debug_scavenge_root.ok())
fatal("found an unadvertised bad non-perm oop in the code cache");
}
assert(scavenge_root_not_marked(), "");
}
#endif // PRODUCT
@ -2040,6 +2202,7 @@ void nmethod::print() const {
if (is_not_entrant()) tty->print("not_entrant ");
if (is_zombie()) tty->print("zombie ");
if (is_unloaded()) tty->print("unloaded ");
if (on_scavenge_root_list()) tty->print("scavenge_root ");
tty->print_cr("}:");
}
if (size () > 0) tty->print_cr(" total in heap [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",

View File

@ -125,6 +125,7 @@ class xmlStream;
class nmethod : public CodeBlob {
friend class VMStructs;
friend class NMethodSweeper;
friend class CodeCache; // non-perm oops
private:
// Shared fields for all nmethod's
static int _zombie_instruction_size;
@ -132,7 +133,12 @@ class nmethod : public CodeBlob {
methodOop _method;
int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method
nmethod* _link; // To support simple linked-list chaining of nmethods
// 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
static nmethod* volatile _oops_do_mark_nmethods;
nmethod* volatile _oops_do_mark_link;
AbstractCompiler* _compiler; // The compiler which compiled this nmethod
@ -174,6 +180,8 @@ class nmethod : public CodeBlob {
// used by jvmti to track if an unload event has been posted for this nmethod.
bool _unload_reported;
jbyte _scavenge_root_state;
NOT_PRODUCT(bool _has_debug_info; )
// Nmethod Flushing lock (if non-zero, then the nmethod is not removed)
@ -242,7 +250,6 @@ class nmethod : public CodeBlob {
// helper methods
void* operator new(size_t size, int nmethod_size);
void check_store();
const char* reloc_string_for(u_char* begin, u_char* end);
void make_not_entrant_or_zombie(int state);
@ -406,6 +413,24 @@ class nmethod : public CodeBlob {
int version() const { return flags.version; }
void set_version(int v);
// Non-perm oop support
bool on_scavenge_root_list() const { return (_scavenge_root_state & 1) != 0; }
protected:
enum { npl_on_list = 0x01, npl_marked = 0x10 };
void set_on_scavenge_root_list() { _scavenge_root_state = npl_on_list; }
void clear_on_scavenge_root_list() { _scavenge_root_state = 0; }
// assertion-checking and pruning logic uses the bits of _scavenge_root_state
#ifndef PRODUCT
void set_scavenge_root_marked() { _scavenge_root_state |= npl_marked; }
void clear_scavenge_root_marked() { _scavenge_root_state &= ~npl_marked; }
bool scavenge_root_not_marked() { return (_scavenge_root_state &~ npl_on_list) == 0; }
// N.B. there is no positive marked query, and we only use the not_marked query for asserts.
#endif //PRODUCT
nmethod* scavenge_root_link() const { return _scavenge_root_link; }
void set_scavenge_root_link(nmethod *n) { _scavenge_root_link = n; }
public:
// Sweeper support
long stack_traversal_mark() { return _stack_traversal_mark; }
void set_stack_traversal_mark(long l) { _stack_traversal_mark = l; }
@ -424,8 +449,8 @@ class nmethod : public CodeBlob {
int osr_entry_bci() const { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _entry_bci; }
address osr_entry() const { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _osr_entry_point; }
void invalidate_osr_method();
nmethod* link() const { return _link; }
void set_link(nmethod *n) { _link = n; }
nmethod* osr_link() const { return _osr_link; }
void set_osr_link(nmethod *n) { _osr_link = n; }
// tells whether frames described by this nmethod can be deoptimized
// note: native wrappers cannot be deoptimized.
@ -465,7 +490,16 @@ class nmethod : public CodeBlob {
void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map,
OopClosure* f);
void oops_do(OopClosure* f);
virtual void oops_do(OopClosure* f) { oops_do(f, false); }
void oops_do(OopClosure* f, bool do_strong_roots_only);
bool detect_scavenge_root_oops();
void verify_scavenge_root_oops() PRODUCT_RETURN;
bool test_set_oops_do_mark();
static void oops_do_marking_prologue();
static void oops_do_marking_epilogue();
static bool oops_do_marking_is_active() { return _oops_do_mark_nmethods != NULL; }
DEBUG_ONLY(bool test_oops_do_mark() { return _oops_do_mark_link != NULL; })
// ScopeDesc for an instruction
ScopeDesc* scope_desc_at(address pc);

View File

@ -47,20 +47,15 @@ class MarkRefsIntoClosure: public OopsInGenClosure {
private:
const MemRegion _span;
CMSBitMap* _bitMap;
const bool _should_do_nmethods;
protected:
DO_OOP_WORK_DEFN
public:
MarkRefsIntoClosure(MemRegion span, CMSBitMap* bitMap,
bool should_do_nmethods);
MarkRefsIntoClosure(MemRegion span, CMSBitMap* bitMap);
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
inline void do_oop_nv(oop* p) { MarkRefsIntoClosure::do_oop_work(p); }
inline void do_oop_nv(narrowOop* p) { MarkRefsIntoClosure::do_oop_work(p); }
bool do_header() { return true; }
virtual const bool do_nmethods() const {
return _should_do_nmethods;
}
Prefetch::style prefetch_style() {
return Prefetch::do_read;
}
@ -73,20 +68,16 @@ class MarkRefsIntoVerifyClosure: public OopsInGenClosure {
const MemRegion _span;
CMSBitMap* _verification_bm;
CMSBitMap* _cms_bm;
const bool _should_do_nmethods;
protected:
DO_OOP_WORK_DEFN
public:
MarkRefsIntoVerifyClosure(MemRegion span, CMSBitMap* verification_bm,
CMSBitMap* cms_bm, bool should_do_nmethods);
CMSBitMap* cms_bm);
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
inline void do_oop_nv(oop* p) { MarkRefsIntoVerifyClosure::do_oop_work(p); }
inline void do_oop_nv(narrowOop* p) { MarkRefsIntoVerifyClosure::do_oop_work(p); }
bool do_header() { return true; }
virtual const bool do_nmethods() const {
return _should_do_nmethods;
}
Prefetch::style prefetch_style() {
return Prefetch::do_read;
}
@ -228,7 +219,6 @@ class MarkRefsIntoAndScanClosure: public OopsInGenClosure {
inline void do_oop_nv(oop* p) { MarkRefsIntoAndScanClosure::do_oop_work(p); }
inline void do_oop_nv(narrowOop* p) { MarkRefsIntoAndScanClosure::do_oop_work(p); }
bool do_header() { return true; }
virtual const bool do_nmethods() const { return true; }
Prefetch::style prefetch_style() {
return Prefetch::do_read;
}
@ -273,7 +263,6 @@ class Par_MarkRefsIntoAndScanClosure: public OopsInGenClosure {
inline void do_oop_nv(oop* p) { Par_MarkRefsIntoAndScanClosure::do_oop_work(p); }
inline void do_oop_nv(narrowOop* p) { Par_MarkRefsIntoAndScanClosure::do_oop_work(p); }
bool do_header() { return true; }
virtual const bool do_nmethods() const { return true; }
// When ScanMarkedObjectsAgainClosure is used,
// it passes [Par_]MarkRefsIntoAndScanClosure to oop_oop_iterate(),
// and this delegation is used.

View File

@ -2852,14 +2852,17 @@ void CMSCollector::verify_after_remark_work_1() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
// Mark from roots one level into CMS
MarkRefsIntoClosure notOlder(_span, verification_mark_bm(), true /* nmethods */);
MarkRefsIntoClosure notOlder(_span, verification_mark_bm());
gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
gch->gen_process_strong_roots(_cmsGen->level(),
true, // younger gens are roots
true, // activate StrongRootsScope
true, // collecting perm gen
SharedHeap::ScanningOption(roots_scanning_options()),
NULL, &notOlder);
&notOlder,
true, // walk code active on stacks
NULL);
// Now mark from the roots
assert(_revisitStack.isEmpty(), "Should be empty");
@ -2901,13 +2904,16 @@ void CMSCollector::verify_after_remark_work_2() {
// Mark from roots one level into CMS
MarkRefsIntoVerifyClosure notOlder(_span, verification_mark_bm(),
markBitMap(), true /* nmethods */);
markBitMap());
gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
gch->gen_process_strong_roots(_cmsGen->level(),
true, // younger gens are roots
true, // activate StrongRootsScope
true, // collecting perm gen
SharedHeap::ScanningOption(roots_scanning_options()),
NULL, &notOlder);
&notOlder,
true, // walk code active on stacks
NULL);
// Now mark from the roots
assert(_revisitStack.isEmpty(), "Should be empty");
@ -3484,8 +3490,10 @@ void CMSCollector::checkpointRootsInitialWork(bool asynch) {
FalseClosure falseClosure;
// In the case of a synchronous collection, we will elide the
// remark step, so it's important to catch all the nmethod oops
// in this step; hence the last argument to the constrcutor below.
MarkRefsIntoClosure notOlder(_span, &_markBitMap, !asynch /* nmethods */);
// in this step.
// The final 'true' flag to gen_process_strong_roots will ensure this.
// If 'async' is true, we can relax the nmethod tracing.
MarkRefsIntoClosure notOlder(_span, &_markBitMap);
GenCollectedHeap* gch = GenCollectedHeap::heap();
verify_work_stacks_empty();
@ -3504,9 +3512,12 @@ void CMSCollector::checkpointRootsInitialWork(bool asynch) {
gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
gch->gen_process_strong_roots(_cmsGen->level(),
true, // younger gens are roots
true, // activate StrongRootsScope
true, // collecting perm gen
SharedHeap::ScanningOption(roots_scanning_options()),
NULL, &notOlder);
&notOlder,
true, // walk all of code cache if (so & SO_CodeCache)
NULL);
}
// Clear mod-union table; it will be dirtied in the prologue of
@ -5040,9 +5051,15 @@ void CMSParRemarkTask::work(int i) {
_timer.start();
gch->gen_process_strong_roots(_collector->_cmsGen->level(),
false, // yg was scanned above
false, // this is parallel code
true, // collecting perm gen
SharedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
NULL, &par_mrias_cl);
&par_mrias_cl,
true, // walk all of code cache if (so & SO_CodeCache)
NULL);
assert(_collector->should_unload_classes()
|| (_collector->CMSCollector::roots_scanning_options() & SharedHeap::SO_CodeCache),
"if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops");
_timer.stop();
if (PrintCMSStatistics != 0) {
gclog_or_tty->print_cr(
@ -5423,7 +5440,6 @@ void CMSCollector::do_remark_parallel() {
// Set up for parallel process_strong_roots work.
gch->set_par_threads(n_workers);
gch->change_strong_roots_parity();
// We won't be iterating over the cards in the card table updating
// the younger_gen cards, so we shouldn't call the following else
// the verification code as well as subsequent younger_refs_iterate
@ -5454,8 +5470,10 @@ void CMSCollector::do_remark_parallel() {
if (n_workers > 1) {
// Make refs discovery MT-safe
ReferenceProcessorMTMutator mt(ref_processor(), true);
GenCollectedHeap::StrongRootsScope srs(gch);
workers->run_task(&tsk);
} else {
GenCollectedHeap::StrongRootsScope srs(gch);
tsk.work(0);
}
gch->set_par_threads(0); // 0 ==> non-parallel.
@ -5539,11 +5557,18 @@ void CMSCollector::do_remark_non_parallel() {
verify_work_stacks_empty();
gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
GenCollectedHeap::StrongRootsScope srs(gch);
gch->gen_process_strong_roots(_cmsGen->level(),
true, // younger gens as roots
false, // use the local StrongRootsScope
true, // collecting perm gen
SharedHeap::ScanningOption(roots_scanning_options()),
NULL, &mrias_cl);
&mrias_cl,
true, // walk code active on stacks
NULL);
assert(should_unload_classes()
|| (roots_scanning_options() & SharedHeap::SO_CodeCache),
"if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops");
}
verify_work_stacks_empty();
// Restore evacuated mark words, if any, used for overflow list links
@ -6418,10 +6443,9 @@ void CMSMarkStack::expand() {
// generation then this will lose younger_gen cards!
MarkRefsIntoClosure::MarkRefsIntoClosure(
MemRegion span, CMSBitMap* bitMap, bool should_do_nmethods):
MemRegion span, CMSBitMap* bitMap):
_span(span),
_bitMap(bitMap),
_should_do_nmethods(should_do_nmethods)
_bitMap(bitMap)
{
assert(_ref_processor == NULL, "deliberately left NULL");
assert(_bitMap->covers(_span), "_bitMap/_span mismatch");
@ -6442,12 +6466,11 @@ void MarkRefsIntoClosure::do_oop(narrowOop* p) { MarkRefsIntoClosure::do_oop_wor
// A variant of the above, used for CMS marking verification.
MarkRefsIntoVerifyClosure::MarkRefsIntoVerifyClosure(
MemRegion span, CMSBitMap* verification_bm, CMSBitMap* cms_bm,
bool should_do_nmethods):
MemRegion span, CMSBitMap* verification_bm, CMSBitMap* cms_bm):
_span(span),
_verification_bm(verification_bm),
_cms_bm(cms_bm),
_should_do_nmethods(should_do_nmethods) {
_cms_bm(cms_bm)
{
assert(_ref_processor == NULL, "deliberately left NULL");
assert(_verification_bm->covers(_span), "_verification_bm/_span mismatch");
}

View File

@ -746,10 +746,11 @@ void ConcurrentMark::checkpointRootsInitialPre() {
// clear the mark bitmap (no grey objects to start with)
_nextMarkBitMap->clearAll();
PrintReachableClosure prcl(_nextMarkBitMap);
g1h->process_strong_roots(
g1h->process_strong_roots(true, // activate StrongRootsScope
false, // fake perm gen collection
SharedHeap::SO_AllClasses,
&prcl, // Regular roots
NULL, // do not visit active blobs
&prcl // Perm Gen Roots
);
// The root iteration above "consumed" dirty cards in the perm gen.
@ -852,9 +853,11 @@ void ConcurrentMark::checkpointRootsInitial() {
g1h->set_marking_started();
g1h->rem_set()->prepare_for_younger_refs_iterate(false);
g1h->process_strong_roots(false, // fake perm gen collection
g1h->process_strong_roots(true, // activate StrongRootsScope
false, // fake perm gen collection
SharedHeap::SO_AllClasses,
&notOlder, // Regular roots
NULL, // do not visit active blobs
&older // Perm Gen Roots
);
checkpointRootsInitialPost();
@ -1915,7 +1918,7 @@ void ConcurrentMark::checkpointRootsFinalWork() {
g1h->ensure_parsability(false);
if (ParallelGCThreads > 0) {
g1h->change_strong_roots_parity();
G1CollectedHeap::StrongRootsScope srs(g1h);
// this is remark, so we'll use up all available threads
int active_workers = ParallelGCThreads;
set_phase(active_workers, false);
@ -1932,7 +1935,7 @@ void ConcurrentMark::checkpointRootsFinalWork() {
SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
guarantee( satb_mq_set.completed_buffers_num() == 0, "invariant" );
} else {
g1h->change_strong_roots_parity();
G1CollectedHeap::StrongRootsScope srs(g1h);
// this is remark, so we'll use up all available threads
int active_workers = 1;
set_phase(active_workers, false);

View File

@ -2300,9 +2300,12 @@ void G1CollectedHeap::verify(bool allow_dirty,
if (SafepointSynchronize::is_at_safepoint() || ! UseTLAB) {
if (!silent) { gclog_or_tty->print("roots "); }
VerifyRootsClosure rootsCl(use_prev_marking);
process_strong_roots(false,
CodeBlobToOopClosure blobsCl(&rootsCl, /*do_marking=*/ false);
process_strong_roots(true, // activate StrongRootsScope
false,
SharedHeap::SO_AllClasses,
&rootsCl,
&blobsCl,
&rootsCl);
rem_set()->invalidate(perm_gen()->used_region(), false);
if (!silent) { gclog_or_tty->print("heapRegions "); }
@ -3987,8 +3990,14 @@ g1_process_strong_roots(bool collecting_perm_gen,
BufferingOopsInGenClosure buf_scan_perm(scan_perm);
buf_scan_perm.set_generation(perm_gen());
process_strong_roots(collecting_perm_gen, so,
// Walk the code cache w/o buffering, because StarTask cannot handle
// unaligned oop locations.
CodeBlobToOopClosure eager_scan_code_roots(scan_non_heap_roots, /*do_marking=*/ true);
process_strong_roots(false, // no scoping; this is parallel code
collecting_perm_gen, so,
&buf_scan_non_heap_roots,
&eager_scan_code_roots,
&buf_scan_perm);
// Finish up any enqueued closure apps.
buf_scan_non_heap_roots.done();
@ -4078,7 +4087,8 @@ G1CollectedHeap::scan_scan_only_set(OopsInHeapRegionClosure* oc,
void
G1CollectedHeap::g1_process_weak_roots(OopClosure* root_closure,
OopClosure* non_root_closure) {
SharedHeap::process_weak_roots(root_closure, non_root_closure);
CodeBlobToOopClosure roots_in_blobs(root_closure, /*do_marking=*/ false);
SharedHeap::process_weak_roots(root_closure, &roots_in_blobs, non_root_closure);
}
@ -4112,15 +4122,16 @@ void G1CollectedHeap::evacuate_collection_set() {
init_for_evac_failure(NULL);
change_strong_roots_parity(); // In preparation for parallel strong roots.
rem_set()->prepare_for_younger_refs_iterate(true);
assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty");
double start_par = os::elapsedTime();
if (ParallelGCThreads > 0) {
// The individual threads will set their evac-failure closures.
StrongRootsScope srs(this);
workers()->run_task(&g1_par_task);
} else {
StrongRootsScope srs(this);
g1_par_task.work(0);
}

View File

@ -121,9 +121,11 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading,
SharedHeap* sh = SharedHeap::heap();
sh->process_strong_roots(true, // Collecting permanent generation.
sh->process_strong_roots(true, // activeate StrongRootsScope
true, // Collecting permanent generation.
SharedHeap::SO_SystemClasses,
&GenMarkSweep::follow_root_closure,
&GenMarkSweep::follow_code_root_closure,
&GenMarkSweep::follow_root_closure);
// Process reference objects found during marking
@ -286,9 +288,11 @@ void G1MarkSweep::mark_sweep_phase3() {
SharedHeap* sh = SharedHeap::heap();
sh->process_strong_roots(true, // Collecting permanent generation.
sh->process_strong_roots(true, // activate StrongRootsScope
true, // Collecting permanent generation.
SharedHeap::SO_AllClasses,
&GenMarkSweep::adjust_root_pointer_closure,
NULL, // do not touch code cache here
&GenMarkSweep::adjust_pointer_closure);
g1h->ref_processor()->weak_oops_do(&GenMarkSweep::adjust_root_pointer_closure);

View File

@ -373,6 +373,7 @@ psScavenge.inline.hpp parallelScavengeHeap.hpp
psScavenge.inline.hpp psPromotionManager.hpp
psScavenge.inline.hpp psScavenge.hpp
pcTasks.cpp codeCache.hpp
pcTasks.cpp collectedHeap.hpp
pcTasks.cpp fprofiler.hpp
pcTasks.cpp jniHandles.hpp
@ -392,6 +393,7 @@ pcTasks.hpp gcTaskManager.hpp
pcTasks.hpp psTasks.hpp
psTasks.cpp cardTableExtension.hpp
psTasks.cpp codeCache.hpp
psTasks.cpp fprofiler.hpp
psTasks.cpp gcTaskManager.hpp
psTasks.cpp iterator.hpp

View File

@ -480,12 +480,14 @@ void ParNewGenTask::work(int i) {
par_scan_state.start_strong_roots();
gch->gen_process_strong_roots(_gen->level(),
true, // Process younger gens, if any,
// as strong roots.
false,// not collecting perm generation.
true, // Process younger gens, if any,
// as strong roots.
false, // no scope; this is parallel code
false, // not collecting perm generation.
SharedHeap::SO_AllClasses,
&par_scan_state.older_gen_closure(),
&par_scan_state.to_space_root_closure());
&par_scan_state.to_space_root_closure(),
true, // walk *all* scavengable nmethods
&par_scan_state.older_gen_closure());
par_scan_state.end_strong_roots();
// "evacuate followers".
@ -799,15 +801,16 @@ void ParNewGeneration::collect(bool full,
ParNewGenTask tsk(this, _next_gen, reserved().end(), &thread_state_set);
int n_workers = workers->total_workers();
gch->set_par_threads(n_workers);
gch->change_strong_roots_parity();
gch->rem_set()->prepare_for_younger_refs_iterate(true);
// It turns out that even when we're using 1 thread, doing the work in a
// separate thread causes wide variance in run times. We can't help this
// in the multi-threaded case, but we special-case n=1 here to get
// repeatable measurements of the 1-thread overhead of the parallel code.
if (n_workers > 1) {
GenCollectedHeap::StrongRootsScope srs(gch);
workers->run_task(&tsk);
} else {
GenCollectedHeap::StrongRootsScope srs(gch);
tsk.work(0);
}
thread_state_set.reset();

View File

@ -962,6 +962,14 @@ void ParallelScavengeHeap::resize_old_gen(size_t desired_free_space) {
_old_gen->resize(desired_free_space);
}
ParallelScavengeHeap::ParStrongRootsScope::ParStrongRootsScope() {
// nothing particular
}
ParallelScavengeHeap::ParStrongRootsScope::~ParStrongRootsScope() {
// nothing particular
}
#ifndef PRODUCT
void ParallelScavengeHeap::record_gen_tops_before_GC() {
if (ZapUnusedHeapArea) {

View File

@ -234,6 +234,13 @@ class ParallelScavengeHeap : public CollectedHeap {
// Mangle the unused parts of all spaces in the heap
void gen_mangle_unused_area() PRODUCT_RETURN;
// Call these in sequential code around the processing of strong roots.
class ParStrongRootsScope : public MarkingCodeBlobClosure::MarkScope {
public:
ParStrongRootsScope();
~ParStrongRootsScope();
};
};
inline size_t ParallelScavengeHeap::set_alignment(size_t& var, size_t val)

View File

@ -39,12 +39,13 @@ void ThreadRootsMarkingTask::do_it(GCTaskManager* manager, uint which) {
ParCompactionManager* cm =
ParCompactionManager::gc_thread_compaction_manager(which);
PSParallelCompact::MarkAndPushClosure mark_and_push_closure(cm);
CodeBlobToOopClosure mark_and_push_in_blobs(&mark_and_push_closure, /*do_marking=*/ true);
if (_java_thread != NULL)
_java_thread->oops_do(&mark_and_push_closure);
_java_thread->oops_do(&mark_and_push_closure, &mark_and_push_in_blobs);
if (_vm_thread != NULL)
_vm_thread->oops_do(&mark_and_push_closure);
_vm_thread->oops_do(&mark_and_push_closure, &mark_and_push_in_blobs);
// Do the real work
cm->drain_marking_stacks(&mark_and_push_closure);
@ -78,7 +79,8 @@ void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) {
case threads:
{
ResourceMark rm;
Threads::oops_do(&mark_and_push_closure);
CodeBlobToOopClosure each_active_code_blob(&mark_and_push_closure, /*do_marking=*/ true);
Threads::oops_do(&mark_and_push_closure, &each_active_code_blob);
}
break;
@ -106,6 +108,11 @@ void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) {
vmSymbols::oops_do(&mark_and_push_closure);
break;
case code_cache:
// Do not treat nmethods as strong roots for mark/sweep, since we can unload them.
//CodeCache::scavenge_root_nmethods_do(CodeBlobToOopClosure(&mark_and_push_closure));
break;
default:
fatal("Unknown root type");
}

View File

@ -92,7 +92,8 @@ class MarkFromRootsTask : public GCTask {
jvmti = 7,
system_dictionary = 8,
vm_symbols = 9,
reference_processing = 10
reference_processing = 10,
code_cache = 11
};
private:
RootType _root_type;

View File

@ -511,16 +511,22 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
// General strong roots.
Universe::oops_do(mark_and_push_closure());
ReferenceProcessor::oops_do(mark_and_push_closure());
JNIHandles::oops_do(mark_and_push_closure()); // Global (strong) JNI handles
Threads::oops_do(mark_and_push_closure());
ObjectSynchronizer::oops_do(mark_and_push_closure());
FlatProfiler::oops_do(mark_and_push_closure());
Management::oops_do(mark_and_push_closure());
JvmtiExport::oops_do(mark_and_push_closure());
SystemDictionary::always_strong_oops_do(mark_and_push_closure());
vmSymbols::oops_do(mark_and_push_closure());
{
ParallelScavengeHeap::ParStrongRootsScope psrs;
Universe::oops_do(mark_and_push_closure());
ReferenceProcessor::oops_do(mark_and_push_closure());
JNIHandles::oops_do(mark_and_push_closure()); // Global (strong) JNI handles
CodeBlobToOopClosure each_active_code_blob(mark_and_push_closure(), /*do_marking=*/ true);
Threads::oops_do(mark_and_push_closure(), &each_active_code_blob);
ObjectSynchronizer::oops_do(mark_and_push_closure());
FlatProfiler::oops_do(mark_and_push_closure());
Management::oops_do(mark_and_push_closure());
JvmtiExport::oops_do(mark_and_push_closure());
SystemDictionary::always_strong_oops_do(mark_and_push_closure());
vmSymbols::oops_do(mark_and_push_closure());
// Do not treat nmethods as strong roots for mark/sweep, since we can unload them.
//CodeCache::scavenge_root_nmethods_do(CodeBlobToOopClosure(mark_and_push_closure()));
}
// Flush marking stack.
follow_stack();
@ -617,7 +623,7 @@ void PSMarkSweep::mark_sweep_phase3() {
Universe::oops_do(adjust_root_pointer_closure());
ReferenceProcessor::oops_do(adjust_root_pointer_closure());
JNIHandles::oops_do(adjust_root_pointer_closure()); // Global (strong) JNI handles
Threads::oops_do(adjust_root_pointer_closure());
Threads::oops_do(adjust_root_pointer_closure(), NULL);
ObjectSynchronizer::oops_do(adjust_root_pointer_closure());
FlatProfiler::oops_do(adjust_root_pointer_closure());
Management::oops_do(adjust_root_pointer_closure());
@ -625,6 +631,7 @@ void PSMarkSweep::mark_sweep_phase3() {
// SO_AllClasses
SystemDictionary::oops_do(adjust_root_pointer_closure());
vmSymbols::oops_do(adjust_root_pointer_closure());
//CodeCache::scavenge_root_nmethods_oops_do(adjust_root_pointer_closure());
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)

View File

@ -2322,6 +2322,7 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
{
TraceTime tm_m("par mark", print_phases(), true, gclog_or_tty);
ParallelScavengeHeap::ParStrongRootsScope psrs;
GCTaskQueue* q = GCTaskQueue::create();
@ -2335,6 +2336,7 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::system_dictionary));
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::jvmti));
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::vm_symbols));
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::code_cache));
if (parallel_gc_threads > 1) {
for (uint j = 0; j < parallel_gc_threads; j++) {
@ -2408,7 +2410,7 @@ void PSParallelCompact::adjust_roots() {
Universe::oops_do(adjust_root_pointer_closure());
ReferenceProcessor::oops_do(adjust_root_pointer_closure());
JNIHandles::oops_do(adjust_root_pointer_closure()); // Global (strong) JNI handles
Threads::oops_do(adjust_root_pointer_closure());
Threads::oops_do(adjust_root_pointer_closure(), NULL);
ObjectSynchronizer::oops_do(adjust_root_pointer_closure());
FlatProfiler::oops_do(adjust_root_pointer_closure());
Management::oops_do(adjust_root_pointer_closure());

View File

@ -799,8 +799,7 @@ class PSParallelCompact : AllStatic {
FollowRootClosure(ParCompactionManager* cm) : _compaction_manager(cm) { }
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
virtual const bool do_nmethods() const { return true; }
};
};
class FollowStackClosure: public VoidClosure {
private:
@ -817,6 +816,8 @@ class PSParallelCompact : AllStatic {
AdjustPointerClosure(bool is_root) : _is_root(is_root) { }
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
// do not walk from thread stacks to the code cache on this phase
virtual void do_code_blob(CodeBlob* cb) const { }
};
// Closure for verifying update of pointers. Does not
@ -1063,7 +1064,6 @@ class PSParallelCompact : AllStatic {
MarkAndPushClosure(ParCompactionManager* cm) : _compaction_manager(cm) { }
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
virtual const bool do_nmethods() const { return true; }
};
PSParallelCompact();

View File

@ -358,6 +358,7 @@ bool PSScavenge::invoke_no_policy() {
PSPromotionManager* promotion_manager = PSPromotionManager::vm_thread_promotion_manager();
{
// TraceTime("Roots");
ParallelScavengeHeap::ParStrongRootsScope psrs;
GCTaskQueue* q = GCTaskQueue::create();
@ -376,6 +377,7 @@ bool PSScavenge::invoke_no_policy() {
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::management));
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::system_dictionary));
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::jvmti));
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::code_cache));
ParallelTaskTerminator terminator(
gc_task_manager()->workers(),

View File

@ -66,7 +66,7 @@ void ScavengeRootsTask::do_it(GCTaskManager* manager, uint which) {
case threads:
{
ResourceMark rm;
Threads::oops_do(&roots_closure);
Threads::oops_do(&roots_closure, NULL);
}
break;
@ -90,6 +90,14 @@ void ScavengeRootsTask::do_it(GCTaskManager* manager, uint which) {
JvmtiExport::oops_do(&roots_closure);
break;
case code_cache:
{
CodeBlobToOopClosure each_scavengable_code_blob(&roots_closure, /*do_marking=*/ true);
CodeCache::scavenge_root_nmethods_do(&each_scavengable_code_blob);
}
break;
default:
fatal("Unknown root type");
}
@ -107,12 +115,13 @@ void ThreadRootsTask::do_it(GCTaskManager* manager, uint which) {
PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(which);
PSScavengeRootsClosure roots_closure(pm);
CodeBlobToOopClosure roots_in_blobs(&roots_closure, /*do_marking=*/ true);
if (_java_thread != NULL)
_java_thread->oops_do(&roots_closure);
_java_thread->oops_do(&roots_closure, &roots_in_blobs);
if (_vm_thread != NULL)
_vm_thread->oops_do(&roots_closure);
_vm_thread->oops_do(&roots_closure, &roots_in_blobs);
// Do the real work
pm->drain_stacks(false);

View File

@ -54,7 +54,8 @@ class ScavengeRootsTask : public GCTask {
flat_profiler = 5,
system_dictionary = 6,
management = 7,
jvmti = 8
jvmti = 8,
code_cache = 9
};
private:
RootType _root_type;

View File

@ -93,6 +93,7 @@ void MarkSweep::follow_mdo_weak_refs() {
}
MarkSweep::FollowRootClosure MarkSweep::follow_root_closure;
CodeBlobToOopClosure MarkSweep::follow_code_root_closure(&MarkSweep::follow_root_closure, /*do_marking=*/ true);
void MarkSweep::FollowRootClosure::do_oop(oop* p) { follow_root(p); }
void MarkSweep::FollowRootClosure::do_oop(narrowOop* p) { follow_root(p); }

View File

@ -58,14 +58,12 @@ class MarkSweep : AllStatic {
public:
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
virtual const bool do_nmethods() const { return true; }
};
class MarkAndPushClosure: public OopClosure {
public:
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
virtual const bool do_nmethods() const { return true; }
virtual const bool should_remember_mdo() const { return true; }
virtual void remember_mdo(DataLayout* p) { MarkSweep::revisit_mdo(p); }
};
@ -173,6 +171,7 @@ class MarkSweep : AllStatic {
public:
// Public closures
static FollowRootClosure follow_root_closure;
static CodeBlobToOopClosure follow_code_root_closure; // => follow_root_closure
static MarkAndPushClosure mark_and_push_closure;
static FollowStackClosure follow_stack_closure;
static AdjustPointerClosure adjust_root_pointer_closure;

View File

@ -263,6 +263,14 @@ class CollectedHeap : public CHeapObj {
return p == NULL || is_permanent(p);
}
// An object is scavengable if its location may move during a scavenge.
// (A scavenge is a GC which is not a full GC.)
// Currently, this just means it is not perm (and not null).
// This could change if we rethink what's in perm-gen.
bool is_scavengable(const void *p) const {
return !is_in_permanent_or_null(p);
}
// Returns "TRUE" if "p" is a method oop in the
// current heap, with high probability. This predicate
// is not stable, in general.

View File

@ -555,12 +555,14 @@ void DefNewGeneration::collect(bool full,
"save marks have not been newly set.");
gch->gen_process_strong_roots(_level,
true, // Process younger gens, if any, as
// strong roots.
false,// not collecting permanent generation.
true, // Process younger gens, if any,
// as strong roots.
true, // activate StrongRootsScope
false, // not collecting perm generation.
SharedHeap::SO_AllClasses,
&fsc_with_gc_barrier,
&fsc_with_no_gc_barrier);
&fsc_with_no_gc_barrier,
true, // walk *all* scavengable nmethods
&fsc_with_gc_barrier);
// "evacuate followers".
evacuate_followers.do_void();

View File

@ -677,13 +677,23 @@ static AssertIsPermClosure assert_is_perm_closure;
void GenCollectedHeap::
gen_process_strong_roots(int level,
bool younger_gens_as_roots,
bool activate_scope,
bool collecting_perm_gen,
SharedHeap::ScanningOption so,
OopsInGenClosure* older_gens,
OopsInGenClosure* not_older_gens) {
OopsInGenClosure* not_older_gens,
bool do_code_roots,
OopsInGenClosure* older_gens) {
// General strong roots.
SharedHeap::process_strong_roots(collecting_perm_gen, so,
not_older_gens, older_gens);
if (!do_code_roots) {
SharedHeap::process_strong_roots(activate_scope, collecting_perm_gen, so,
not_older_gens, NULL, older_gens);
} else {
bool do_code_marking = (activate_scope || nmethod::oops_do_marking_is_active());
CodeBlobToOopClosure code_roots(not_older_gens, /*do_marking=*/ do_code_marking);
SharedHeap::process_strong_roots(activate_scope, collecting_perm_gen, so,
not_older_gens, &code_roots, older_gens);
}
if (younger_gens_as_roots) {
if (!_gen_process_strong_tasks->is_task_claimed(GCH_PS_younger_gens)) {
@ -706,8 +716,9 @@ gen_process_strong_roots(int level,
}
void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure,
CodeBlobClosure* code_roots,
OopClosure* non_root_closure) {
SharedHeap::process_weak_roots(root_closure, non_root_closure);
SharedHeap::process_weak_roots(root_closure, code_roots, non_root_closure);
// "Local" "weak" refs
for (int i = 0; i < _n_gens; i++) {
_gens[i]->ref_processor()->weak_oops_do(root_closure);

View File

@ -408,16 +408,22 @@ public:
// "SO_SystemClasses" to all the "system" classes and loaders;
// "SO_Symbols_and_Strings" applies the closure to all entries in
// SymbolsTable and StringTable.
void gen_process_strong_roots(int level, bool younger_gens_as_roots,
void gen_process_strong_roots(int level,
bool younger_gens_as_roots,
// The remaining arguments are in an order
// consistent with SharedHeap::process_strong_roots:
bool activate_scope,
bool collecting_perm_gen,
SharedHeap::ScanningOption so,
OopsInGenClosure* older_gens,
OopsInGenClosure* not_older_gens);
OopsInGenClosure* not_older_gens,
bool do_code_roots,
OopsInGenClosure* older_gens);
// Apply "blk" to all the weak roots of the system. These include
// JNI weak roots, the code cache, system dictionary, symbol table,
// string table, and referents of reachable weak refs.
void gen_process_weak_roots(OopClosure* root_closure,
CodeBlobClosure* code_roots,
OopClosure* non_root_closure);
// Set the saved marks of generations, if that makes sense.

View File

@ -244,9 +244,12 @@ void GenMarkSweep::mark_sweep_phase1(int level,
gch->gen_process_strong_roots(level,
false, // Younger gens are not roots.
true, // activate StrongRootsScope
true, // Collecting permanent generation.
SharedHeap::SO_SystemClasses,
&follow_root_closure, &follow_root_closure);
&follow_root_closure,
true, // walk code active on stacks
&follow_root_closure);
// Process reference objects found during marking
{
@ -338,14 +341,19 @@ void GenMarkSweep::mark_sweep_phase3(int level) {
gch->gen_process_strong_roots(level,
false, // Younger gens are not roots.
true, // activate StrongRootsScope
true, // Collecting permanent generation.
SharedHeap::SO_AllClasses,
&adjust_root_pointer_closure,
false, // do not walk code
&adjust_root_pointer_closure);
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
CodeBlobToOopClosure adjust_code_pointer_closure(&adjust_pointer_closure,
/*do_marking=*/ false);
gch->gen_process_weak_roots(&adjust_root_pointer_closure,
&adjust_code_pointer_closure,
&adjust_pointer_closure);
adjust_marks();

View File

@ -46,3 +46,42 @@ void OopClosure::set_must_remember_klasses(bool v) {
}
#endif
MarkingCodeBlobClosure::MarkScope::MarkScope(bool activate)
: _active(activate)
{
if (_active) nmethod::oops_do_marking_prologue();
}
MarkingCodeBlobClosure::MarkScope::~MarkScope() {
if (_active) nmethod::oops_do_marking_epilogue();
}
void MarkingCodeBlobClosure::do_code_blob(CodeBlob* cb) {
if (!cb->is_nmethod()) return;
nmethod* nm = (nmethod*) cb;
if (!nm->test_set_oops_do_mark()) {
NOT_PRODUCT(if (TraceScavenge) nm->print_on(tty, "oops_do, 1st visit\n"));
do_newly_marked_nmethod(nm);
} else {
NOT_PRODUCT(if (TraceScavenge) nm->print_on(tty, "oops_do, skipped on 2nd visit\n"));
}
}
void CodeBlobToOopClosure::do_newly_marked_nmethod(nmethod* nm) {
nm->oops_do(_cl, /*do_strong_roots_only=*/ true);
}
void CodeBlobToOopClosure::do_code_blob(CodeBlob* cb) {
if (!_do_marking) {
NOT_PRODUCT(if (TraceScavenge && Verbose && cb->is_nmethod()) ((nmethod*)cb)->print_on(tty, "oops_do, unmarked visit\n"));
// This assert won't work, since there are lots of mini-passes
// (mostly in debug mode) that co-exist with marking phases.
//assert(!(cb->is_nmethod() && ((nmethod*)cb)->test_oops_do_mark()), "found marked nmethod during mark-free phase");
cb->oops_do(_cl);
} else {
MarkingCodeBlobClosure::do_code_blob(cb);
}
}

View File

@ -24,6 +24,8 @@
// The following classes are C++ `closures` for iterating over objects, roots and spaces
class CodeBlob;
class nmethod;
class ReferenceProcessor;
class DataLayout;
@ -69,9 +71,6 @@ class OopClosure : public Closure {
virtual const bool should_remember_mdo() const { return false; }
virtual void remember_mdo(DataLayout* v) { /* do nothing */ }
// If "true", invoke on nmethods (when scanning compiled frames).
virtual const bool do_nmethods() const { return false; }
// The methods below control how object iterations invoking this closure
// should be performed:
@ -176,6 +175,51 @@ class CompactibleSpaceClosure : public StackObj {
};
// CodeBlobClosure is used for iterating through code blobs
// in the code cache or on thread stacks
class CodeBlobClosure : public Closure {
public:
// Called for each code blob.
virtual void do_code_blob(CodeBlob* cb) = 0;
};
class MarkingCodeBlobClosure : public CodeBlobClosure {
public:
// Called for each code blob, but at most once per unique blob.
virtual void do_newly_marked_nmethod(nmethod* nm) = 0;
virtual void do_code_blob(CodeBlob* cb);
// = { if (!nmethod(cb)->test_set_oops_do_mark()) do_newly_marked_nmethod(cb); }
class MarkScope : public StackObj {
protected:
bool _active;
public:
MarkScope(bool activate = true);
// = { if (active) nmethod::oops_do_marking_prologue(); }
~MarkScope();
// = { if (active) nmethod::oops_do_marking_epilogue(); }
};
};
// Applies an oop closure to all ref fields in code blobs
// iterated over in an object iteration.
class CodeBlobToOopClosure: public MarkingCodeBlobClosure {
OopClosure* _cl;
bool _do_marking;
public:
virtual void do_newly_marked_nmethod(nmethod* cb);
// = { cb->oops_do(_cl); }
virtual void do_code_blob(CodeBlob* cb);
// = { if (_do_marking) super::do_code_blob(cb); else cb->oops_do(_cl); }
CodeBlobToOopClosure(OopClosure* cl, bool do_marking)
: _cl(cl), _do_marking(do_marking) {}
};
// MonitorClosure is used for iterating over monitors in the monitors cache

View File

@ -100,12 +100,27 @@ void SharedHeap::change_strong_roots_parity() {
"Not in range.");
}
void SharedHeap::process_strong_roots(bool collecting_perm_gen,
SharedHeap::StrongRootsScope::StrongRootsScope(SharedHeap* outer, bool activate)
: MarkScope(activate)
{
if (_active) {
outer->change_strong_roots_parity();
}
}
SharedHeap::StrongRootsScope::~StrongRootsScope() {
// nothing particular
}
void SharedHeap::process_strong_roots(bool activate_scope,
bool collecting_perm_gen,
ScanningOption so,
OopClosure* roots,
CodeBlobClosure* code_roots,
OopsInGenClosure* perm_blk) {
StrongRootsScope srs(this, activate_scope);
// General strong roots.
if (n_par_threads() == 0) change_strong_roots_parity();
assert(_strong_roots_parity != 0, "must have called prologue code");
if (!_process_strong_tasks->is_task_claimed(SH_PS_Universe_oops_do)) {
Universe::oops_do(roots);
ReferenceProcessor::oops_do(roots);
@ -117,9 +132,9 @@ void SharedHeap::process_strong_roots(bool collecting_perm_gen,
JNIHandles::oops_do(roots);
// All threads execute this; the individual threads are task groups.
if (ParallelGCThreads > 0) {
Threads::possibly_parallel_oops_do(roots);
Threads::possibly_parallel_oops_do(roots, code_roots);
} else {
Threads::oops_do(roots);
Threads::oops_do(roots, code_roots);
}
if (!_process_strong_tasks-> is_task_claimed(SH_PS_ObjectSynchronizer_oops_do))
ObjectSynchronizer::oops_do(roots);
@ -156,11 +171,29 @@ void SharedHeap::process_strong_roots(bool collecting_perm_gen,
}
if (!_process_strong_tasks->is_task_claimed(SH_PS_CodeCache_oops_do)) {
if (so & SO_CodeCache) {
CodeCache::oops_do(roots);
}
if (so & SO_CodeCache) {
// (Currently, CMSCollector uses this to do intermediate-strength collections.)
assert(collecting_perm_gen, "scanning all of code cache");
assert(code_roots != NULL, "must supply closure for code cache");
if (code_roots != NULL) {
CodeCache::blobs_do(code_roots);
}
} else if (so & (SO_SystemClasses|SO_AllClasses)) {
if (!collecting_perm_gen) {
// If we are collecting from class statics, but we are not going to
// visit all of the CodeCache, collect from the non-perm roots if any.
// This makes the code cache function temporarily as a source of strong
// roots for oops, until the next major collection.
//
// If collecting_perm_gen is true, we require that this phase will call
// CodeCache::do_unloading. This will kill off nmethods with expired
// weak references, such as stale invokedynamic targets.
CodeCache::scavenge_root_nmethods_do(code_roots);
}
}
// Verify if the code cache contents are in the perm gen
NOT_PRODUCT(CodeCache::oops_do(&assert_is_perm_closure));
NOT_PRODUCT(CodeBlobToOopClosure assert_code_is_perm(&assert_is_perm_closure, /*do_marking=*/ false));
NOT_PRODUCT(CodeCache::asserted_non_scavengable_nmethods_do(&assert_code_is_perm));
}
// Roots that should point only into permanent generation.
@ -220,11 +253,12 @@ public:
// just skip adjusting any shared entries in the string table.
void SharedHeap::process_weak_roots(OopClosure* root_closure,
CodeBlobClosure* code_roots,
OopClosure* non_root_closure) {
// Global (weak) JNI handles
JNIHandles::weak_oops_do(&always_true, root_closure);
CodeCache::oops_do(non_root_closure);
CodeCache::blobs_do(code_roots);
SymbolTable::oops_do(root_closure);
if (UseSharedSpaces && !DumpSharedSpaces) {
SkipAdjustingSharedStrings skip_closure(root_closure);

View File

@ -165,9 +165,21 @@ public:
// c) to never return a distinguished value (zero) with which such
// task-claiming variables may be initialized, to indicate "never
// claimed".
private:
void change_strong_roots_parity();
public:
int strong_roots_parity() { return _strong_roots_parity; }
// Call these in sequential code around process_strong_roots.
// strong_roots_prologue calls change_strong_roots_parity, if
// parallel tasks are enabled.
class StrongRootsScope : public MarkingCodeBlobClosure::MarkScope {
public:
StrongRootsScope(SharedHeap* outer, bool activate = true);
~StrongRootsScope();
};
friend class StrongRootsScope;
enum ScanningOption {
SO_None = 0x0,
SO_AllClasses = 0x1,
@ -198,15 +210,18 @@ public:
// "SO_Symbols" applies the closure to all entries in SymbolsTable;
// "SO_Strings" applies the closure to all entries in StringTable;
// "SO_CodeCache" applies the closure to all elements of the CodeCache.
void process_strong_roots(bool collecting_perm_gen,
void process_strong_roots(bool activate_scope,
bool collecting_perm_gen,
ScanningOption so,
OopClosure* roots,
CodeBlobClosure* code_roots,
OopsInGenClosure* perm_blk);
// Apply "blk" to all the weak roots of the system. These include
// JNI weak roots, the code cache, system dictionary, symbol table,
// string table.
void process_weak_roots(OopClosure* root_closure,
CodeBlobClosure* code_roots,
OopClosure* non_root_closure);

View File

@ -2152,7 +2152,7 @@ void instanceKlass::add_osr_nmethod(nmethod* n) {
// This is a short non-blocking critical region, so the no safepoint check is ok.
OsrList_lock->lock_without_safepoint_check();
assert(n->is_osr_method(), "wrong kind of nmethod");
n->set_link(osr_nmethods_head());
n->set_osr_link(osr_nmethods_head());
set_osr_nmethods_head(n);
// Remember to unlock again
OsrList_lock->unlock();
@ -2168,17 +2168,17 @@ void instanceKlass::remove_osr_nmethod(nmethod* n) {
// Search for match
while(cur != NULL && cur != n) {
last = cur;
cur = cur->link();
cur = cur->osr_link();
}
if (cur == n) {
if (last == NULL) {
// Remove first element
set_osr_nmethods_head(osr_nmethods_head()->link());
set_osr_nmethods_head(osr_nmethods_head()->osr_link());
} else {
last->set_link(cur->link());
last->set_osr_link(cur->osr_link());
}
}
n->set_link(NULL);
n->set_osr_link(NULL);
// Remember to unlock again
OsrList_lock->unlock();
}
@ -2195,7 +2195,7 @@ nmethod* instanceKlass::lookup_osr_nmethod(const methodOop m, int bci) const {
OsrList_lock->unlock();
return osr;
}
osr = osr->link();
osr = osr->osr_link();
}
OsrList_lock->unlock();
return NULL;

View File

@ -330,6 +330,7 @@ class oopDesc {
bool is_perm() const;
bool is_perm_or_null() const;
bool is_scavengable() const;
bool is_shared() const;
bool is_shared_readonly() const;
bool is_shared_readwrite() const;

View File

@ -34,3 +34,7 @@ inline bool oopDesc::is_perm() const {
inline bool oopDesc::is_perm_or_null() const {
return this == NULL || is_perm();
}
inline bool oopDesc::is_scavengable() const {
return Universe::heap()->is_scavengable(this);
}

View File

@ -1085,6 +1085,9 @@ Node *CastX2PNode::Ideal(PhaseGVN *phase, bool can_reshape) {
switch (op) {
case Op_SubX:
x = in(1)->in(1);
// Avoid ideal transformations ping-pong between this and AddP for raw pointers.
if (phase->find_intptr_t_con(x, -1) == 0)
break;
y = in(1)->in(2);
if (fits_in_int(phase->type(y), true)) {
return addP_of_X2P(phase, x, y, true);

View File

@ -524,12 +524,15 @@ bool ConnectionGraph::split_AddP(Node *addp, Node *base, PhaseGVN *igvn) {
// inlining) which was not eliminated during parsing since the exactness
// of the allocation type was not propagated to the subclass type check.
//
// Or the type 't' could be not related to 'base_t' at all.
// It could happened when CHA type is different from MDO type on a dead path
// (for example, from instanceof check) which is not collapsed during parsing.
//
// Do nothing for such AddP node and don't process its users since
// this code branch will go away.
//
if (!t->is_known_instance() &&
!t->klass()->equals(base_t->klass()) &&
t->klass()->is_subtype_of(base_t->klass())) {
!base_t->klass()->is_subtype_of(t->klass())) {
return false; // bail out
}

View File

@ -1450,7 +1450,7 @@ void GraphKit::post_barrier(Node* ctl,
case BarrierSet::CardTableModRef:
case BarrierSet::CardTableExtension:
write_barrier_post(store, obj, adr, val, use_precise);
write_barrier_post(store, obj, adr, adr_idx, val, use_precise);
break;
case BarrierSet::ModRef:
@ -3165,6 +3165,7 @@ void GraphKit::sync_kit(IdealKit& ideal) {
void GraphKit::write_barrier_post(Node* oop_store,
Node* obj,
Node* adr,
uint adr_idx,
Node* val,
bool use_precise) {
// No store check needed if we're storing a NULL or an old object
@ -3214,7 +3215,7 @@ void GraphKit::write_barrier_post(Node* oop_store,
__ store(__ ctrl(), card_adr, zero, bt, adr_type);
} else {
// Specialized path for CM store barrier
__ storeCM(__ ctrl(), card_adr, zero, oop_store, bt, adr_type);
__ storeCM(__ ctrl(), card_adr, zero, oop_store, adr_idx, bt, adr_type);
}
// Final sync IdealKit and GraphKit.
@ -3314,6 +3315,7 @@ void GraphKit::g1_write_barrier_pre(Node* obj,
void GraphKit::g1_mark_card(IdealKit& ideal,
Node* card_adr,
Node* oop_store,
uint oop_alias_idx,
Node* index,
Node* index_adr,
Node* buffer,
@ -3323,7 +3325,7 @@ void GraphKit::g1_mark_card(IdealKit& ideal,
Node* no_base = __ top();
BasicType card_bt = T_BYTE;
// Smash zero into card. MUST BE ORDERED WRT TO STORE
__ storeCM(__ ctrl(), card_adr, zero, oop_store, card_bt, Compile::AliasIdxRaw);
__ storeCM(__ ctrl(), card_adr, zero, oop_store, oop_alias_idx, card_bt, Compile::AliasIdxRaw);
// Now do the queue work
__ if_then(index, BoolTest::ne, zero); {
@ -3435,13 +3437,13 @@ void GraphKit::g1_write_barrier_post(Node* oop_store,
Node* card_val = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw);
__ if_then(card_val, BoolTest::ne, zero); {
g1_mark_card(ideal, card_adr, oop_store, index, index_adr, buffer, tf);
g1_mark_card(ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf);
} __ end_if();
} __ end_if();
} __ end_if();
} else {
// Object.clone() instrinsic uses this path.
g1_mark_card(ideal, card_adr, oop_store, index, index_adr, buffer, tf);
g1_mark_card(ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf);
}
// Final sync IdealKit and GraphKit.

View File

@ -603,7 +603,8 @@ class GraphKit : public Phase {
void sync_kit(IdealKit& ideal);
// vanilla/CMS post barrier
void write_barrier_post(Node *store, Node* obj, Node* adr, Node* val, bool use_precise);
void write_barrier_post(Node *store, Node* obj,
Node* adr, uint adr_idx, Node* val, bool use_precise);
// G1 pre/post barriers
void g1_write_barrier_pre(Node* obj,
@ -622,7 +623,8 @@ class GraphKit : public Phase {
bool use_precise);
// Helper function for g1
private:
void g1_mark_card(IdealKit& ideal, Node* card_adr, Node* store, Node* index, Node* index_adr,
void g1_mark_card(IdealKit& ideal, Node* card_adr, Node* store, uint oop_alias_idx,
Node* index, Node* index_adr,
Node* buffer, const TypeFunc* tf);
public:

View File

@ -378,7 +378,7 @@ Node* IdealKit::store(Node* ctl, Node* adr, Node *val, BasicType bt,
// Card mark store. Must be ordered so that it will come after the store of
// the oop.
Node* IdealKit::storeCM(Node* ctl, Node* adr, Node *val, Node* oop_store,
Node* IdealKit::storeCM(Node* ctl, Node* adr, Node *val, Node* oop_store, int oop_adr_idx,
BasicType bt,
int adr_idx) {
assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" );
@ -388,7 +388,7 @@ Node* IdealKit::storeCM(Node* ctl, Node* adr, Node *val, Node* oop_store,
// Add required edge to oop_store, optimizer does not support precedence edges.
// Convert required edge to precedence edge before allocation.
Node* st = new (C, 5) StoreCMNode(ctl, mem, adr, adr_type, val, oop_store);
Node* st = new (C, 5) StoreCMNode(ctl, mem, adr, adr_type, val, oop_store, oop_adr_idx);
st = transform(st);
set_memory(st, adr_idx);

View File

@ -216,6 +216,7 @@ class IdealKit: public StackObj {
Node* adr,
Node* val,
Node* oop_store,
int oop_adr_idx,
BasicType bt,
int adr_idx);

View File

@ -133,6 +133,7 @@ class LibraryCallKit : public GraphKit {
return generate_method_call(method_id, true, false);
}
Node* make_string_method_node(int opcode, Node* str1, Node* cnt1, Node* str2, Node* cnt2);
bool inline_string_compareTo();
bool inline_string_indexOf();
Node* string_indexOf(Node* string_object, ciTypeArray* target_array, jint offset, jint cache_i, jint md2_i);
@ -796,6 +797,64 @@ Node* LibraryCallKit::generate_current_thread(Node* &tls_output) {
}
//------------------------------make_string_method_node------------------------
// Helper method for String intrinsic finctions.
Node* LibraryCallKit::make_string_method_node(int opcode, Node* str1, Node* cnt1, Node* str2, Node* cnt2) {
const int value_offset = java_lang_String::value_offset_in_bytes();
const int count_offset = java_lang_String::count_offset_in_bytes();
const int offset_offset = java_lang_String::offset_offset_in_bytes();
Node* no_ctrl = NULL;
ciInstanceKlass* klass = env()->String_klass();
const TypeInstPtr* string_type =
TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0);
const TypeAryPtr* value_type =
TypeAryPtr::make(TypePtr::NotNull,
TypeAry::make(TypeInt::CHAR,TypeInt::POS),
ciTypeArrayKlass::make(T_CHAR), true, 0);
// Get start addr of string and substring
Node* str1_valuea = basic_plus_adr(str1, str1, value_offset);
Node* str1_value = make_load(no_ctrl, str1_valuea, value_type, T_OBJECT, string_type->add_offset(value_offset));
Node* str1_offseta = basic_plus_adr(str1, str1, offset_offset);
Node* str1_offset = make_load(no_ctrl, str1_offseta, TypeInt::INT, T_INT, string_type->add_offset(offset_offset));
Node* str1_start = array_element_address(str1_value, str1_offset, T_CHAR);
// Pin loads from String::equals() argument since it could be NULL.
Node* str2_ctrl = (opcode == Op_StrEquals) ? control() : no_ctrl;
Node* str2_valuea = basic_plus_adr(str2, str2, value_offset);
Node* str2_value = make_load(str2_ctrl, str2_valuea, value_type, T_OBJECT, string_type->add_offset(value_offset));
Node* str2_offseta = basic_plus_adr(str2, str2, offset_offset);
Node* str2_offset = make_load(str2_ctrl, str2_offseta, TypeInt::INT, T_INT, string_type->add_offset(offset_offset));
Node* str2_start = array_element_address(str2_value, str2_offset, T_CHAR);
Node* result = NULL;
switch (opcode) {
case Op_StrIndexOf:
result = new (C, 6) StrIndexOfNode(control(), memory(TypeAryPtr::CHARS),
str1_start, cnt1, str2_start, cnt2);
break;
case Op_StrComp:
result = new (C, 6) StrCompNode(control(), memory(TypeAryPtr::CHARS),
str1_start, cnt1, str2_start, cnt2);
break;
case Op_StrEquals:
result = new (C, 5) StrEqualsNode(control(), memory(TypeAryPtr::CHARS),
str1_start, str2_start, cnt1);
break;
default:
ShouldNotReachHere();
return NULL;
}
// All these intrinsics have checks.
C->set_has_split_ifs(true); // Has chance for split-if optimization
return _gvn.transform(result);
}
//------------------------------inline_string_compareTo------------------------
bool LibraryCallKit::inline_string_compareTo() {
@ -824,16 +883,16 @@ bool LibraryCallKit::inline_string_compareTo() {
ciInstanceKlass* klass = env()->String_klass();
const TypeInstPtr* string_type =
TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0);
Node* no_ctrl = NULL;
Node* compare =
_gvn.transform(new (C, 7) StrCompNode(
control(),
memory(TypeAryPtr::CHARS),
memory(string_type->add_offset(value_offset)),
memory(string_type->add_offset(count_offset)),
memory(string_type->add_offset(offset_offset)),
receiver,
argument));
// Get counts for string and argument
Node* receiver_cnta = basic_plus_adr(receiver, receiver, count_offset);
Node* receiver_cnt = make_load(no_ctrl, receiver_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset));
Node* argument_cnta = basic_plus_adr(argument, argument, count_offset);
Node* argument_cnt = make_load(no_ctrl, argument_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset));
Node* compare = make_string_method_node(Op_StrComp, receiver, receiver_cnt, argument, argument_cnt);
push(compare);
return true;
}
@ -865,45 +924,71 @@ bool LibraryCallKit::inline_string_equals() {
return true;
}
// paths (plus control) merge
RegionNode* region = new (C, 5) RegionNode(5);
Node* phi = new (C, 5) PhiNode(region, TypeInt::BOOL);
// does source == target string?
Node* cmp = _gvn.transform(new (C, 3) CmpPNode(receiver, argument));
Node* bol = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq));
Node* if_eq = generate_slow_guard(bol, NULL);
if (if_eq != NULL) {
// receiver == argument
phi->init_req(2, intcon(1));
region->init_req(2, if_eq);
}
// get String klass for instanceOf
ciInstanceKlass* klass = env()->String_klass();
// two paths (plus control) merge
RegionNode* region = new (C, 3) RegionNode(3);
Node* phi = new (C, 3) PhiNode(region, TypeInt::BOOL);
if (!stopped()) {
Node* inst = gen_instanceof(argument, makecon(TypeKlassPtr::make(klass)));
Node* cmp = _gvn.transform(new (C, 3) CmpINode(inst, intcon(1)));
Node* bol = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::ne));
Node* inst = gen_instanceof(argument, makecon(TypeKlassPtr::make(klass)));
Node* cmp = _gvn.transform(new (C, 3) CmpINode(inst, intcon(1)));
Node* bol = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq));
Node* inst_false = generate_guard(bol, NULL, PROB_MIN);
//instanceOf == true, fallthrough
IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN);
Node* if_true = _gvn.transform(new (C, 1) IfTrueNode(iff));
set_control(if_true);
if (inst_false != NULL) {
phi->init_req(3, intcon(0));
region->init_req(3, inst_false);
}
}
const TypeInstPtr* string_type =
TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0);
// instanceOf == true
Node* equals =
_gvn.transform(new (C, 7) StrEqualsNode(
control(),
memory(TypeAryPtr::CHARS),
memory(string_type->add_offset(value_offset)),
memory(string_type->add_offset(count_offset)),
memory(string_type->add_offset(offset_offset)),
receiver,
argument));
Node* no_ctrl = NULL;
Node* receiver_cnt;
Node* argument_cnt;
phi->init_req(1, _gvn.transform(equals));
region->init_req(1, if_true);
if (!stopped()) {
// Get counts for string and argument
Node* receiver_cnta = basic_plus_adr(receiver, receiver, count_offset);
receiver_cnt = make_load(no_ctrl, receiver_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset));
//instanceOf == false, fallthrough
Node* if_false = _gvn.transform(new (C, 1) IfFalseNode(iff));
set_control(if_false);
// Pin load from argument string since it could be NULL.
Node* argument_cnta = basic_plus_adr(argument, argument, count_offset);
argument_cnt = make_load(control(), argument_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset));
phi->init_req(2, _gvn.transform(intcon(0)));
region->init_req(2, if_false);
// Check for receiver count != argument count
Node* cmp = _gvn.transform( new(C, 3) CmpINode(receiver_cnt, argument_cnt) );
Node* bol = _gvn.transform( new(C, 2) BoolNode(cmp, BoolTest::ne) );
Node* if_ne = generate_slow_guard(bol, NULL);
if (if_ne != NULL) {
phi->init_req(4, intcon(0));
region->init_req(4, if_ne);
}
}
// Check for count == 0 is done by mach node StrEquals.
if (!stopped()) {
Node* equals = make_string_method_node(Op_StrEquals, receiver, receiver_cnt, argument, argument_cnt);
phi->init_req(1, equals);
region->init_req(1, control());
}
// post merge
set_control(_gvn.transform(region));
@ -924,10 +1009,8 @@ bool LibraryCallKit::inline_array_equals() {
Node *argument1 = pop();
Node* equals =
_gvn.transform(new (C, 3) AryEqNode(control(),
argument1,
argument2)
);
_gvn.transform(new (C, 4) AryEqNode(control(), memory(TypeAryPtr::CHARS),
argument1, argument2) );
push(equals);
return true;
}
@ -1108,19 +1191,40 @@ bool LibraryCallKit::inline_string_indexOf() {
return true;
}
// Make the merge point
RegionNode* result_rgn = new (C, 3) RegionNode(3);
Node* result_phi = new (C, 3) PhiNode(result_rgn, TypeInt::INT);
Node* no_ctrl = NULL;
ciInstanceKlass* klass = env()->String_klass();
const TypeInstPtr* string_type =
TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0);
result =
_gvn.transform(new (C, 7)
StrIndexOfNode(control(),
memory(TypeAryPtr::CHARS),
memory(string_type->add_offset(value_offset)),
memory(string_type->add_offset(count_offset)),
memory(string_type->add_offset(offset_offset)),
receiver,
argument));
// Get counts for string and substr
Node* source_cnta = basic_plus_adr(receiver, receiver, count_offset);
Node* source_cnt = make_load(no_ctrl, source_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset));
Node* substr_cnta = basic_plus_adr(argument, argument, count_offset);
Node* substr_cnt = make_load(no_ctrl, substr_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset));
// Check for substr count > string count
Node* cmp = _gvn.transform( new(C, 3) CmpINode(substr_cnt, source_cnt) );
Node* bol = _gvn.transform( new(C, 2) BoolNode(cmp, BoolTest::gt) );
Node* if_gt = generate_slow_guard(bol, NULL);
if (if_gt != NULL) {
result_phi->init_req(2, intcon(-1));
result_rgn->init_req(2, if_gt);
}
if (!stopped()) {
result = make_string_method_node(Op_StrIndexOf, receiver, source_cnt, argument, substr_cnt);
result_phi->init_req(1, result);
result_rgn->init_req(1, control());
}
set_control(_gvn.transform(result_rgn));
record_for_igvn(result_rgn);
result = _gvn.transform(result_phi);
} else { //Use LibraryCallKit::string_indexOf
// don't intrinsify is argument isn't a constant string.
if (!argument->is_Con()) {

View File

@ -2032,6 +2032,23 @@ void Matcher::find_shared( Node *n ) {
n->del_req(3);
break;
}
case Op_StrEquals: {
Node *pair1 = new (C, 3) BinaryNode(n->in(2),n->in(3));
n->set_req(2,pair1);
n->set_req(3,n->in(4));
n->del_req(4);
break;
}
case Op_StrComp:
case Op_StrIndexOf: {
Node *pair1 = new (C, 3) BinaryNode(n->in(2),n->in(3));
n->set_req(2,pair1);
Node *pair2 = new (C, 3) BinaryNode(n->in(4),n->in(5));
n->set_req(3,pair2);
n->del_req(5);
n->del_req(4);
break;
}
default:
break;
}

View File

@ -2313,6 +2313,22 @@ Node *StoreCMNode::Identity( PhaseTransform *phase ) {
return this;
}
//=============================================================================
//------------------------------Ideal---------------------------------------
Node *StoreCMNode::Ideal(PhaseGVN *phase, bool can_reshape){
Node* progress = StoreNode::Ideal(phase, can_reshape);
if (progress != NULL) return progress;
Node* my_store = in(MemNode::OopStore);
if (my_store->is_MergeMem()) {
Node* mem = my_store->as_MergeMem()->memory_at(oop_alias_idx());
set_req(MemNode::OopStore, mem);
return this;
}
return NULL;
}
//------------------------------Value-----------------------------------------
const Type *StoreCMNode::Value( PhaseTransform *phase ) const {
// Either input is TOP ==> the result is TOP
@ -2498,7 +2514,7 @@ Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
//=============================================================================
// Do we match on this edge? No memory edges
uint StrCompNode::match_edge(uint idx) const {
return idx == 5 || idx == 6;
return idx == 2 || idx == 3; // StrComp (Binary str1 cnt1) (Binary str2 cnt2)
}
//------------------------------Ideal------------------------------------------
@ -2508,9 +2524,10 @@ Node *StrCompNode::Ideal(PhaseGVN *phase, bool can_reshape){
return remove_dead_region(phase, can_reshape) ? this : NULL;
}
//=============================================================================
// Do we match on this edge? No memory edges
uint StrEqualsNode::match_edge(uint idx) const {
return idx == 5 || idx == 6;
return idx == 2 || idx == 3; // StrEquals (Binary str1 str2) cnt
}
//------------------------------Ideal------------------------------------------
@ -2523,7 +2540,7 @@ Node *StrEqualsNode::Ideal(PhaseGVN *phase, bool can_reshape){
//=============================================================================
// Do we match on this edge? No memory edges
uint StrIndexOfNode::match_edge(uint idx) const {
return idx == 5 || idx == 6;
return idx == 2 || idx == 3; // StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)
}
//------------------------------Ideal------------------------------------------
@ -2533,6 +2550,11 @@ Node *StrIndexOfNode::Ideal(PhaseGVN *phase, bool can_reshape){
return remove_dead_region(phase, can_reshape) ? this : NULL;
}
//=============================================================================
// Do we match on this edge? No memory edges
uint AryEqNode::match_edge(uint idx) const {
return idx == 2 || idx == 3; // StrEquals ary1 ary2
}
//------------------------------Ideal------------------------------------------
// Return a node which is more "ideal" than the current node. Strip out
// control copies

View File

@ -582,12 +582,16 @@ public:
// The last StoreCM before a SafePoint must be preserved and occur after its "oop" store
// Preceeding equivalent StoreCMs may be eliminated.
class StoreCMNode : public StoreNode {
private:
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 ) : StoreNode(c,mem,adr,at,val,oop_store) {}
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) {}
virtual int Opcode() const;
virtual Node *Identity( PhaseTransform *phase );
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
virtual const Type *Value( PhaseTransform *phase ) const;
virtual BasicType memory_type() const { return T_VOID; } // unspecific
int oop_alias_idx() const { return _oop_alias_idx; }
};
//------------------------------LoadPLockedNode---------------------------------
@ -744,22 +748,15 @@ public:
//------------------------------StrComp-------------------------------------
class StrCompNode: public Node {
public:
StrCompNode(Node *control,
Node* char_array_mem,
Node* value_mem,
Node* count_mem,
Node* offset_mem,
Node* s1, Node* s2): Node(control,
char_array_mem,
value_mem,
count_mem,
offset_mem,
s1, s2) {};
StrCompNode(Node* control, Node* char_array_mem,
Node* s1, Node* c1,
Node* s2, Node* c2): Node(control, char_array_mem,
s1, c1,
s2, c2) {};
virtual int Opcode() const;
virtual bool depends_only_on_test() const { return false; }
virtual const Type* bottom_type() const { return TypeInt::INT; }
// a StrCompNode (conservatively) aliases with everything:
virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; }
virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; }
virtual uint match_edge(uint idx) const;
virtual uint ideal_reg() const { return Op_RegI; }
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
@ -768,22 +765,13 @@ public:
//------------------------------StrEquals-------------------------------------
class StrEqualsNode: public Node {
public:
StrEqualsNode(Node *control,
Node* char_array_mem,
Node* value_mem,
Node* count_mem,
Node* offset_mem,
Node* s1, Node* s2): Node(control,
char_array_mem,
value_mem,
count_mem,
offset_mem,
s1, s2) {};
StrEqualsNode(Node* control, Node* char_array_mem,
Node* s1, Node* s2, Node* c): Node(control, char_array_mem,
s1, s2, c) {};
virtual int Opcode() const;
virtual bool depends_only_on_test() const { return false; }
virtual const Type* bottom_type() const { return TypeInt::BOOL; }
// a StrEqualsNode (conservatively) aliases with everything:
virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; }
virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; }
virtual uint match_edge(uint idx) const;
virtual uint ideal_reg() const { return Op_RegI; }
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
@ -792,22 +780,15 @@ public:
//------------------------------StrIndexOf-------------------------------------
class StrIndexOfNode: public Node {
public:
StrIndexOfNode(Node *control,
Node* char_array_mem,
Node* value_mem,
Node* count_mem,
Node* offset_mem,
Node* s1, Node* s2): Node(control,
char_array_mem,
value_mem,
count_mem,
offset_mem,
s1, s2) {};
StrIndexOfNode(Node* control, Node* char_array_mem,
Node* s1, Node* c1,
Node* s2, Node* c2): Node(control, char_array_mem,
s1, c1,
s2, c2) {};
virtual int Opcode() const;
virtual bool depends_only_on_test() const { return false; }
virtual const Type* bottom_type() const { return TypeInt::INT; }
// a StrIndexOfNode (conservatively) aliases with everything:
virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; }
virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; }
virtual uint match_edge(uint idx) const;
virtual uint ideal_reg() const { return Op_RegI; }
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
@ -816,11 +797,13 @@ public:
//------------------------------AryEq---------------------------------------
class AryEqNode: public Node {
public:
AryEqNode(Node *control, Node* s1, Node* s2): Node(control, s1, s2) {};
AryEqNode(Node* control, Node* char_array_mem,
Node* s1, Node* s2): Node(control, char_array_mem, s1, s2) {};
virtual int Opcode() const;
virtual bool depends_only_on_test() const { return false; }
virtual const Type* bottom_type() const { return TypeInt::BOOL; }
virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; }
virtual uint match_edge(uint idx) const;
virtual uint ideal_reg() const { return Op_RegI; }
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
};

View File

@ -611,7 +611,7 @@ void Compile::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local,
assert(cik->is_instance_klass() ||
cik->is_array_klass(), "Not supported allocation.");
sv = new ObjectValue(spobj->_idx,
new ConstantOopWriteValue(cik->encoding()));
new ConstantOopWriteValue(cik->constant_encoding()));
Compile::set_sv_for_object_node(objs, sv);
uint first_ind = spobj->first_index();
@ -702,13 +702,13 @@ void Compile::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local,
case Type::AryPtr:
case Type::InstPtr:
case Type::KlassPtr: // fall through
array->append(new ConstantOopWriteValue(t->isa_oopptr()->const_oop()->encoding()));
array->append(new ConstantOopWriteValue(t->isa_oopptr()->const_oop()->constant_encoding()));
break;
case Type::NarrowOop:
if (t == TypeNarrowOop::NULL_PTR) {
array->append(new ConstantOopWriteValue(NULL));
} else {
array->append(new ConstantOopWriteValue(t->make_ptr()->isa_oopptr()->const_oop()->encoding()));
array->append(new ConstantOopWriteValue(t->make_ptr()->isa_oopptr()->const_oop()->constant_encoding()));
}
break;
case Type::Int:
@ -871,7 +871,7 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) {
assert(cik->is_instance_klass() ||
cik->is_array_klass(), "Not supported allocation.");
ObjectValue* sv = new ObjectValue(spobj->_idx,
new ConstantOopWriteValue(cik->encoding()));
new ConstantOopWriteValue(cik->constant_encoding()));
Compile::set_sv_for_object_node(objs, sv);
uint first_ind = spobj->first_index();
@ -890,7 +890,7 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) {
}
} else {
const TypePtr *tp = obj_node->bottom_type()->make_ptr();
scval = new ConstantOopWriteValue(tp->is_instptr()->const_oop()->encoding());
scval = new ConstantOopWriteValue(tp->is_instptr()->const_oop()->constant_encoding());
}
OptoReg::Name box_reg = BoxLockNode::stack_slot(box_node);

View File

@ -469,7 +469,7 @@ class Parse : public GraphKit {
// loading from a constant field or the constant pool
// returns false if push failed (non-perm field constants only, not ldcs)
bool push_constant(ciConstant con);
bool push_constant(ciConstant con, bool require_constant = false);
// implementation of object creation bytecodes
void do_new();

View File

@ -229,7 +229,9 @@ void Parse::load_interpreter_state(Node* osr_buf) {
}
}
MethodLivenessResult live_locals = method()->liveness_at_bci(osr_bci());
// Use the raw liveness computation to make sure that unexpected
// values don't propagate into the OSR frame.
MethodLivenessResult live_locals = method()->raw_liveness_at_bci(osr_bci());
if (!live_locals.is_valid()) {
// Degenerate or breakpointed method.
C->record_method_not_compilable("OSR in empty or breakpointed method");

View File

@ -1325,7 +1325,8 @@ void Parse::do_one_bytecode() {
}
}
}
push_constant(constant);
bool pushed = push_constant(constant, true);
guarantee(pushed, "must be possible to push this constant");
}
break;

View File

@ -267,7 +267,7 @@ void Parse::do_put_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool
}
bool Parse::push_constant(ciConstant constant) {
bool Parse::push_constant(ciConstant constant, bool require_constant) {
switch (constant.basic_type()) {
case T_BOOLEAN: push( intcon(constant.as_boolean()) ); break;
case T_INT: push( intcon(constant.as_int()) ); break;
@ -279,13 +279,16 @@ bool Parse::push_constant(ciConstant constant) {
case T_LONG: push_pair( longcon(constant.as_long()) ); break;
case T_ARRAY:
case T_OBJECT: {
// the oop is in perm space if the ciObject "has_encoding"
// cases:
// can_be_constant = (oop not scavengable || ScavengeRootsInCode != 0)
// should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2)
// An oop is not scavengable if it is in the perm gen.
ciObject* oop_constant = constant.as_object();
if (oop_constant->is_null_object()) {
push( zerocon(T_OBJECT) );
break;
} else if (oop_constant->has_encoding()) {
push( makecon(TypeOopPtr::make_from_constant(oop_constant)) );
} else if (require_constant || oop_constant->should_be_constant()) {
push( makecon(TypeOopPtr::make_from_constant(oop_constant, require_constant)) );
break;
} else {
// we cannot inline the oop, but we can use it later to narrow a type

View File

@ -457,10 +457,6 @@ void SuperWord::mem_slice_preds(Node* start, Node* stop, GrowableArray<Node*> &p
} else if (out->Opcode() == Op_StoreCM && out->in(MemNode::OopStore) == n) {
// StoreCM has an input edge used as a precedence edge.
// Maybe an issue when oop stores are vectorized.
} else if( out->is_MergeMem() && prev &&
prev->Opcode() == Op_StoreCM && out == prev->in(MemNode::OopStore)) {
// Oop store is a MergeMem! This should not happen. Temporarily remove the assertion
// for this case because it could not be superwordized anyway.
} else {
assert(out == prev || prev == NULL, "no branches off of store slice");
}
@ -477,6 +473,12 @@ void SuperWord::mem_slice_preds(Node* start, Node* stop, GrowableArray<Node*> &p
// Can s1 and s2 be in a pack with s1 immediately preceding s2 and
// s1 aligned at "align"
bool SuperWord::stmts_can_pack(Node* s1, Node* s2, int align) {
// Do not use superword for non-primitives
if((s1->is_Mem() && !is_java_primitive(s1->as_Mem()->memory_type())) ||
(s2->is_Mem() && !is_java_primitive(s2->as_Mem()->memory_type())))
return false;
if (isomorphic(s1, s2)) {
if (independent(s1, s2)) {
if (!exists_at(s1, 0) && !exists_at(s2, 1)) {

View File

@ -296,7 +296,7 @@ void Type::Initialize_shared(Compile* current) {
false, 0, oopDesc::mark_offset_in_bytes());
TypeInstPtr::KLASS = TypeInstPtr::make(TypePtr::BotPTR, current->env()->Object_klass(),
false, 0, oopDesc::klass_offset_in_bytes());
TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot);
TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot);
TypeNarrowOop::NULL_PTR = TypeNarrowOop::make( TypePtr::NULL_PTR );
TypeNarrowOop::BOTTOM = TypeNarrowOop::make( TypeInstPtr::BOTTOM );
@ -492,8 +492,13 @@ bool Type::is_nan() const {
bool Type::interface_vs_oop(const Type *t) const {
bool result = false;
const TypeInstPtr* this_inst = this->isa_instptr();
const TypeInstPtr* t_inst = t->isa_instptr();
const TypePtr* this_ptr = this->make_ptr(); // In case it is narrow_oop
const TypePtr* t_ptr = t->make_ptr();
if( this_ptr == NULL || t_ptr == NULL )
return result;
const TypeInstPtr* this_inst = this_ptr->isa_instptr();
const TypeInstPtr* t_inst = t_ptr->isa_instptr();
if( this_inst && this_inst->is_loaded() && t_inst && t_inst->is_loaded() ) {
bool this_interface = this_inst->klass()->is_interface();
bool t_interface = t_inst->klass()->is_interface();
@ -2249,7 +2254,7 @@ const TypeOopPtr *TypeOopPtr::make(PTR ptr,
const Type *TypeOopPtr::cast_to_ptr_type(PTR ptr) const {
assert(_base == OopPtr, "subclass must override cast_to_ptr_type");
if( ptr == _ptr ) return this;
return make(ptr, _offset);
return make(ptr, _offset, _instance_id);
}
//-----------------------------cast_to_instance_id----------------------------
@ -2319,8 +2324,10 @@ const Type *TypeOopPtr::xmeet( const Type *t ) const {
if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset);
// else fall through:
case TopPTR:
case AnyNull:
return make(ptr, offset);
case AnyNull: {
int instance_id = meet_instance_id(InstanceTop);
return make(ptr, offset, instance_id);
}
case BotPTR:
case NotNull:
return TypePtr::make(AnyPtr, ptr, offset);
@ -2411,14 +2418,13 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_
//------------------------------make_from_constant-----------------------------
// Make a java pointer from an oop constant
const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o) {
const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_constant) {
if (o->is_method_data() || o->is_method()) {
// Treat much like a typeArray of bytes, like below, but fake the type...
assert(o->has_encoding(), "must be a perm space object");
const Type* etype = (Type*)get_const_basic_type(T_BYTE);
const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
ciKlass *klass = ciTypeArrayKlass::make((BasicType) T_BYTE);
assert(o->has_encoding(), "method data oops should be tenured");
assert(o->can_be_constant(), "method data oops should be tenured");
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
return arr;
} else {
@ -2427,8 +2433,9 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o) {
ciKlass *klass = o->klass();
if (klass->is_instance_klass()) {
// Element is an instance
if (!o->has_encoding()) { // not a perm-space constant
// %%% remove this restriction by rewriting non-perm ConPNodes in a later phase
if (require_constant) {
if (!o->can_be_constant()) return NULL;
} else if (!o->should_be_constant()) {
return TypeInstPtr::make(TypePtr::NotNull, klass, true, NULL, 0);
}
return TypeInstPtr::make(o);
@ -2440,8 +2447,9 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o) {
// We used to pass NotNull in here, asserting that the sub-arrays
// are all not-null. This is not true in generally, as code can
// slam NULLs down in the subarrays.
if (!o->has_encoding()) { // not a perm-space constant
// %%% remove this restriction by rewriting non-perm ConPNodes in a later phase
if (require_constant) {
if (!o->can_be_constant()) return NULL;
} else if (!o->should_be_constant()) {
return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
}
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
@ -2453,8 +2461,9 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o) {
const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
// We used to pass NotNull in here, asserting that the array pointer
// is not-null. That was not true in general.
if (!o->has_encoding()) { // not a perm-space constant
// %%% remove this restriction by rewriting non-perm ConPNodes in a later phase
if (require_constant) {
if (!o->can_be_constant()) return NULL;
} else if (!o->should_be_constant()) {
return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
}
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
@ -2483,7 +2492,7 @@ intptr_t TypeOopPtr::get_con() const {
ShouldNotReachHere();
}
return (intptr_t)const_oop()->encoding();
return (intptr_t)const_oop()->constant_encoding();
}
@ -2591,7 +2600,7 @@ bool TypeOopPtr::singleton(void) const {
//------------------------------add_offset-------------------------------------
const TypePtr *TypeOopPtr::add_offset( intptr_t offset ) const {
return make( _ptr, xadd_offset(offset) );
return make( _ptr, xadd_offset(offset), _instance_id);
}
//------------------------------meet_instance_id--------------------------------
@ -2694,6 +2703,7 @@ const TypeOopPtr *TypeInstPtr::cast_to_instance_id(int instance_id) const {
const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const {
int off = meet_offset(tinst->offset());
PTR ptr = meet_ptr(tinst->ptr());
int instance_id = meet_instance_id(tinst->instance_id());
const TypeInstPtr *loaded = is_loaded() ? this : tinst;
const TypeInstPtr *unloaded = is_loaded() ? tinst : this;
@ -2714,7 +2724,7 @@ const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const {
assert(loaded->ptr() != TypePtr::Null, "insanity check");
//
if( loaded->ptr() == TypePtr::TopPTR ) { return unloaded; }
else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make( ptr, unloaded->klass() ); }
else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make( ptr, unloaded->klass(), false, NULL, off, instance_id ); }
else if (loaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; }
else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) {
if (unloaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; }
@ -3338,14 +3348,19 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
ciObject* o = const_oop();
if( _ptr == Constant ) {
if( tap->const_oop() != NULL && !o->equals(tap->const_oop()) ) {
xk = (klass() == tap->klass());
ptr = NotNull;
o = NULL;
instance_id = InstanceBot;
} else {
xk = true;
}
} else if( above_centerline(_ptr) ) {
o = tap->const_oop();
xk = true;
} else {
xk = this->_klass_is_exact;
}
xk = true;
return TypeAryPtr::make( ptr, o, tary, tap->_klass, xk, off, instance_id );
}
case NotNull:

View File

@ -711,10 +711,13 @@ public:
return make_from_klass_common(klass, false, false);
}
// Creates a singleton type given an object.
static const TypeOopPtr* make_from_constant(ciObject* o);
// If the object cannot be rendered as a constant,
// may return a non-singleton type.
// If require_constant, produce a NULL if a singleton is not possible.
static const TypeOopPtr* make_from_constant(ciObject* o, bool require_constant = false);
// Make a generic (unclassed) pointer to an oop.
static const TypeOopPtr* make(PTR ptr, int offset, int instance_id = InstanceBot);
static const TypeOopPtr* make(PTR ptr, int offset, int instance_id);
ciObject* const_oop() const { return _const_oop; }
virtual ciKlass* klass() const { return _klass; }

View File

@ -3126,6 +3126,12 @@ inline bool VM_HeapWalkOperation::collect_simple_roots() {
// exceptions) will be visible.
blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER);
Universe::oops_do(&blk);
// If there are any non-perm roots in the code cache, visit them.
blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER);
CodeBlobToOopClosure look_in_blobs(&blk, false);
CodeCache::scavenge_root_nmethods_do(&look_in_blobs);
return true;
}

View File

@ -2648,16 +2648,22 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
if (EnableInvokeDynamic && !EnableMethodHandles) {
if (!FLAG_IS_DEFAULT(EnableMethodHandles)) {
warning("forcing EnableMethodHandles true to allow EnableInvokeDynamic");
warning("forcing EnableMethodHandles true because EnableInvokeDynamic is true");
}
EnableMethodHandles = true;
}
if (EnableMethodHandles && !AnonymousClasses) {
if (!FLAG_IS_DEFAULT(AnonymousClasses)) {
warning("forcing AnonymousClasses true to enable EnableMethodHandles");
warning("forcing AnonymousClasses true because EnableMethodHandles is true");
}
AnonymousClasses = true;
}
if ((EnableMethodHandles || AnonymousClasses) && ScavengeRootsInCode == 0) {
if (!FLAG_IS_DEFAULT(ScavengeRootsInCode)) {
warning("forcing ScavengeRootsInCode non-zero because EnableMethodHandles or AnonymousClasses is true");
}
ScavengeRootsInCode = 1;
}
if (PrintGCDetails) {
// Turn on -verbose:gc options as well

View File

@ -1043,7 +1043,7 @@ void frame::oops_interpreted_arguments_do(symbolHandle signature, bool is_static
finder.oops_do();
}
void frame::oops_code_blob_do(OopClosure* f, const RegisterMap* reg_map) {
void frame::oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, const RegisterMap* reg_map) {
assert(_cb != NULL, "sanity check");
if (_cb->oop_maps() != NULL) {
OopMapSet::oops_do(this, reg_map, f);
@ -1058,21 +1058,9 @@ void frame::oops_code_blob_do(OopClosure* f, const RegisterMap* reg_map) {
// oops referenced from nmethods active on thread stacks so as to
// prevent them from being collected. However, this visit should be
// restricted to certain phases of the collection only. The
// closure answers whether it wants nmethods to be traced.
// (All CodeBlob subtypes other than NMethod currently have
// an empty oops_do() method.
if (f->do_nmethods()) {
_cb->oops_do(f);
}
}
void frame::nmethods_code_blob_do() {
assert(_cb != NULL, "sanity check");
// If we see an activation belonging to a non_entrant nmethod, we mark it.
if (_cb->is_nmethod() && ((nmethod *)_cb)->is_not_entrant()) {
((nmethod*)_cb)->mark_as_seen_on_stack();
}
// closure decides how it wants nmethods to be traced.
if (cf != NULL)
cf->do_code_blob(_cb);
}
class CompiledArgumentOopFinder: public SignatureInfo {
@ -1201,18 +1189,18 @@ void frame::oops_entry_do(OopClosure* f, const RegisterMap* map) {
}
void frame::oops_do_internal(OopClosure* f, RegisterMap* map, bool use_interpreter_oop_map_cache) {
void frame::oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache) {
if (is_interpreted_frame()) { oops_interpreted_do(f, map, use_interpreter_oop_map_cache);
} else if (is_entry_frame()) { oops_entry_do (f, map);
} else if (CodeCache::contains(pc())) { oops_code_blob_do (f, map);
} else if (CodeCache::contains(pc())) { oops_code_blob_do (f, cf, map);
} else {
ShouldNotReachHere();
}
}
void frame::nmethods_do() {
void frame::nmethods_do(CodeBlobClosure* cf) {
if (_cb != NULL && _cb->is_nmethod()) {
nmethods_code_blob_do();
cf->do_code_blob(_cb);
}
}
@ -1358,7 +1346,7 @@ void frame::verify(const RegisterMap* map) {
}
}
COMPILER2_PRESENT(assert(DerivedPointerTable::is_empty(), "must be empty before verify");)
oops_do_internal(&VerifyOopClosure::verify_oop, (RegisterMap*)map, false);
oops_do_internal(&VerifyOopClosure::verify_oop, NULL, (RegisterMap*)map, false);
}

View File

@ -384,16 +384,14 @@ class frame VALUE_OBJ_CLASS_SPEC {
void oops_interpreted_arguments_do(symbolHandle signature, bool is_static, OopClosure* f);
// Iteration of oops
void oops_do_internal(OopClosure* f, RegisterMap* map, bool use_interpreter_oop_map_cache);
void oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache);
void oops_entry_do(OopClosure* f, const RegisterMap* map);
void oops_code_blob_do(OopClosure* f, const RegisterMap* map);
void oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, const RegisterMap* map);
int adjust_offset(methodOop method, int index); // helper for above fn
// Iteration of nmethods
void nmethods_code_blob_do();
public:
// Memory management
void oops_do(OopClosure* f, RegisterMap* map) { oops_do_internal(f, map, true); }
void nmethods_do();
void oops_do(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map) { oops_do_internal(f, cf, map, true); }
void nmethods_do(CodeBlobClosure* cf);
void gc_prologue();
void gc_epilogue();

View File

@ -714,6 +714,11 @@ class CommandLineFlags {
diagnostic(bool, TraceNMethodInstalls, false, \
"Trace nmethod intallation") \
\
diagnostic(intx, ScavengeRootsInCode, 0, \
"0: do not allow scavengable oops in the code cache; " \
"1: allow scavenging from the code cache; " \
"2: emit as many constants as the compiler can see") \
\
diagnostic(bool, TraceOSRBreakpoint, false, \
"Trace OSR Breakpoint ") \
\

View File

@ -34,6 +34,17 @@ jint NMethodSweeper::_locked_seen = 0;
jint NMethodSweeper::_not_entrant_seen_on_stack = 0;
bool NMethodSweeper::_rescan = false;
class MarkActivationClosure: public CodeBlobClosure {
public:
virtual void do_code_blob(CodeBlob* cb) {
// If we see an activation belonging to a non_entrant nmethod, we mark it.
if (cb->is_nmethod() && ((nmethod*)cb)->is_not_entrant()) {
((nmethod*)cb)->mark_as_seen_on_stack();
}
}
};
static MarkActivationClosure mark_activation_closure;
void NMethodSweeper::sweep() {
assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint");
if (!MethodFlushing) return;
@ -57,7 +68,7 @@ void NMethodSweeper::sweep() {
if (PrintMethodFlushing) {
tty->print_cr("### Sweep: stack traversal %d", _traversals);
}
Threads::nmethods_do();
Threads::nmethods_do(&mark_activation_closure);
// reset the flags since we started a scan from the beginning.
_rescan = false;

View File

@ -683,14 +683,15 @@ bool Thread::claim_oops_do_par_case(int strong_roots_parity) {
return false;
}
void Thread::oops_do(OopClosure* f) {
void Thread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
active_handles()->oops_do(f);
// Do oop for ThreadShadow
f->do_oop((oop*)&_pending_exception);
handle_area()->oops_do(f);
}
void Thread::nmethods_do() {
void Thread::nmethods_do(CodeBlobClosure* cf) {
// no nmethods in a generic thread...
}
void Thread::print_on(outputStream* st) const {
@ -2316,12 +2317,12 @@ void JavaThread::gc_prologue() {
}
void JavaThread::oops_do(OopClosure* f) {
void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
// The ThreadProfiler oops_do is done from FlatProfiler::oops_do
// since there may be more than one thread using each ThreadProfiler.
// Traverse the GCHandles
Thread::oops_do(f);
Thread::oops_do(f, cf);
assert( (!has_last_Java_frame() && java_call_counter() == 0) ||
(has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!");
@ -2347,7 +2348,7 @@ void JavaThread::oops_do(OopClosure* f) {
// Traverse the execution stack
for(StackFrameStream fst(this); !fst.is_done(); fst.next()) {
fst.current()->oops_do(f, fst.register_map());
fst.current()->oops_do(f, cf, fst.register_map());
}
}
@ -2379,9 +2380,8 @@ void JavaThread::oops_do(OopClosure* f) {
}
}
void JavaThread::nmethods_do() {
// Traverse the GCHandles
Thread::nmethods_do();
void JavaThread::nmethods_do(CodeBlobClosure* cf) {
Thread::nmethods_do(cf); // (super method is a no-op)
assert( (!has_last_Java_frame() && java_call_counter() == 0) ||
(has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!");
@ -2389,7 +2389,7 @@ void JavaThread::nmethods_do() {
if (has_last_Java_frame()) {
// Traverse the execution stack
for(StackFrameStream fst(this); !fst.is_done(); fst.next()) {
fst.current()->nmethods_do();
fst.current()->nmethods_do(cf);
}
}
}
@ -2463,7 +2463,7 @@ static void frame_verify(frame* f, const RegisterMap *map) { f->verify(map); }
void JavaThread::verify() {
// Verify oops in the thread.
oops_do(&VerifyOopClosure::verify_oop);
oops_do(&VerifyOopClosure::verify_oop, NULL);
// Verify the stack frames.
frames_do(frame_verify);
@ -3602,14 +3602,14 @@ bool Threads::includes(JavaThread* p) {
// uses the Threads_lock to gurantee this property. It also makes sure that
// all threads gets blocked when exiting or starting).
void Threads::oops_do(OopClosure* f) {
void Threads::oops_do(OopClosure* f, CodeBlobClosure* cf) {
ALL_JAVA_THREADS(p) {
p->oops_do(f);
p->oops_do(f, cf);
}
VMThread::vm_thread()->oops_do(f);
VMThread::vm_thread()->oops_do(f, cf);
}
void Threads::possibly_parallel_oops_do(OopClosure* f) {
void Threads::possibly_parallel_oops_do(OopClosure* f, CodeBlobClosure* cf) {
// Introduce a mechanism allowing parallel threads to claim threads as
// root groups. Overhead should be small enough to use all the time,
// even in sequential code.
@ -3618,12 +3618,12 @@ void Threads::possibly_parallel_oops_do(OopClosure* f) {
int cp = SharedHeap::heap()->strong_roots_parity();
ALL_JAVA_THREADS(p) {
if (p->claim_oops_do(is_par, cp)) {
p->oops_do(f);
p->oops_do(f, cf);
}
}
VMThread* vmt = VMThread::vm_thread();
if (vmt->claim_oops_do(is_par, cp))
vmt->oops_do(f);
vmt->oops_do(f, cf);
}
#ifndef SERIALGC
@ -3644,11 +3644,11 @@ void Threads::create_thread_roots_marking_tasks(GCTaskQueue* q) {
}
#endif // SERIALGC
void Threads::nmethods_do() {
void Threads::nmethods_do(CodeBlobClosure* cf) {
ALL_JAVA_THREADS(p) {
p->nmethods_do();
p->nmethods_do(cf);
}
VMThread::vm_thread()->nmethods_do();
VMThread::vm_thread()->nmethods_do(cf);
}
void Threads::gc_epilogue() {

View File

@ -374,7 +374,8 @@ class Thread: public ThreadShadow {
// GC support
// Apply "f->do_oop" to all root oops in "this".
void oops_do(OopClosure* f);
// Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames
void oops_do(OopClosure* f, CodeBlobClosure* cf);
// Handles the parallel case for the method below.
private:
@ -398,7 +399,7 @@ public:
}
// Sweeper support
void nmethods_do();
void nmethods_do(CodeBlobClosure* cf);
// Tells if adr belong to this thread. This is used
// for checking if a lock is owned by the running thread.
@ -1229,10 +1230,10 @@ class JavaThread: public Thread {
void frames_do(void f(frame*, const RegisterMap*));
// Memory operations
void oops_do(OopClosure* f);
void oops_do(OopClosure* f, CodeBlobClosure* cf);
// Sweeper operations
void nmethods_do();
void nmethods_do(CodeBlobClosure* cf);
// Memory management operations
void gc_epilogue();
@ -1620,9 +1621,9 @@ class Threads: AllStatic {
// Apply "f->do_oop" to all root oops in all threads.
// This version may only be called by sequential code.
static void oops_do(OopClosure* f);
static void oops_do(OopClosure* f, CodeBlobClosure* cf);
// This version may be called by sequential or parallel code.
static void possibly_parallel_oops_do(OopClosure* f);
static void possibly_parallel_oops_do(OopClosure* f, CodeBlobClosure* cf);
// This creates a list of GCTasks, one per thread.
static void create_thread_roots_tasks(GCTaskQueue* q);
// This creates a list of GCTasks, one per thread, for marking objects.
@ -1630,13 +1631,13 @@ class Threads: AllStatic {
// Apply "f->do_oop" to roots in all threads that
// are part of compiled frames
static void compiled_frame_oops_do(OopClosure* f);
static void compiled_frame_oops_do(OopClosure* f, CodeBlobClosure* cf);
static void convert_hcode_pointers();
static void restore_hcode_pointers();
// Sweeper
static void nmethods_do();
static void nmethods_do(CodeBlobClosure* cf);
static void gc_epilogue();
static void gc_prologue();

View File

@ -549,6 +549,7 @@ static inline uint64_t cast_uint64_t(size_t x)
/********************************/ \
\
static_field(CodeCache, _heap, CodeHeap*) \
static_field(CodeCache, _scavenge_root_nmethods, nmethod*) \
\
/*******************************/ \
/* CodeHeap (NOTE: incomplete) */ \
@ -618,7 +619,9 @@ static inline uint64_t cast_uint64_t(size_t x)
static_field(nmethod, _zombie_instruction_size, int) \
nonstatic_field(nmethod, _method, methodOop) \
nonstatic_field(nmethod, _entry_bci, int) \
nonstatic_field(nmethod, _link, nmethod*) \
nonstatic_field(nmethod, _osr_link, nmethod*) \
nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \
nonstatic_field(nmethod, _scavenge_root_state, jbyte) \
nonstatic_field(nmethod, _exception_offset, int) \
nonstatic_field(nmethod, _deoptimize_offset, int) \
nonstatic_field(nmethod, _orig_pc_offset, int) \

View File

@ -619,8 +619,8 @@ void VMThread::execute(VM_Operation* op) {
}
void VMThread::oops_do(OopClosure* f) {
Thread::oops_do(f);
void VMThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
Thread::oops_do(f, cf);
_vm_queue->oops_do(f);
}
@ -652,5 +652,5 @@ void VMOperationQueue::verify_queue(int prio) {
#endif
void VMThread::verify() {
oops_do(&VerifyOopClosure::verify_oop);
oops_do(&VerifyOopClosure::verify_oop, NULL);
}

View File

@ -121,7 +121,7 @@ class VMThread: public Thread {
static VMThread* vm_thread() { return _vm_thread; }
// GC support
void oops_do(OopClosure* f);
void oops_do(OopClosure* f, CodeBlobClosure* cf);
// Debugging
void print_on(outputStream* st) const;

View File

@ -702,11 +702,14 @@ static void findref(intptr_t x) {
tty->print_cr("Searching strong roots:");
Universe::oops_do(&lookFor, false);
JNIHandles::oops_do(&lookFor); // Global (strong) JNI handles
Threads::oops_do(&lookFor);
Threads::oops_do(&lookFor, NULL);
ObjectSynchronizer::oops_do(&lookFor);
//FlatProfiler::oops_do(&lookFor);
SystemDictionary::oops_do(&lookFor);
tty->print_cr("Searching code cache:");
CodeCache::oops_do(&lookFor);
tty->print_cr("Done.");
}

View File

@ -26,7 +26,7 @@
* @test
* @bug 6823453
* @summary DeoptimizeALot causes fastdebug server jvm to fail with assert(false,"unscheduable graph")
* @run main/othervm -Xcomp -XX:CompileOnly=Test -XX:+DeoptimizeALot Test
* @run main/othervm -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:CompileOnly=Test -XX:+DeoptimizeALot Test
*/
public class Test {

Some files were not shown because too many files have changed in this diff Show More