This commit is contained in:
Jesper Wilhelmsson 2017-11-25 20:28:10 +01:00
commit f32bd0cb43
118 changed files with 5610 additions and 1779 deletions

View File

@ -59,6 +59,7 @@ JVM_CFLAGS_INCLUDES += \
-I$(TOPDIR)/src/hotspot/share/precompiled \
-I$(TOPDIR)/src/java.base/share/native/include \
-I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/include \
-I$(TOPDIR)/src/java.management/share/native/include \
-I$(TOPDIR)/src/java.base/share/native/libjimage \
#

View File

@ -2968,7 +2968,9 @@ class StubGenerator: public StubCodeGenerator {
CardTableModRefBS* ct = barrier_set_cast<CardTableModRefBS>(bs);
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
Label L_cardtable_loop;
Label L_cardtable_loop, L_done;
__ cbz_32(count, L_done); // zero count - nothing to do
__ add_ptr_scaled_int32(count, addr, count, LogBytesPerHeapOop);
__ sub(count, count, BytesPerHeapOop); // last addr
@ -2987,6 +2989,7 @@ class StubGenerator: public StubCodeGenerator {
__ strb(zero, Address(addr, 1, post_indexed));
__ subs(count, count, 1);
__ b(L_cardtable_loop, ge);
__ BIND(L_done);
}
break;
case BarrierSet::ModRef:

View File

@ -582,7 +582,11 @@ class Assembler : public AbstractAssembler {
#define LOC_ZOPC (unsigned long)(0xebL << 40 | 0xf2L) // z196
#define LOCG_ZOPC (unsigned long)(0xebL << 40 | 0xe2L) // z196
#define LMG_ZOPC (unsigned long)(235L << 40 | 4L)
// LOAD multiple registers at once
#define LM_ZOPC (unsigned int)(0x98 << 24)
#define LMY_ZOPC (unsigned long)(0xebL << 40 | 0x98L)
#define LMG_ZOPC (unsigned long)(0xebL << 40 | 0x04L)
#define LE_ZOPC (unsigned int)(0x78 << 24)
#define LEY_ZOPC (unsigned long)(237L << 40 | 100L)
@ -613,7 +617,10 @@ class Assembler : public AbstractAssembler {
#define STOC_ZOPC (unsigned long)(0xebL << 40 | 0xf3L) // z196
#define STOCG_ZOPC (unsigned long)(0xebL << 40 | 0xe3L) // z196
#define STMG_ZOPC (unsigned long)(235L << 40 | 36L)
// STORE multiple registers at once
#define STM_ZOPC (unsigned int)(0x90 << 24)
#define STMY_ZOPC (unsigned long)(0xebL << 40 | 0x90L)
#define STMG_ZOPC (unsigned long)(0xebL << 40 | 0x24L)
#define STE_ZOPC (unsigned int)(0x70 << 24)
#define STEY_ZOPC (unsigned long)(237L << 40 | 102L)
@ -874,15 +881,19 @@ class Assembler : public AbstractAssembler {
// Shift
// arithmetic
#define SLA_ZOPC (unsigned int)(139 << 24)
#define SLAG_ZOPC (unsigned long)(235L << 40 | 11L)
#define SRA_ZOPC (unsigned int)(138 << 24)
#define SRAG_ZOPC (unsigned long)(235L << 40 | 10L)
#define SLA_ZOPC (unsigned int)(0x8b << 24)
#define SLAK_ZOPC (unsigned long)(0xebL << 40 | 0xddL)
#define SLAG_ZOPC (unsigned long)(0xebL << 40 | 0x0bL)
#define SRA_ZOPC (unsigned int)(0x8a << 24)
#define SRAK_ZOPC (unsigned long)(0xebL << 40 | 0xdcL)
#define SRAG_ZOPC (unsigned long)(0xebL << 40 | 0x0aL)
// logical
#define SLL_ZOPC (unsigned int)(137 << 24)
#define SLLG_ZOPC (unsigned long)(235L << 40 | 13L)
#define SRL_ZOPC (unsigned int)(136 << 24)
#define SRLG_ZOPC (unsigned long)(235L << 40 | 12L)
#define SLL_ZOPC (unsigned int)(0x89 << 24)
#define SLLK_ZOPC (unsigned long)(0xebL << 40 | 0xdfL)
#define SLLG_ZOPC (unsigned long)(0xebL << 40 | 0x0dL)
#define SRL_ZOPC (unsigned int)(0x88 << 24)
#define SRLK_ZOPC (unsigned long)(0xebL << 40 | 0xdeL)
#define SRLG_ZOPC (unsigned long)(0xebL << 40 | 0x0cL)
// Rotate, then AND/XOR/OR/insert
// rotate
@ -2262,12 +2273,16 @@ class Assembler : public AbstractAssembler {
// shift
inline void z_sla( Register r1, int64_t d2, Register b2=Z_R0); // shift left r1 = r1 << ((d2+b2)&0x3f) ; int32, only 31 bits shifted, sign preserved!
inline void z_slak(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int32, only 31 bits shifted, sign preserved!
inline void z_slag(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int64, only 63 bits shifted, sign preserved!
inline void z_sra( Register r1, int64_t d2, Register b2=Z_R0); // shift right r1 = r1 >> ((d2+b2)&0x3f) ; int32, sign extended
inline void z_srak(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int32, sign extended
inline void z_srag(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int64, sign extended
inline void z_sll( Register r1, int64_t d2, Register b2=Z_R0); // shift left r1 = r1 << ((d2+b2)&0x3f) ; int32, zeros added
inline void z_sllk(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int32, zeros added
inline void z_sllg(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int64, zeros added
inline void z_srl( Register r1, int64_t d2, Register b2=Z_R0); // shift right r1 = r1 >> ((d2+b2)&0x3f) ; int32, zero extended
inline void z_srlk(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int32, zero extended
inline void z_srlg(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int64, zero extended
// rotate
@ -3035,7 +3050,11 @@ class Assembler : public AbstractAssembler {
inline void z_tam();
inline void z_stckf(int64_t d2, Register b2);
inline void z_stm( Register r1, Register r3, int64_t d2, Register b2);
inline void z_stmy(Register r1, Register r3, int64_t d2, Register b2);
inline void z_stmg(Register r1, Register r3, int64_t d2, Register b2);
inline void z_lm( Register r1, Register r3, int64_t d2, Register b2);
inline void z_lmy(Register r1, Register r3, int64_t d2, Register b2);
inline void z_lmg(Register r1, Register r3, int64_t d2, Register b2);
inline void z_cs( Register r1, Register r3, int64_t d2, Register b2);

View File

@ -334,12 +334,16 @@ inline void Assembler::z_stfle(int64_t d2, Register b2) { emit_32(STFLE_ZOPC | u
// SHIFT/RORATE OPERATIONS
//-----------------------------------
inline void Assembler::z_sla( Register r1, int64_t d2, Register b2) { emit_32( SLA_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); }
inline void Assembler::z_slak(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SLAK_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
inline void Assembler::z_slag(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SLAG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
inline void Assembler::z_sra( Register r1, int64_t d2, Register b2) { emit_32( SRA_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); }
inline void Assembler::z_srak(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SRAK_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
inline void Assembler::z_srag(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SRAG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
inline void Assembler::z_sll( Register r1, int64_t d2, Register b2) { emit_32( SLL_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); }
inline void Assembler::z_sllk(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SLLK_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
inline void Assembler::z_sllg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SLLG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
inline void Assembler::z_srl( Register r1, int64_t d2, Register b2) { emit_32( SRL_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); }
inline void Assembler::z_srlk(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SRLK_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
inline void Assembler::z_srlg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SRLG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); }
// rotate left
@ -690,10 +694,14 @@ inline void Assembler::z_ahhlr(Register r1, Register r2, Register r3) { emit_32(
inline void Assembler::z_tam() { emit_16( TAM_ZOPC); }
inline void Assembler::z_stckf(int64_t d2, Register b2) { emit_32( STCKF_ZOPC | uimm12(d2, 20, 32) | regz(b2, 16, 32)); }
inline void Assembler::z_stmg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( STMG_ZOPC | simm20(d2) | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) ); }
inline void Assembler::z_lmg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( LMG_ZOPC | simm20(d2) | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) ); }
inline void Assembler::z_stm( Register r1, Register r3, int64_t d2, Register b2) { emit_32( STM_ZOPC | reg(r1, 8, 32) | reg(r3,12,32)| reg(b2,16,32) | uimm12(d2, 20,32)); }
inline void Assembler::z_stmy(Register r1, Register r3, int64_t d2, Register b2) { emit_48( STMY_ZOPC | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) | simm20(d2) ); }
inline void Assembler::z_stmg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( STMG_ZOPC | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) | simm20(d2) ); }
inline void Assembler::z_lm( Register r1, Register r3, int64_t d2, Register b2) { emit_32( LM_ZOPC | reg(r1, 8, 32) | reg(r3,12,32)| reg(b2,16,32) | uimm12(d2, 20,32)); }
inline void Assembler::z_lmy( Register r1, Register r3, int64_t d2, Register b2) { emit_48( LMY_ZOPC | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) | simm20(d2) ); }
inline void Assembler::z_lmg( Register r1, Register r3, int64_t d2, Register b2) { emit_48( LMG_ZOPC | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) | simm20(d2) ); }
inline void Assembler::z_cs(Register r1, Register r3, int64_t d2, Register b2) { emit_32( CS_ZOPC | regt(r1, 8, 32) | reg(r3, 12, 32) | reg(b2, 16, 32) | uimm12(d2, 20, 32)); }
inline void Assembler::z_cs( Register r1, Register r3, int64_t d2, Register b2) { emit_32( CS_ZOPC | regt(r1, 8, 32) | reg(r3, 12, 32) | reg(b2, 16, 32) | uimm12(d2, 20, 32)); }
inline void Assembler::z_csy(Register r1, Register r3, int64_t d2, Register b2) { emit_48( CSY_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | reg(b2, 16, 48) | simm20(d2)); }
inline void Assembler::z_csg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( CSG_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | reg(b2, 16, 48) | simm20(d2)); }
inline void Assembler::z_cs( Register r1, Register r3, const Address& a) { assert(!a.has_index(), "Cannot encode index"); z_cs( r1, r3, a.disp(), a.baseOrR0()); }

View File

@ -936,7 +936,7 @@ void MacroAssembler::load_long_pcrelative(Register Rdst, address dataLocation) {
// Some extra safety net.
if (!RelAddr::is_in_range_of_RelAddr32(total_distance)) {
guarantee(RelAddr::is_in_range_of_RelAddr32(total_distance), "too far away");
guarantee(RelAddr::is_in_range_of_RelAddr32(total_distance), "load_long_pcrelative can't handle distance " INTPTR_FORMAT, total_distance);
}
(this)->relocate(rspec, relocInfo::pcrel_addr_format);
@ -956,7 +956,7 @@ void MacroAssembler::load_addr_pcrelative(Register Rdst, address addrLocation) {
// Some extra safety net.
if (!RelAddr::is_in_range_of_RelAddr32(total_distance)) {
guarantee(RelAddr::is_in_range_of_RelAddr32(total_distance), "too far away");
guarantee(RelAddr::is_in_range_of_RelAddr32(total_distance), "load_long_pcrelative can't handle distance " INTPTR_FORMAT, total_distance);
}
(this)->relocate(rspec, relocInfo::pcrel_addr_format);
@ -1025,6 +1025,13 @@ void MacroAssembler::testbit(Register r, unsigned int bitPos) {
}
}
void MacroAssembler::prefetch_read(Address a) {
z_pfd(1, a.disp20(), a.indexOrR0(), a.base());
}
void MacroAssembler::prefetch_update(Address a) {
z_pfd(2, a.disp20(), a.indexOrR0(), a.base());
}
// Clear a register, i.e. load const zero into reg.
// Return len (in bytes) of generated instruction(s).
// whole_reg: Clear 64 bits if true, 32 bits otherwise.
@ -4896,77 +4903,295 @@ unsigned int MacroAssembler::CopyRawMemory_AlignedDisjoint(Register src_reg, Reg
// Intrinsics for CompactStrings
// Compress char[] to byte[]. odd_reg contains cnt. Kills dst. Early clobber: result
// Compress char[] to byte[].
// Restores: src, dst
// Uses: cnt
// Kills: tmp, Z_R0, Z_R1.
// Early clobber: result.
// Note:
// cnt is signed int. Do not rely on high word!
// counts # characters, not bytes.
// The result is the number of characters copied before the first incompatible character was found.
// If tmp2 is provided and the compression fails, the compression stops exactly at this point and the result is precise.
// If precise is true, the processing stops exactly at this point. Otherwise, the result may be off
// by a few bytes. The result always indicates the number of copied characters.
//
// Note: Does not behave exactly like package private StringUTF16 compress java implementation in case of failure:
// - Different number of characters may have been written to dead array (if tmp2 not provided).
// - Different number of characters may have been written to dead array (if precise is false).
// - Returns a number <cnt instead of 0. (Result gets compared with cnt.)
unsigned int MacroAssembler::string_compress(Register result, Register src, Register dst, Register odd_reg,
Register even_reg, Register tmp, Register tmp2) {
int block_start = offset();
Label Lloop1, Lloop2, Lslow, Ldone;
const Register addr2 = dst, ind1 = result, mask = tmp;
const bool precise = (tmp2 != noreg);
unsigned int MacroAssembler::string_compress(Register result, Register src, Register dst, Register cnt,
Register tmp, bool precise) {
assert_different_registers(Z_R0, Z_R1, src, dst, cnt, tmp);
BLOCK_COMMENT("string_compress {");
z_sll(odd_reg, 1); // Number of bytes to read. (Must be a positive simm32.)
clear_reg(ind1); // Index to read.
z_llilf(mask, 0xFF00FF00);
z_ahi(odd_reg, -16); // Last possible index for fast loop.
z_brl(Lslow);
// ind1: index, even_reg: index increment, odd_reg: index limit
z_iihf(mask, 0xFF00FF00);
z_lhi(even_reg, 16);
bind(Lloop1); // 8 Characters per iteration.
z_lg(Z_R0, Address(src, ind1));
z_lg(Z_R1, Address(src, ind1, 8));
if (precise) {
BLOCK_COMMENT("encode_iso_array {");
} else {
BLOCK_COMMENT("string_compress {");
}
int block_start = offset();
Register Rsrc = src;
Register Rdst = dst;
Register Rix = tmp;
Register Rcnt = cnt;
Register Rmask = result; // holds incompatibility check mask until result value is stored.
Label ScalarShortcut, AllDone;
z_iilf(Rmask, 0xFF00FF00);
z_iihf(Rmask, 0xFF00FF00);
#if 0 // Sacrifice shortcuts for code compactness
{
//---< shortcuts for short strings (very frequent) >---
// Strings with 4 and 8 characters were fond to occur very frequently.
// Therefore, we handle them right away with minimal overhead.
Label skipShortcut, skip4Shortcut, skip8Shortcut;
Register Rout = Z_R0;
z_chi(Rcnt, 4);
z_brne(skip4Shortcut); // 4 characters are very frequent
z_lg(Z_R0, 0, Rsrc); // Treat exactly 4 characters specially.
if (VM_Version::has_DistinctOpnds()) {
Rout = Z_R0;
z_ngrk(Rix, Z_R0, Rmask);
} else {
Rout = Rix;
z_lgr(Rix, Z_R0);
z_ngr(Z_R0, Rmask);
}
z_brnz(skipShortcut);
z_stcmh(Rout, 5, 0, Rdst);
z_stcm(Rout, 5, 2, Rdst);
z_lgfr(result, Rcnt);
z_bru(AllDone);
bind(skip4Shortcut);
z_chi(Rcnt, 8);
z_brne(skip8Shortcut); // There's more to do...
z_lmg(Z_R0, Z_R1, 0, Rsrc); // Treat exactly 8 characters specially.
if (VM_Version::has_DistinctOpnds()) {
Rout = Z_R0;
z_ogrk(Rix, Z_R0, Z_R1);
z_ngr(Rix, Rmask);
} else {
Rout = Rix;
z_lgr(Rix, Z_R0);
z_ogr(Z_R0, Z_R1);
z_ngr(Z_R0, Rmask);
}
z_brnz(skipShortcut);
z_stcmh(Rout, 5, 0, Rdst);
z_stcm(Rout, 5, 2, Rdst);
z_stcmh(Z_R1, 5, 4, Rdst);
z_stcm(Z_R1, 5, 6, Rdst);
z_lgfr(result, Rcnt);
z_bru(AllDone);
bind(skip8Shortcut);
clear_reg(Z_R0, true, false); // #characters already processed (none). Precond for scalar loop.
z_brl(ScalarShortcut); // Just a few characters
bind(skipShortcut);
}
#endif
clear_reg(Z_R0); // make sure register is properly initialized.
if (VM_Version::has_VectorFacility()) {
const int min_vcnt = 32; // Minimum #characters required to use vector instructions.
// Otherwise just do nothing in vector mode.
// Must be multiple of 2*(vector register length in chars (8 HW = 128 bits)).
const int log_min_vcnt = exact_log2(min_vcnt);
Label VectorLoop, VectorDone, VectorBreak;
VectorRegister Vtmp1 = Z_V16;
VectorRegister Vtmp2 = Z_V17;
VectorRegister Vmask = Z_V18;
VectorRegister Vzero = Z_V19;
VectorRegister Vsrc_first = Z_V20;
VectorRegister Vsrc_last = Z_V23;
assert((Vsrc_last->encoding() - Vsrc_first->encoding() + 1) == min_vcnt/8, "logic error");
assert(VM_Version::has_DistinctOpnds(), "Assumption when has_VectorFacility()");
z_srak(Rix, Rcnt, log_min_vcnt); // # vector loop iterations
z_brz(VectorDone); // not enough data for vector loop
z_vzero(Vzero); // all zeroes
z_vgmh(Vmask, 0, 7); // generate 0xff00 mask for all 2-byte elements
z_sllg(Z_R0, Rix, log_min_vcnt); // remember #chars that will be processed by vector loop
bind(VectorLoop);
z_vlm(Vsrc_first, Vsrc_last, 0, Rsrc);
add2reg(Rsrc, min_vcnt*2);
//---< check for incompatible character >---
z_vo(Vtmp1, Z_V20, Z_V21);
z_vo(Vtmp2, Z_V22, Z_V23);
z_vo(Vtmp1, Vtmp1, Vtmp2);
z_vn(Vtmp1, Vtmp1, Vmask);
z_vceqhs(Vtmp1, Vtmp1, Vzero); // high half of all chars must be zero for successful compress.
z_brne(VectorBreak); // break vector loop, incompatible character found.
// re-process data from current iteration in break handler.
//---< pack & store characters >---
z_vpkh(Vtmp1, Z_V20, Z_V21); // pack (src1, src2) -> tmp1
z_vpkh(Vtmp2, Z_V22, Z_V23); // pack (src3, src4) -> tmp2
z_vstm(Vtmp1, Vtmp2, 0, Rdst); // store packed string
add2reg(Rdst, min_vcnt);
z_brct(Rix, VectorLoop);
z_bru(VectorDone);
bind(VectorBreak);
z_sll(Rix, log_min_vcnt); // # chars processed so far in VectorLoop, excl. current iteration.
z_sr(Z_R0, Rix); // correct # chars processed in total.
bind(VectorDone);
}
{
const int min_cnt = 8; // Minimum #characters required to use unrolled loop.
// Otherwise just do nothing in unrolled loop.
// Must be multiple of 8.
const int log_min_cnt = exact_log2(min_cnt);
Label UnrolledLoop, UnrolledDone, UnrolledBreak;
if (VM_Version::has_DistinctOpnds()) {
z_ogrk(tmp2, Z_R0, Z_R1);
z_srk(Rix, Rcnt, Z_R0); // remaining # chars to compress in unrolled loop
} else {
z_lgr(tmp2, Z_R0);
z_ogr(tmp2, Z_R1);
z_lr(Rix, Rcnt);
z_sr(Rix, Z_R0);
}
z_ngr(tmp2, mask);
z_brne(Lslow); // Failed fast case, retry slowly.
z_sra(Rix, log_min_cnt); // unrolled loop count
z_brz(UnrolledDone);
bind(UnrolledLoop);
z_lmg(Z_R0, Z_R1, 0, Rsrc);
if (precise) {
z_ogr(Z_R1, Z_R0); // check all 8 chars for incompatibility
z_ngr(Z_R1, Rmask);
z_brnz(UnrolledBreak);
z_lg(Z_R1, 8, Rsrc); // reload destroyed register
z_stcmh(Z_R0, 5, 0, Rdst);
z_stcm(Z_R0, 5, 2, Rdst);
} else {
z_stcmh(Z_R0, 5, 0, Rdst);
z_stcm(Z_R0, 5, 2, Rdst);
z_ogr(Z_R0, Z_R1);
z_ngr(Z_R0, Rmask);
z_brnz(UnrolledBreak);
}
z_stcmh(Z_R1, 5, 4, Rdst);
z_stcm(Z_R1, 5, 6, Rdst);
add2reg(Rsrc, min_cnt*2);
add2reg(Rdst, min_cnt);
z_brct(Rix, UnrolledLoop);
z_lgfr(Z_R0, Rcnt); // # chars processed in total after unrolled loop.
z_nilf(Z_R0, ~(min_cnt-1));
z_tmll(Rcnt, min_cnt-1);
z_brnaz(ScalarShortcut); // if all bits zero, there is nothing left to do for scalar loop.
// Rix == 0 in all cases.
z_lgfr(result, Rcnt); // all characters processed.
z_sgfr(Rdst, Rcnt); // restore ptr
z_sgfr(Rsrc, Rcnt); // restore ptr, double the element count for Rsrc restore
z_sgfr(Rsrc, Rcnt);
z_bru(AllDone);
bind(UnrolledBreak);
z_lgfr(Z_R0, Rcnt); // # chars processed in total after unrolled loop
z_nilf(Z_R0, ~(min_cnt-1));
z_sll(Rix, log_min_cnt); // # chars processed so far in UnrolledLoop, excl. current iteration.
z_sr(Z_R0, Rix); // correct # chars processed in total.
if (!precise) {
z_lgfr(result, Z_R0);
z_aghi(result, min_cnt/2); // min_cnt/2 characters have already been written
// but ptrs were not updated yet.
z_sgfr(Rdst, Z_R0); // restore ptr
z_sgfr(Rsrc, Z_R0); // restore ptr, double the element count for Rsrc restore
z_sgfr(Rsrc, Z_R0);
z_bru(AllDone);
}
bind(UnrolledDone);
}
z_stcmh(Z_R0, 5, 0, addr2);
z_stcm(Z_R0, 5, 2, addr2);
if (!precise) { z_ogr(Z_R0, Z_R1); }
z_stcmh(Z_R1, 5, 4, addr2);
z_stcm(Z_R1, 5, 6, addr2);
if (!precise) {
z_ngr(Z_R0, mask);
z_brne(Ldone); // Failed (more than needed was written).
{
Label ScalarLoop, ScalarDone, ScalarBreak;
bind(ScalarShortcut);
z_ltgfr(result, Rcnt);
z_brz(AllDone);
#if 0 // Sacrifice shortcuts for code compactness
{
//---< Special treatment for very short strings (one or two characters) >---
// For these strings, we are sure that the above code was skipped.
// Thus, no registers were modified, register restore is not required.
Label ScalarDoit, Scalar2Char;
z_chi(Rcnt, 2);
z_brh(ScalarDoit);
z_llh(Z_R1, 0, Z_R0, Rsrc);
z_bre(Scalar2Char);
z_tmll(Z_R1, 0xff00);
z_lghi(result, 0); // cnt == 1, first char invalid, no chars successfully processed
z_brnaz(AllDone);
z_stc(Z_R1, 0, Z_R0, Rdst);
z_lghi(result, 1);
z_bru(AllDone);
bind(Scalar2Char);
z_llh(Z_R0, 2, Z_R0, Rsrc);
z_tmll(Z_R1, 0xff00);
z_lghi(result, 0); // cnt == 2, first char invalid, no chars successfully processed
z_brnaz(AllDone);
z_stc(Z_R1, 0, Z_R0, Rdst);
z_tmll(Z_R0, 0xff00);
z_lghi(result, 1); // cnt == 2, second char invalid, one char successfully processed
z_brnaz(AllDone);
z_stc(Z_R0, 1, Z_R0, Rdst);
z_lghi(result, 2);
z_bru(AllDone);
bind(ScalarDoit);
}
#endif
if (VM_Version::has_DistinctOpnds()) {
z_srk(Rix, Rcnt, Z_R0); // remaining # chars to compress in unrolled loop
} else {
z_lr(Rix, Rcnt);
z_sr(Rix, Z_R0);
}
z_lgfr(result, Rcnt); // # processed characters (if all runs ok).
z_brz(ScalarDone);
bind(ScalarLoop);
z_llh(Z_R1, 0, Z_R0, Rsrc);
z_tmll(Z_R1, 0xff00);
z_brnaz(ScalarBreak);
z_stc(Z_R1, 0, Z_R0, Rdst);
add2reg(Rsrc, 2);
add2reg(Rdst, 1);
z_brct(Rix, ScalarLoop);
z_bru(ScalarDone);
bind(ScalarBreak);
z_sr(result, Rix);
bind(ScalarDone);
z_sgfr(Rdst, result); // restore ptr
z_sgfr(Rsrc, result); // restore ptr, double the element count for Rsrc restore
z_sgfr(Rsrc, result);
}
z_aghi(addr2, 8);
z_brxle(ind1, even_reg, Lloop1);
bind(Lslow);
// Compute index limit and skip if negative.
z_ahi(odd_reg, 16-2); // Last possible index for slow loop.
z_lhi(even_reg, 2);
z_cr(ind1, odd_reg);
z_brh(Ldone);
bind(Lloop2); // 1 Character per iteration.
z_llh(Z_R0, Address(src, ind1));
z_tmll(Z_R0, 0xFF00);
z_brnaz(Ldone); // Failed slow case: Return number of written characters.
z_stc(Z_R0, Address(addr2));
z_aghi(addr2, 1);
z_brxle(ind1, even_reg, Lloop2);
bind(Ldone); // result = ind1 = 2*cnt
z_srl(ind1, 1);
BLOCK_COMMENT("} string_compress");
bind(AllDone);
if (precise) {
BLOCK_COMMENT("} encode_iso_array");
} else {
BLOCK_COMMENT("} string_compress");
}
return offset() - block_start;
}
@ -4997,53 +5222,432 @@ unsigned int MacroAssembler::string_inflate_trot(Register src, Register dst, Reg
return offset() - block_start;
}
// Inflate byte[] to char[]. odd_reg contains cnt. Kills src.
unsigned int MacroAssembler::string_inflate(Register src, Register dst, Register odd_reg,
Register even_reg, Register tmp) {
int block_start = offset();
// Inflate byte[] to char[].
// Restores: src, dst
// Uses: cnt
// Kills: tmp, Z_R0, Z_R1.
// Note:
// cnt is signed int. Do not rely on high word!
// counts # characters, not bytes.
unsigned int MacroAssembler::string_inflate(Register src, Register dst, Register cnt, Register tmp) {
assert_different_registers(Z_R0, Z_R1, src, dst, cnt, tmp);
BLOCK_COMMENT("string_inflate {");
int block_start = offset();
Label Lloop1, Lloop2, Lslow, Ldone;
const Register addr1 = src, ind2 = tmp;
Register Rcnt = cnt; // # characters (src: bytes, dst: char (2-byte)), remaining after current loop.
Register Rix = tmp; // loop index
Register Rsrc = src; // addr(src array)
Register Rdst = dst; // addr(dst array)
Label ScalarShortcut, AllDone;
z_sll(odd_reg, 1); // Number of bytes to write. (Must be a positive simm32.)
clear_reg(ind2); // Index to write.
z_ahi(odd_reg, -16); // Last possible index for fast loop.
z_brl(Lslow);
#if 0 // Sacrifice shortcuts for code compactness
{
//---< shortcuts for short strings (very frequent) >---
Label skipShortcut, skip4Shortcut;
z_ltr(Rcnt, Rcnt); // absolutely nothing to do for strings of len == 0.
z_brz(AllDone);
clear_reg(Z_R0); // make sure registers are properly initialized.
clear_reg(Z_R1);
z_chi(Rcnt, 4);
z_brne(skip4Shortcut); // 4 characters are very frequent
z_icm(Z_R0, 5, 0, Rsrc); // Treat exactly 4 characters specially.
z_icm(Z_R1, 5, 2, Rsrc);
z_stm(Z_R0, Z_R1, 0, Rdst);
z_bru(AllDone);
bind(skip4Shortcut);
// ind2: index, even_reg: index increment, odd_reg: index limit
clear_reg(Z_R0);
clear_reg(Z_R1);
z_lhi(even_reg, 16);
z_chi(Rcnt, 8);
z_brh(skipShortcut); // There's a lot to do...
z_lgfr(Z_R0, Rcnt); // remaining #characters (<= 8). Precond for scalar loop.
// This does not destroy the "register cleared" state of Z_R0.
z_brl(ScalarShortcut); // Just a few characters
z_icmh(Z_R0, 5, 0, Rsrc); // Treat exactly 8 characters specially.
z_icmh(Z_R1, 5, 4, Rsrc);
z_icm(Z_R0, 5, 2, Rsrc);
z_icm(Z_R1, 5, 6, Rsrc);
z_stmg(Z_R0, Z_R1, 0, Rdst);
z_bru(AllDone);
bind(skipShortcut);
}
#endif
clear_reg(Z_R0); // make sure register is properly initialized.
bind(Lloop1); // 8 Characters per iteration.
z_icmh(Z_R0, 5, 0, addr1);
z_icmh(Z_R1, 5, 4, addr1);
z_icm(Z_R0, 5, 2, addr1);
z_icm(Z_R1, 5, 6, addr1);
z_aghi(addr1, 8);
z_stg(Z_R0, Address(dst, ind2));
z_stg(Z_R1, Address(dst, ind2, 8));
z_brxle(ind2, even_reg, Lloop1);
if (VM_Version::has_VectorFacility()) {
const int min_vcnt = 32; // Minimum #characters required to use vector instructions.
// Otherwise just do nothing in vector mode.
// Must be multiple of vector register length (16 bytes = 128 bits).
const int log_min_vcnt = exact_log2(min_vcnt);
Label VectorLoop, VectorDone;
bind(Lslow);
// Compute index limit and skip if negative.
z_ahi(odd_reg, 16-2); // Last possible index for slow loop.
z_lhi(even_reg, 2);
z_cr(ind2, odd_reg);
z_brh(Ldone);
assert(VM_Version::has_DistinctOpnds(), "Assumption when has_VectorFacility()");
z_srak(Rix, Rcnt, log_min_vcnt); // calculate # vector loop iterations
z_brz(VectorDone); // skip if none
bind(Lloop2); // 1 Character per iteration.
z_llc(Z_R0, Address(addr1));
z_sth(Z_R0, Address(dst, ind2));
z_aghi(addr1, 1);
z_brxle(ind2, even_reg, Lloop2);
z_sllg(Z_R0, Rix, log_min_vcnt); // remember #chars that will be processed by vector loop
bind(Ldone);
bind(VectorLoop);
z_vlm(Z_V20, Z_V21, 0, Rsrc); // get next 32 characters (single-byte)
add2reg(Rsrc, min_vcnt);
z_vuplhb(Z_V22, Z_V20); // V2 <- (expand) V0(high)
z_vupllb(Z_V23, Z_V20); // V3 <- (expand) V0(low)
z_vuplhb(Z_V24, Z_V21); // V4 <- (expand) V1(high)
z_vupllb(Z_V25, Z_V21); // V5 <- (expand) V1(low)
z_vstm(Z_V22, Z_V25, 0, Rdst); // store next 32 bytes
add2reg(Rdst, min_vcnt*2);
z_brct(Rix, VectorLoop);
bind(VectorDone);
}
const int min_cnt = 8; // Minimum #characters required to use unrolled scalar loop.
// Otherwise just do nothing in unrolled scalar mode.
// Must be multiple of 8.
{
const int log_min_cnt = exact_log2(min_cnt);
Label UnrolledLoop, UnrolledDone;
if (VM_Version::has_DistinctOpnds()) {
z_srk(Rix, Rcnt, Z_R0); // remaining # chars to process in unrolled loop
} else {
z_lr(Rix, Rcnt);
z_sr(Rix, Z_R0);
}
z_sra(Rix, log_min_cnt); // unrolled loop count
z_brz(UnrolledDone);
clear_reg(Z_R0);
clear_reg(Z_R1);
bind(UnrolledLoop);
z_icmh(Z_R0, 5, 0, Rsrc);
z_icmh(Z_R1, 5, 4, Rsrc);
z_icm(Z_R0, 5, 2, Rsrc);
z_icm(Z_R1, 5, 6, Rsrc);
add2reg(Rsrc, min_cnt);
z_stmg(Z_R0, Z_R1, 0, Rdst);
add2reg(Rdst, min_cnt*2);
z_brct(Rix, UnrolledLoop);
bind(UnrolledDone);
z_lgfr(Z_R0, Rcnt); // # chars left over after unrolled loop.
z_nilf(Z_R0, min_cnt-1);
z_brnz(ScalarShortcut); // if zero, there is nothing left to do for scalar loop.
// Rix == 0 in all cases.
z_sgfr(Z_R0, Rcnt); // negative # characters the ptrs have been advanced previously.
z_agr(Rdst, Z_R0); // restore ptr, double the element count for Rdst restore.
z_agr(Rdst, Z_R0);
z_agr(Rsrc, Z_R0); // restore ptr.
z_bru(AllDone);
}
{
bind(ScalarShortcut);
// Z_R0 must contain remaining # characters as 64-bit signed int here.
// register contents is preserved over scalar processing (for register fixup).
#if 0 // Sacrifice shortcuts for code compactness
{
Label ScalarDefault;
z_chi(Rcnt, 2);
z_brh(ScalarDefault);
z_llc(Z_R0, 0, Z_R0, Rsrc); // 6 bytes
z_sth(Z_R0, 0, Z_R0, Rdst); // 4 bytes
z_brl(AllDone);
z_llc(Z_R0, 1, Z_R0, Rsrc); // 6 bytes
z_sth(Z_R0, 2, Z_R0, Rdst); // 4 bytes
z_bru(AllDone);
bind(ScalarDefault);
}
#endif
Label CodeTable;
// Some comments on Rix calculation:
// - Rcnt is small, therefore no bits shifted out of low word (sll(g) instructions).
// - high word of both Rix and Rcnt may contain garbage
// - the final lngfr takes care of that garbage, extending the sign to high word
z_sllg(Rix, Z_R0, 2); // calculate 10*Rix = (4*Rix + Rix)*2
z_ar(Rix, Z_R0);
z_larl(Z_R1, CodeTable);
z_sll(Rix, 1);
z_lngfr(Rix, Rix); // ix range: [0..7], after inversion & mult: [-(7*12)..(0*12)].
z_bc(Assembler::bcondAlways, 0, Rix, Z_R1);
z_llc(Z_R1, 6, Z_R0, Rsrc); // 6 bytes
z_sth(Z_R1, 12, Z_R0, Rdst); // 4 bytes
z_llc(Z_R1, 5, Z_R0, Rsrc);
z_sth(Z_R1, 10, Z_R0, Rdst);
z_llc(Z_R1, 4, Z_R0, Rsrc);
z_sth(Z_R1, 8, Z_R0, Rdst);
z_llc(Z_R1, 3, Z_R0, Rsrc);
z_sth(Z_R1, 6, Z_R0, Rdst);
z_llc(Z_R1, 2, Z_R0, Rsrc);
z_sth(Z_R1, 4, Z_R0, Rdst);
z_llc(Z_R1, 1, Z_R0, Rsrc);
z_sth(Z_R1, 2, Z_R0, Rdst);
z_llc(Z_R1, 0, Z_R0, Rsrc);
z_sth(Z_R1, 0, Z_R0, Rdst);
bind(CodeTable);
z_chi(Rcnt, 8); // no fixup for small strings. Rdst, Rsrc were not modified.
z_brl(AllDone);
z_sgfr(Z_R0, Rcnt); // # characters the ptrs have been advanced previously.
z_agr(Rdst, Z_R0); // restore ptr, double the element count for Rdst restore.
z_agr(Rdst, Z_R0);
z_agr(Rsrc, Z_R0); // restore ptr.
}
bind(AllDone);
BLOCK_COMMENT("} string_inflate");
return offset() - block_start;
}
// Inflate byte[] to char[], length known at compile time.
// Restores: src, dst
// Kills: tmp, Z_R0, Z_R1.
// Note:
// len is signed int. Counts # characters, not bytes.
unsigned int MacroAssembler::string_inflate_const(Register src, Register dst, Register tmp, int len) {
assert_different_registers(Z_R0, Z_R1, src, dst, tmp);
BLOCK_COMMENT("string_inflate_const {");
int block_start = offset();
Register Rix = tmp; // loop index
Register Rsrc = src; // addr(src array)
Register Rdst = dst; // addr(dst array)
Label ScalarShortcut, AllDone;
int nprocessed = 0;
int src_off = 0; // compensate for saved (optimized away) ptr advancement.
int dst_off = 0; // compensate for saved (optimized away) ptr advancement.
bool restore_inputs = false;
bool workreg_clear = false;
if ((len >= 32) && VM_Version::has_VectorFacility()) {
const int min_vcnt = 32; // Minimum #characters required to use vector instructions.
// Otherwise just do nothing in vector mode.
// Must be multiple of vector register length (16 bytes = 128 bits).
const int log_min_vcnt = exact_log2(min_vcnt);
const int iterations = (len - nprocessed) >> log_min_vcnt;
nprocessed += iterations << log_min_vcnt;
Label VectorLoop;
if (iterations == 1) {
z_vlm(Z_V20, Z_V21, 0+src_off, Rsrc); // get next 32 characters (single-byte)
z_vuplhb(Z_V22, Z_V20); // V2 <- (expand) V0(high)
z_vupllb(Z_V23, Z_V20); // V3 <- (expand) V0(low)
z_vuplhb(Z_V24, Z_V21); // V4 <- (expand) V1(high)
z_vupllb(Z_V25, Z_V21); // V5 <- (expand) V1(low)
z_vstm(Z_V22, Z_V25, 0+dst_off, Rdst); // store next 32 bytes
src_off += min_vcnt;
dst_off += min_vcnt*2;
} else {
restore_inputs = true;
z_lgfi(Rix, len>>log_min_vcnt);
bind(VectorLoop);
z_vlm(Z_V20, Z_V21, 0, Rsrc); // get next 32 characters (single-byte)
add2reg(Rsrc, min_vcnt);
z_vuplhb(Z_V22, Z_V20); // V2 <- (expand) V0(high)
z_vupllb(Z_V23, Z_V20); // V3 <- (expand) V0(low)
z_vuplhb(Z_V24, Z_V21); // V4 <- (expand) V1(high)
z_vupllb(Z_V25, Z_V21); // V5 <- (expand) V1(low)
z_vstm(Z_V22, Z_V25, 0, Rdst); // store next 32 bytes
add2reg(Rdst, min_vcnt*2);
z_brct(Rix, VectorLoop);
}
}
if (((len-nprocessed) >= 16) && VM_Version::has_VectorFacility()) {
const int min_vcnt = 16; // Minimum #characters required to use vector instructions.
// Otherwise just do nothing in vector mode.
// Must be multiple of vector register length (16 bytes = 128 bits).
const int log_min_vcnt = exact_log2(min_vcnt);
const int iterations = (len - nprocessed) >> log_min_vcnt;
nprocessed += iterations << log_min_vcnt;
assert(iterations == 1, "must be!");
z_vl(Z_V20, 0+src_off, Z_R0, Rsrc); // get next 16 characters (single-byte)
z_vuplhb(Z_V22, Z_V20); // V2 <- (expand) V0(high)
z_vupllb(Z_V23, Z_V20); // V3 <- (expand) V0(low)
z_vstm(Z_V22, Z_V23, 0+dst_off, Rdst); // store next 32 bytes
src_off += min_vcnt;
dst_off += min_vcnt*2;
}
if ((len-nprocessed) > 8) {
const int min_cnt = 8; // Minimum #characters required to use unrolled scalar loop.
// Otherwise just do nothing in unrolled scalar mode.
// Must be multiple of 8.
const int log_min_cnt = exact_log2(min_cnt);
const int iterations = (len - nprocessed) >> log_min_cnt;
nprocessed += iterations << log_min_cnt;
//---< avoid loop overhead/ptr increment for small # iterations >---
if (iterations <= 2) {
clear_reg(Z_R0);
clear_reg(Z_R1);
workreg_clear = true;
z_icmh(Z_R0, 5, 0+src_off, Rsrc);
z_icmh(Z_R1, 5, 4+src_off, Rsrc);
z_icm(Z_R0, 5, 2+src_off, Rsrc);
z_icm(Z_R1, 5, 6+src_off, Rsrc);
z_stmg(Z_R0, Z_R1, 0+dst_off, Rdst);
src_off += min_cnt;
dst_off += min_cnt*2;
}
if (iterations == 2) {
z_icmh(Z_R0, 5, 0+src_off, Rsrc);
z_icmh(Z_R1, 5, 4+src_off, Rsrc);
z_icm(Z_R0, 5, 2+src_off, Rsrc);
z_icm(Z_R1, 5, 6+src_off, Rsrc);
z_stmg(Z_R0, Z_R1, 0+dst_off, Rdst);
src_off += min_cnt;
dst_off += min_cnt*2;
}
if (iterations > 2) {
Label UnrolledLoop;
restore_inputs = true;
clear_reg(Z_R0);
clear_reg(Z_R1);
workreg_clear = true;
z_lgfi(Rix, iterations);
bind(UnrolledLoop);
z_icmh(Z_R0, 5, 0, Rsrc);
z_icmh(Z_R1, 5, 4, Rsrc);
z_icm(Z_R0, 5, 2, Rsrc);
z_icm(Z_R1, 5, 6, Rsrc);
add2reg(Rsrc, min_cnt);
z_stmg(Z_R0, Z_R1, 0, Rdst);
add2reg(Rdst, min_cnt*2);
z_brct(Rix, UnrolledLoop);
}
}
if ((len-nprocessed) > 0) {
switch (len-nprocessed) {
case 8:
if (!workreg_clear) {
clear_reg(Z_R0);
clear_reg(Z_R1);
}
z_icmh(Z_R0, 5, 0+src_off, Rsrc);
z_icmh(Z_R1, 5, 4+src_off, Rsrc);
z_icm(Z_R0, 5, 2+src_off, Rsrc);
z_icm(Z_R1, 5, 6+src_off, Rsrc);
z_stmg(Z_R0, Z_R1, 0+dst_off, Rdst);
break;
case 7:
if (!workreg_clear) {
clear_reg(Z_R0);
clear_reg(Z_R1);
}
clear_reg(Rix);
z_icm(Z_R0, 5, 0+src_off, Rsrc);
z_icm(Z_R1, 5, 2+src_off, Rsrc);
z_icm(Rix, 5, 4+src_off, Rsrc);
z_stm(Z_R0, Z_R1, 0+dst_off, Rdst);
z_llc(Z_R0, 6+src_off, Z_R0, Rsrc);
z_st(Rix, 8+dst_off, Z_R0, Rdst);
z_sth(Z_R0, 12+dst_off, Z_R0, Rdst);
break;
case 6:
if (!workreg_clear) {
clear_reg(Z_R0);
clear_reg(Z_R1);
}
clear_reg(Rix);
z_icm(Z_R0, 5, 0+src_off, Rsrc);
z_icm(Z_R1, 5, 2+src_off, Rsrc);
z_icm(Rix, 5, 4+src_off, Rsrc);
z_stm(Z_R0, Z_R1, 0+dst_off, Rdst);
z_st(Rix, 8+dst_off, Z_R0, Rdst);
break;
case 5:
if (!workreg_clear) {
clear_reg(Z_R0);
clear_reg(Z_R1);
}
z_icm(Z_R0, 5, 0+src_off, Rsrc);
z_icm(Z_R1, 5, 2+src_off, Rsrc);
z_llc(Rix, 4+src_off, Z_R0, Rsrc);
z_stm(Z_R0, Z_R1, 0+dst_off, Rdst);
z_sth(Rix, 8+dst_off, Z_R0, Rdst);
break;
case 4:
if (!workreg_clear) {
clear_reg(Z_R0);
clear_reg(Z_R1);
}
z_icm(Z_R0, 5, 0+src_off, Rsrc);
z_icm(Z_R1, 5, 2+src_off, Rsrc);
z_stm(Z_R0, Z_R1, 0+dst_off, Rdst);
break;
case 3:
if (!workreg_clear) {
clear_reg(Z_R0);
}
z_llc(Z_R1, 2+src_off, Z_R0, Rsrc);
z_icm(Z_R0, 5, 0+src_off, Rsrc);
z_sth(Z_R1, 4+dst_off, Z_R0, Rdst);
z_st(Z_R0, 0+dst_off, Rdst);
break;
case 2:
z_llc(Z_R0, 0+src_off, Z_R0, Rsrc);
z_llc(Z_R1, 1+src_off, Z_R0, Rsrc);
z_sth(Z_R0, 0+dst_off, Z_R0, Rdst);
z_sth(Z_R1, 2+dst_off, Z_R0, Rdst);
break;
case 1:
z_llc(Z_R0, 0+src_off, Z_R0, Rsrc);
z_sth(Z_R0, 0+dst_off, Z_R0, Rdst);
break;
default:
guarantee(false, "Impossible");
break;
}
src_off += len-nprocessed;
dst_off += (len-nprocessed)*2;
nprocessed = len;
}
//---< restore modified input registers >---
if ((nprocessed > 0) && restore_inputs) {
z_agfi(Rsrc, -(nprocessed-src_off));
if (nprocessed < 1000000000) { // avoid int overflow
z_agfi(Rdst, -(nprocessed*2-dst_off));
} else {
z_agfi(Rdst, -(nprocessed-dst_off));
z_agfi(Rdst, -nprocessed);
}
}
BLOCK_COMMENT("} string_inflate_const");
return offset() - block_start;
}

View File

@ -198,6 +198,9 @@ class MacroAssembler: public Assembler {
// Test a bit in a register. Result is reflected in CC.
void testbit(Register r, unsigned int bitPos);
void prefetch_read(Address a);
void prefetch_update(Address a);
// Clear a register, i.e. load const zero into reg. Return len (in bytes) of
// generated instruction(s).
// whole_reg: Clear 64 bits if true, 32 bits otherwise.
@ -836,7 +839,7 @@ class MacroAssembler: public Assembler {
void load_mirror(Register mirror, Register method);
//--------------------------
//--- perations on arrays.
//--- Operations on arrays.
//--------------------------
unsigned int Clear_Array(Register cnt_arg, Register base_pointer_arg, Register src_addr, Register src_len);
unsigned int Clear_Array_Const(long cnt, Register base);
@ -849,20 +852,34 @@ class MacroAssembler: public Assembler {
// Special String Intrinsics Implementation.
//-------------------------------------------
// Intrinsics for CompactStrings
// Compress char[] to byte[]. odd_reg contains cnt. tmp3 is only needed for precise behavior in failure case. Kills dst.
unsigned int string_compress(Register result, Register src, Register dst, Register odd_reg,
Register even_reg, Register tmp, Register tmp2 = noreg);
// Restores: src, dst
// Uses: cnt
// Kills: tmp, Z_R0, Z_R1.
// Early clobber: result.
// Boolean precise controls accuracy of result value.
unsigned int string_compress(Register result, Register src, Register dst, Register cnt,
Register tmp, bool precise);
// Inflate byte[] to char[].
unsigned int string_inflate_trot(Register src, Register dst, Register cnt, Register tmp);
// Inflate byte[] to char[].
// Restores: src, dst
// Uses: cnt
// Kills: tmp, Z_R0, Z_R1.
unsigned int string_inflate(Register src, Register dst, Register cnt, Register tmp);
// Inflate byte[] to char[], length known at compile time.
// Restores: src, dst
// Kills: tmp, Z_R0, Z_R1.
// Note:
// len is signed int. Counts # characters, not bytes.
unsigned int string_inflate_const(Register src, Register dst, Register tmp, int len);
// Kills src.
unsigned int has_negatives(Register result, Register src, Register cnt,
Register odd_reg, Register even_reg, Register tmp);
// Inflate byte[] to char[].
unsigned int string_inflate_trot(Register src, Register dst, Register cnt, Register tmp);
// Odd_reg contains cnt. Kills src.
unsigned int string_inflate(Register src, Register dst, Register odd_reg,
Register even_reg, Register tmp);
unsigned int string_compare(Register str1, Register str2, Register cnt1, Register cnt2,
Register odd_reg, Register even_reg, Register result, int ae);

View File

@ -10267,14 +10267,14 @@ instruct indexOf_UL(iRegP haystack, rarg2RegI haycnt, iRegP needle, rarg5RegI ne
%}
// char[] to byte[] compression
instruct string_compress(iRegP src, rarg5RegP dst, iRegI result, roddRegI len, revenRegI evenReg, iRegI tmp, flagsReg cr) %{
instruct string_compress(iRegP src, iRegP dst, iRegI result, iRegI len, iRegI tmp, flagsReg cr) %{
match(Set result (StrCompressedCopy src (Binary dst len)));
effect(TEMP_DEF result, USE_KILL dst, USE_KILL len, TEMP evenReg, TEMP tmp, KILL cr); // R0, R1 are killed, too.
effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too.
ins_cost(300);
format %{ "String Compress $src->$dst($len) -> $result" %}
ins_encode %{
__ string_compress($result$$Register, $src$$Register, $dst$$Register, $len$$Register,
$evenReg$$Register, $tmp$$Register);
$tmp$$Register, false);
%}
ins_pipe(pipe_class_dummy);
%}
@ -10293,13 +10293,25 @@ instruct string_compress(iRegP src, rarg5RegP dst, iRegI result, roddRegI len, r
//%}
// byte[] to char[] inflation
instruct string_inflate(Universe dummy, rarg5RegP src, iRegP dst, roddRegI len, revenRegI evenReg, iRegI tmp, flagsReg cr) %{
instruct string_inflate(Universe dummy, iRegP src, iRegP dst, iRegI len, iRegI tmp, flagsReg cr) %{
match(Set dummy (StrInflatedCopy src (Binary dst len)));
effect(USE_KILL src, USE_KILL len, TEMP evenReg, TEMP tmp, KILL cr); // R0, R1 are killed, too.
effect(TEMP tmp, KILL cr); // R0, R1 are killed, too.
ins_cost(300);
format %{ "String Inflate $src->$dst($len)" %}
ins_encode %{
__ string_inflate($src$$Register, $dst$$Register, $len$$Register, $evenReg$$Register, $tmp$$Register);
__ string_inflate($src$$Register, $dst$$Register, $len$$Register, $tmp$$Register);
%}
ins_pipe(pipe_class_dummy);
%}
// byte[] to char[] inflation
instruct string_inflate_const(Universe dummy, iRegP src, iRegP dst, iRegI tmp, immI len, flagsReg cr) %{
match(Set dummy (StrInflatedCopy src (Binary dst len)));
effect(TEMP tmp, KILL cr); // R0, R1 are killed, too.
ins_cost(300);
format %{ "String Inflate (constLen) $src->$dst($len)" %}
ins_encode %{
__ string_inflate_const($src$$Register, $dst$$Register, $tmp$$Register, $len$$constant);
%}
ins_pipe(pipe_class_dummy);
%}
@ -10318,14 +10330,14 @@ instruct has_negatives(rarg5RegP ary1, iRegI len, iRegI result, roddRegI oddReg,
%}
// encode char[] to byte[] in ISO_8859_1
instruct encode_iso_array(rarg5RegP src, iRegP dst, iRegI result, roddRegI len, revenRegI evenReg, iRegI tmp, iRegI tmp2, flagsReg cr) %{
instruct encode_iso_array(iRegP src, iRegP dst, iRegI result, iRegI len, iRegI tmp, flagsReg cr) %{
match(Set result (EncodeISOArray src (Binary dst len)));
effect(TEMP_DEF result, USE_KILL src, USE_KILL len, TEMP evenReg, TEMP tmp, TEMP tmp2, KILL cr); // R0, R1 are killed, too.
effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too.
ins_cost(300);
format %{ "Encode array $src->$dst($len) -> $result" %}
ins_encode %{
__ string_compress($result$$Register, $src$$Register, $dst$$Register, $len$$Register,
$evenReg$$Register, $tmp$$Register, $tmp2$$Register);
$tmp$$Register, true);
%}
ins_pipe(pipe_class_dummy);
%}

View File

@ -898,7 +898,9 @@ class StubGenerator: public StubCodeGenerator {
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
assert_different_registers(addr, count, tmp);
Label L_loop;
Label L_loop, L_done;
__ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_done); // zero count - nothing to do
__ sll_ptr(count, LogBytesPerHeapOop, count);
__ sub(count, BytesPerHeapOop, count);
@ -914,6 +916,7 @@ class StubGenerator: public StubCodeGenerator {
__ subcc(count, 1, count);
__ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop);
__ delayed()->add(addr, 1, addr);
__ BIND(L_done);
}
break;
case BarrierSet::ModRef:

View File

@ -5203,6 +5203,24 @@ void Assembler::vsqrtpd(XMMRegister dst, Address src, int vector_len) {
emit_operand(dst, src);
}
void Assembler::vsqrtps(XMMRegister dst, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x51);
emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::vsqrtps(XMMRegister dst, Address src, int vector_len) {
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x51);
emit_operand(dst, src);
}
void Assembler::andpd(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true);

View File

@ -1919,9 +1919,11 @@ private:
void vdivpd(XMMRegister dst, XMMRegister nds, Address src, int vector_len);
void vdivps(XMMRegister dst, XMMRegister nds, Address src, int vector_len);
// Sqrt Packed Floating-Point Values - Double precision only
// Sqrt Packed Floating-Point Values
void vsqrtpd(XMMRegister dst, XMMRegister src, int vector_len);
void vsqrtpd(XMMRegister dst, Address src, int vector_len);
void vsqrtps(XMMRegister dst, XMMRegister src, int vector_len);
void vsqrtps(XMMRegister dst, Address src, int vector_len);
// Bitwise Logical AND of Packed Floating-Point Values
void andpd(XMMRegister dst, XMMRegister src);

View File

@ -1264,9 +1264,12 @@ class StubGenerator: public StubCodeGenerator {
CardTableModRefBS* ct = barrier_set_cast<CardTableModRefBS>(bs);
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
Label L_loop;
Label L_loop, L_done;
const Register end = count;
__ testl(count, count);
__ jcc(Assembler::zero, L_done); // zero count - nothing to do
__ leaq(end, Address(start, count, TIMES_OOP, 0)); // end == start+count*oop_size
__ subptr(end, BytesPerHeapOop); // end - 1 to make inclusive
__ shrptr(start, CardTableModRefBS::card_shift);
@ -1280,6 +1283,7 @@ class StubGenerator: public StubCodeGenerator {
__ movb(Address(start, count, Address::times_1), 0);
__ decrement(count);
__ jcc(Assembler::greaterEqual, L_loop);
__ BIND(L_done);
}
break;
default:

View File

@ -1252,6 +1252,7 @@ const bool Matcher::match_rule_supported(int opcode) {
ret_value = false;
break;
case Op_SqrtVD:
case Op_SqrtVF:
if (UseAVX < 1) // enabled for AVX only
ret_value = false;
break;
@ -2580,7 +2581,7 @@ instruct negD_reg_reg(regD dst, regD src) %{
instruct sqrtF_reg(regF dst, regF src) %{
predicate(UseSSE>=1);
match(Set dst (ConvD2F (SqrtD (ConvF2D src))));
match(Set dst (SqrtF src));
format %{ "sqrtss $dst, $src" %}
ins_cost(150);
@ -2592,7 +2593,7 @@ instruct sqrtF_reg(regF dst, regF src) %{
instruct sqrtF_mem(regF dst, memory src) %{
predicate(UseSSE>=1);
match(Set dst (ConvD2F (SqrtD (ConvF2D (LoadF src)))));
match(Set dst (SqrtF (LoadF src)));
format %{ "sqrtss $dst, $src" %}
ins_cost(150);
@ -2604,7 +2605,8 @@ instruct sqrtF_mem(regF dst, memory src) %{
instruct sqrtF_imm(regF dst, immF con) %{
predicate(UseSSE>=1);
match(Set dst (ConvD2F (SqrtD (ConvF2D con))));
match(Set dst (SqrtF con));
format %{ "sqrtss $dst, [$constantaddress]\t# load from constant table: float=$con" %}
ins_cost(150);
ins_encode %{
@ -8388,7 +8390,7 @@ instruct vshiftcnt(vecS dst, rRegI cnt) %{
// --------------------------------- Sqrt --------------------------------------
// Floating point vector sqrt - double precision only
// Floating point vector sqrt
instruct vsqrt2D_reg(vecX dst, vecX src) %{
predicate(UseAVX > 0 && n->as_Vector()->length() == 2);
match(Set dst (SqrtVD src));
@ -8455,6 +8457,94 @@ instruct vsqrt8D_mem(vecZ dst, memory mem) %{
ins_pipe( pipe_slow );
%}
instruct vsqrt2F_reg(vecD dst, vecD src) %{
predicate(UseAVX > 0 && n->as_Vector()->length() == 2);
match(Set dst (SqrtVF src));
format %{ "vsqrtps $dst,$src\t! sqrt packed2F" %}
ins_encode %{
int vector_len = 0;
__ vsqrtps($dst$$XMMRegister, $src$$XMMRegister, vector_len);
%}
ins_pipe( pipe_slow );
%}
instruct vsqrt2F_mem(vecD dst, memory mem) %{
predicate(UseAVX > 0 && n->as_Vector()->length() == 2);
match(Set dst (SqrtVF (LoadVector mem)));
format %{ "vsqrtps $dst,$mem\t! sqrt packed2F" %}
ins_encode %{
int vector_len = 0;
__ vsqrtps($dst$$XMMRegister, $mem$$Address, vector_len);
%}
ins_pipe( pipe_slow );
%}
instruct vsqrt4F_reg(vecX dst, vecX src) %{
predicate(UseAVX > 0 && n->as_Vector()->length() == 4);
match(Set dst (SqrtVF src));
format %{ "vsqrtps $dst,$src\t! sqrt packed4F" %}
ins_encode %{
int vector_len = 0;
__ vsqrtps($dst$$XMMRegister, $src$$XMMRegister, vector_len);
%}
ins_pipe( pipe_slow );
%}
instruct vsqrt4F_mem(vecX dst, memory mem) %{
predicate(UseAVX > 0 && n->as_Vector()->length() == 4);
match(Set dst (SqrtVF (LoadVector mem)));
format %{ "vsqrtps $dst,$mem\t! sqrt packed4F" %}
ins_encode %{
int vector_len = 0;
__ vsqrtps($dst$$XMMRegister, $mem$$Address, vector_len);
%}
ins_pipe( pipe_slow );
%}
instruct vsqrt8F_reg(vecY dst, vecY src) %{
predicate(UseAVX > 0 && n->as_Vector()->length() == 8);
match(Set dst (SqrtVF src));
format %{ "vsqrtps $dst,$src\t! sqrt packed8F" %}
ins_encode %{
int vector_len = 1;
__ vsqrtps($dst$$XMMRegister, $src$$XMMRegister, vector_len);
%}
ins_pipe( pipe_slow );
%}
instruct vsqrt8F_mem(vecY dst, memory mem) %{
predicate(UseAVX > 0 && n->as_Vector()->length() == 8);
match(Set dst (SqrtVF (LoadVector mem)));
format %{ "vsqrtps $dst,$mem\t! sqrt packed8F" %}
ins_encode %{
int vector_len = 1;
__ vsqrtps($dst$$XMMRegister, $mem$$Address, vector_len);
%}
ins_pipe( pipe_slow );
%}
instruct vsqrt16F_reg(vecZ dst, vecZ src) %{
predicate(UseAVX > 2 && n->as_Vector()->length() == 16);
match(Set dst (SqrtVF src));
format %{ "vsqrtps $dst,$src\t! sqrt packed16F" %}
ins_encode %{
int vector_len = 2;
__ vsqrtps($dst$$XMMRegister, $src$$XMMRegister, vector_len);
%}
ins_pipe( pipe_slow );
%}
instruct vsqrt16F_mem(vecZ dst, memory mem) %{
predicate(UseAVX > 2 && n->as_Vector()->length() == 16);
match(Set dst (SqrtVF (LoadVector mem)));
format %{ "vsqrtps $dst,$mem\t! sqrt packed16F" %}
ins_encode %{
int vector_len = 2;
__ vsqrtps($dst$$XMMRegister, $mem$$Address, vector_len);
%}
ins_pipe( pipe_slow );
%}
// ------------------------------ LeftShift -----------------------------------
// Shorts/Chars vector left shift

View File

@ -59,6 +59,7 @@
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadCritical.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/timer.hpp"
#include "semaphore_posix.hpp"
#include "services/attachListener.hpp"
@ -1646,7 +1647,10 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
//
// Dynamic loader will make all stacks executable after
// this function returns, and will not do that again.
assert(Threads::first() == NULL, "no Java threads should exist yet.");
#ifdef ASSERT
ThreadsListHandle tlh;
assert(tlh.length() == 0, "no Java threads should exist yet.");
#endif
} else {
warning("You have loaded library %s which might have disabled stack guard. "
"The VM will try to fix the stack guard now.\n"
@ -1874,16 +1878,13 @@ void * os::Linux::dll_load_in_vmthread(const char *filename, char *ebuf,
// may have been queued at the same time.
if (!_stack_is_executable) {
JavaThread *jt = Threads::first();
while (jt) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
if (!jt->stack_guard_zone_unused() && // Stack not yet fully initialized
jt->stack_guards_enabled()) { // No pending stack overflow exceptions
if (!os::guard_memory((char *)jt->stack_end(), jt->stack_guard_zone_size())) {
warning("Attempt to reguard stack yellow zone failed.");
}
}
jt = jt->next();
}
}

View File

@ -478,8 +478,7 @@ int os::sleep(Thread* thread, jlong millis, bool interruptible) {
// interrupt support
void os::interrupt(Thread* thread) {
assert(Thread::current() == thread || Threads_lock->owned_by_self(),
"possibility of dangling Thread pointer");
debug_only(Thread::check_for_dangling_thread_pointer(thread);)
OSThread* osthread = thread->osthread();
@ -499,12 +498,10 @@ void os::interrupt(Thread* thread) {
ParkEvent * ev = thread->_ParkEvent ;
if (ev != NULL) ev->unpark() ;
}
bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
assert(Thread::current() == thread || Threads_lock->owned_by_self(),
"possibility of dangling Thread pointer");
debug_only(Thread::check_for_dangling_thread_pointer(thread);)
OSThread* osthread = thread->osthread();

View File

@ -3490,9 +3490,7 @@ OSReturn os::get_native_priority(const Thread* const thread,
void os::hint_no_preempt() {}
void os::interrupt(Thread* thread) {
assert(!thread->is_Java_thread() || Thread::current() == thread ||
Threads_lock->owned_by_self(),
"possibility of dangling Thread pointer");
debug_only(Thread::check_for_dangling_thread_pointer(thread);)
OSThread* osthread = thread->osthread();
osthread->set_interrupted(true);
@ -3513,8 +3511,7 @@ void os::interrupt(Thread* thread) {
bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
assert(!thread->is_Java_thread() || Thread::current() == thread || Threads_lock->owned_by_self(),
"possibility of dangling Thread pointer");
debug_only(Thread::check_for_dangling_thread_pointer(thread);)
OSThread* osthread = thread->osthread();
// There is no synchronization between the setting of the interrupt

View File

@ -4034,6 +4034,7 @@ int MatchRule::is_expensive() const {
strcmp(opType,"ModF")==0 ||
strcmp(opType,"ModI")==0 ||
strcmp(opType,"SqrtD")==0 ||
strcmp(opType,"SqrtF")==0 ||
strcmp(opType,"TanD")==0 ||
strcmp(opType,"ConvD2F")==0 ||
strcmp(opType,"ConvD2I")==0 ||
@ -4167,7 +4168,7 @@ bool MatchRule::is_vector() const {
"DivVF","DivVD",
"AbsVF","AbsVD",
"NegVF","NegVD",
"SqrtVD",
"SqrtVD","SqrtVF",
"AndV" ,"XorV" ,"OrV",
"AddReductionVI", "AddReductionVL",
"AddReductionVF", "AddReductionVD",

View File

@ -3441,6 +3441,7 @@ const char* GraphBuilder::check_can_parse(ciMethod* callee) const {
if ( callee->is_native()) return "native method";
if ( callee->is_abstract()) return "abstract method";
if (!callee->can_be_compiled()) return "not compilable (disabled)";
if (!callee->can_be_parsed()) return "cannot be parsed";
return NULL;
}

View File

@ -87,6 +87,7 @@ ciMethod::ciMethod(const methodHandle& h_m, ciInstanceKlass* holder) :
_balanced_monitors = !_uses_monitors || h_m()->access_flags().is_monitor_matching();
_is_c1_compilable = !h_m()->is_not_c1_compilable();
_is_c2_compilable = !h_m()->is_not_c2_compilable();
_can_be_parsed = true;
_has_reserved_stack_access = h_m()->has_reserved_stack_access();
// Lazy fields, filled in on demand. Require allocation.
_code = NULL;
@ -99,12 +100,13 @@ ciMethod::ciMethod(const methodHandle& h_m, ciInstanceKlass* holder) :
#endif // COMPILER2
ciEnv *env = CURRENT_ENV;
if (env->jvmti_can_hotswap_or_post_breakpoint() && can_be_compiled()) {
if (env->jvmti_can_hotswap_or_post_breakpoint()) {
// 6328518 check hotswap conditions under the right lock.
MutexLocker locker(Compile_lock);
if (Dependencies::check_evol_method(h_m()) != NULL) {
_is_c1_compilable = false;
_is_c2_compilable = false;
_can_be_parsed = false;
}
} else {
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());

View File

@ -87,6 +87,7 @@ class ciMethod : public ciMetadata {
bool _balanced_monitors;
bool _is_c1_compilable;
bool _is_c2_compilable;
bool _can_be_parsed;
bool _can_be_statically_bound;
bool _has_reserved_stack_access;
@ -291,6 +292,7 @@ class ciMethod : public ciMetadata {
bool has_option(const char *option);
bool has_option_value(const char* option, double& value);
bool can_be_compiled();
bool can_be_parsed() const { return _can_be_parsed; }
bool can_be_osr_compiled(int entry_bci);
void set_not_compilable(const char* reason = NULL);
bool has_compiled_code();

View File

@ -124,7 +124,7 @@ class nmethod : public CompiledMethod {
bool _unload_reported;
// Protected by Patching_lock
volatile char _state; // {not_installed, in_use, not_entrant, zombie, unloaded}
volatile signed char _state; // {not_installed, in_use, not_entrant, zombie, unloaded}
#ifdef ASSERT
bool _oops_are_stale; // indicates that it's no longer safe to access oops section

View File

@ -78,7 +78,6 @@ StubQueue::StubQueue(StubInterface* stub_interface, int buffer_size,
_queue_begin = 0;
_queue_end = 0;
_number_of_stubs = 0;
register_queue(this);
}
@ -205,36 +204,6 @@ void StubQueue::remove_all(){
}
enum { StubQueueLimit = 10 }; // there are only a few in the world
static StubQueue* registered_stub_queues[StubQueueLimit];
void StubQueue::register_queue(StubQueue* sq) {
for (int i = 0; i < StubQueueLimit; i++) {
if (registered_stub_queues[i] == NULL) {
registered_stub_queues[i] = sq;
return;
}
}
ShouldNotReachHere();
}
void StubQueue::queues_do(void f(StubQueue* sq)) {
for (int i = 0; i < StubQueueLimit; i++) {
if (registered_stub_queues[i] != NULL) {
f(registered_stub_queues[i]);
}
}
}
void StubQueue::stubs_do(void f(Stub* s)) {
debug_only(verify();)
MutexLockerEx lock(_mutex);
for (Stub* s = first(); s != NULL; s = next(s)) f(s);
}
void StubQueue::verify() {
// verify only if initialized
if (_stub_buffer == NULL) return;

View File

@ -172,8 +172,6 @@ class StubQueue: public CHeapObj<mtCode> {
void stub_verify(Stub* s) { _stub_interface->verify(s); }
void stub_print(Stub* s) { _stub_interface->print(s); }
static void register_queue(StubQueue*);
public:
StubQueue(StubInterface* stub_interface, int buffer_size, Mutex* lock,
const char* name);
@ -204,8 +202,6 @@ class StubQueue: public CHeapObj<mtCode> {
void deallocate_unused_tail(); // deallocate the unused tail of the underlying CodeBlob
// only used from TemplateInterpreter::initialize()
// Iteration
static void queues_do(void f(StubQueue* s)); // call f with each StubQueue
void stubs_do(void f(Stub* s)); // call f with all stubs
Stub* first() const { return number_of_stubs() > 0 ? stub_at(_queue_begin) : NULL; }
Stub* next(Stub* s) const { int i = index_of(s) + stub_size(s);
// Only wrap around in the non-contiguous case (see stubss.cpp)
@ -213,9 +209,6 @@ class StubQueue: public CHeapObj<mtCode> {
return (i == _queue_end) ? NULL : stub_at(i);
}
address stub_code_begin(Stub* s) const { return _stub_interface->code_begin(s); }
address stub_code_end(Stub* s) const { return _stub_interface->code_end(s); }
// Debugging/printing
void verify(); // verifies the stub queue
void print(); // prints information about the stub queue

View File

@ -32,6 +32,7 @@
#include "runtime/mutexLocker.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
// Closure used for updating remembered sets and recording references that
// point into the collection set while the mutator is running.
@ -319,7 +320,7 @@ void DirtyCardQueueSet::abandon_logs() {
clear();
// Since abandon is done only at safepoints, we can safely manipulate
// these queues.
for (JavaThread* t = Threads::first(); t; t = t->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
t->dirty_card_queue().reset();
}
shared_dirty_card_queue()->reset();
@ -338,7 +339,7 @@ void DirtyCardQueueSet::concatenate_logs() {
int save_max_completed_queue = _max_completed_queue;
_max_completed_queue = max_jint;
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
for (JavaThread* t = Threads::first(); t; t = t->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
concatenate_log(t->dirty_card_queue());
}
concatenate_log(_shared_dirty_card_queue);

View File

@ -39,7 +39,6 @@
#include "gc/g1/g1ConcurrentRefineThread.hpp"
#include "gc/g1/g1EvacStats.inline.hpp"
#include "gc/g1/g1FullCollector.hpp"
#include "gc/g1/g1FullGCScope.hpp"
#include "gc/g1/g1GCPhaseTimes.hpp"
#include "gc/g1/g1HeapSizingPolicy.hpp"
#include "gc/g1/g1HeapTransition.hpp"
@ -81,6 +80,7 @@
#include "runtime/atomic.hpp"
#include "runtime/init.hpp"
#include "runtime/orderAccess.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vmThread.hpp"
#include "utilities/align.hpp"
#include "utilities/globalDefinitions.hpp"
@ -1217,34 +1217,6 @@ void G1CollectedHeap::print_heap_after_full_collection(G1HeapTransition* heap_tr
#endif
}
void G1CollectedHeap::do_full_collection_inner(G1FullGCScope* scope) {
GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause(), true);
g1_policy()->record_full_collection_start();
print_heap_before_gc();
print_heap_regions();
abort_concurrent_cycle();
verify_before_full_collection(scope->is_explicit_gc());
gc_prologue(true);
prepare_heap_for_full_collection();
G1FullCollector collector(scope, ref_processor_stw(), concurrent_mark()->next_mark_bitmap(), workers()->active_workers());
collector.prepare_collection();
collector.collect();
collector.complete_collection();
prepare_heap_for_mutators();
g1_policy()->record_full_collection_end();
gc_epilogue(true);
verify_after_full_collection();
print_heap_after_full_collection(scope->heap_transition());
}
bool G1CollectedHeap::do_full_collection(bool explicit_gc,
bool clear_all_soft_refs) {
assert_at_safepoint(true /* should_be_vm_thread */);
@ -1257,8 +1229,12 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc,
const bool do_clear_all_soft_refs = clear_all_soft_refs ||
collector_policy()->should_clear_all_soft_refs();
G1FullGCScope scope(explicit_gc, do_clear_all_soft_refs);
do_full_collection_inner(&scope);
G1FullCollector collector(this, explicit_gc, do_clear_all_soft_refs);
GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause(), true);
collector.prepare_collection();
collector.collect();
collector.complete_collection();
// Full collection was successfully completed.
return true;
@ -2653,11 +2629,9 @@ G1CollectedHeap::doConcurrentMark() {
size_t G1CollectedHeap::pending_card_num() {
size_t extra_cards = 0;
JavaThread *curr = Threads::first();
while (curr != NULL) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *curr = jtiwh.next(); ) {
DirtyCardQueue& dcq = curr->dirty_card_queue();
extra_cards += dcq.size();
curr = curr->next();
}
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
size_t buffer_size = dcqs.buffer_size();

View File

@ -126,6 +126,7 @@ class G1CollectedHeap : public CollectedHeap {
friend class VM_G1IncCollectionPause;
friend class VMStructs;
friend class MutatorAllocRegion;
friend class G1FullCollector;
friend class G1GCAllocRegion;
friend class G1HeapVerifier;
@ -517,7 +518,6 @@ protected:
private:
// Internal helpers used during full GC to split it up to
// increase readability.
void do_full_collection_inner(G1FullGCScope* scope);
void abort_concurrent_cycle();
void verify_before_full_collection(bool explicit_gc);
void prepare_heap_for_full_collection();

View File

@ -1756,28 +1756,24 @@ private:
G1ConcurrentMark* _cm;
public:
void work(uint worker_id) {
// Since all available tasks are actually started, we should
// only proceed if we're supposed to be active.
if (worker_id < _cm->active_tasks()) {
G1CMTask* task = _cm->task(worker_id);
task->record_start_time();
{
ResourceMark rm;
HandleMark hm;
G1CMTask* task = _cm->task(worker_id);
task->record_start_time();
{
ResourceMark rm;
HandleMark hm;
G1RemarkThreadsClosure threads_f(G1CollectedHeap::heap(), task);
Threads::threads_do(&threads_f);
}
do {
task->do_marking_step(1000000000.0 /* something very large */,
true /* do_termination */,
false /* is_serial */);
} while (task->has_aborted() && !_cm->has_overflown());
// If we overflow, then we do not want to restart. We instead
// want to abort remark and do concurrent marking again.
task->record_end_time();
G1RemarkThreadsClosure threads_f(G1CollectedHeap::heap(), task);
Threads::threads_do(&threads_f);
}
do {
task->do_marking_step(1000000000.0 /* something very large */,
true /* do_termination */,
false /* is_serial */);
} while (task->has_aborted() && !_cm->has_overflown());
// If we overflow, then we do not want to restart. We instead
// want to abort remark and do concurrent marking again.
task->record_end_time();
}
G1CMRemarkTask(G1ConcurrentMark* cm, uint active_workers) :

View File

@ -33,6 +33,107 @@
#include "utilities/pair.hpp"
#include <math.h>
G1ConcurrentRefineThread* G1ConcurrentRefineThreadControl::create_refinement_thread(uint worker_id, bool initializing) {
G1ConcurrentRefineThread* result = NULL;
if (initializing || !InjectGCWorkerCreationFailure) {
result = new G1ConcurrentRefineThread(_cr, worker_id);
}
if (result == NULL || result->osthread() == NULL) {
log_warning(gc)("Failed to create refinement thread %u, no more %s",
worker_id,
result == NULL ? "memory" : "OS threads");
}
return result;
}
G1ConcurrentRefineThreadControl::G1ConcurrentRefineThreadControl() :
_cr(NULL),
_threads(NULL),
_num_max_threads(0)
{
}
G1ConcurrentRefineThreadControl::~G1ConcurrentRefineThreadControl() {
for (uint i = 0; i < _num_max_threads; i++) {
G1ConcurrentRefineThread* t = _threads[i];
if (t != NULL) {
delete t;
}
}
FREE_C_HEAP_ARRAY(G1ConcurrentRefineThread*, _threads);
}
jint G1ConcurrentRefineThreadControl::initialize(G1ConcurrentRefine* cr, uint num_max_threads) {
assert(cr != NULL, "G1ConcurrentRefine must not be NULL");
_cr = cr;
_num_max_threads = num_max_threads;
_threads = NEW_C_HEAP_ARRAY_RETURN_NULL(G1ConcurrentRefineThread*, num_max_threads, mtGC);
if (_threads == NULL) {
vm_shutdown_during_initialization("Could not allocate thread holder array.");
return JNI_ENOMEM;
}
for (uint i = 0; i < num_max_threads; i++) {
if (UseDynamicNumberOfGCThreads && i != 0 /* Always start first thread. */) {
_threads[i] = NULL;
} else {
_threads[i] = create_refinement_thread(i, true);
if (_threads[i] == NULL) {
vm_shutdown_during_initialization("Could not allocate refinement threads.");
return JNI_ENOMEM;
}
}
}
return JNI_OK;
}
void G1ConcurrentRefineThreadControl::maybe_activate_next(uint cur_worker_id) {
assert(cur_worker_id < _num_max_threads,
"Activating another thread from %u not allowed since there can be at most %u",
cur_worker_id, _num_max_threads);
if (cur_worker_id == (_num_max_threads - 1)) {
// Already the last thread, there is no more thread to activate.
return;
}
uint worker_id = cur_worker_id + 1;
G1ConcurrentRefineThread* thread_to_activate = _threads[worker_id];
if (thread_to_activate == NULL) {
// Still need to create the thread...
_threads[worker_id] = create_refinement_thread(worker_id, false);
thread_to_activate = _threads[worker_id];
}
if (thread_to_activate != NULL && !thread_to_activate->is_active()) {
thread_to_activate->activate();
}
}
void G1ConcurrentRefineThreadControl::print_on(outputStream* st) const {
for (uint i = 0; i < _num_max_threads; ++i) {
if (_threads[i] != NULL) {
_threads[i]->print_on(st);
st->cr();
}
}
}
void G1ConcurrentRefineThreadControl::worker_threads_do(ThreadClosure* tc) {
for (uint i = 0; i < _num_max_threads; i++) {
if (_threads[i] != NULL) {
tc->do_thread(_threads[i]);
}
}
}
void G1ConcurrentRefineThreadControl::stop() {
for (uint i = 0; i < _num_max_threads; i++) {
if (_threads[i] != NULL) {
_threads[i]->stop();
}
}
}
// Arbitrary but large limits, to simplify some of the zone calculations.
// The general idea is to allow expressions like
// MIN2(x OP y, max_XXX_zone)
@ -96,7 +197,7 @@ static Thresholds calc_thresholds(size_t green_zone,
size_t yellow_zone,
uint worker_i) {
double yellow_size = yellow_zone - green_zone;
double step = yellow_size / G1ConcurrentRefine::thread_num();
double step = yellow_size / G1ConcurrentRefine::max_num_threads();
if (worker_i == 0) {
// Potentially activate worker 0 more aggressively, to keep
// available buffers near green_zone value. When yellow_size is
@ -115,8 +216,7 @@ G1ConcurrentRefine::G1ConcurrentRefine(size_t green_zone,
size_t yellow_zone,
size_t red_zone,
size_t min_yellow_zone_size) :
_threads(NULL),
_n_worker_threads(thread_num()),
_thread_control(),
_green_zone(green_zone),
_yellow_zone(yellow_zone),
_red_zone(red_zone),
@ -125,9 +225,13 @@ G1ConcurrentRefine::G1ConcurrentRefine(size_t green_zone,
assert_zone_constraints_gyr(green_zone, yellow_zone, red_zone);
}
jint G1ConcurrentRefine::initialize() {
return _thread_control.initialize(this, max_num_threads());
}
static size_t calc_min_yellow_zone_size() {
size_t step = G1ConcRefinementThresholdStep;
uint n_workers = G1ConcurrentRefine::thread_num();
uint n_workers = G1ConcurrentRefine::max_num_threads();
if ((max_yellow_zone / step) < n_workers) {
return max_yellow_zone;
} else {
@ -191,77 +295,27 @@ G1ConcurrentRefine* G1ConcurrentRefine::create(jint* ecode) {
return NULL;
}
cr->_threads = NEW_C_HEAP_ARRAY_RETURN_NULL(G1ConcurrentRefineThread*, cr->_n_worker_threads, mtGC);
if (cr->_threads == NULL) {
*ecode = JNI_ENOMEM;
vm_shutdown_during_initialization("Could not allocate an array for G1ConcurrentRefineThread");
return NULL;
}
uint worker_id_offset = DirtyCardQueueSet::num_par_ids();
G1ConcurrentRefineThread *next = NULL;
for (uint i = cr->_n_worker_threads - 1; i != UINT_MAX; i--) {
Thresholds thresholds = calc_thresholds(green_zone, yellow_zone, i);
G1ConcurrentRefineThread* t =
new G1ConcurrentRefineThread(cr,
next,
worker_id_offset,
i,
activation_level(thresholds),
deactivation_level(thresholds));
assert(t != NULL, "Conc refine should have been created");
if (t->osthread() == NULL) {
*ecode = JNI_ENOMEM;
vm_shutdown_during_initialization("Could not create G1ConcurrentRefineThread");
return NULL;
}
assert(t->cr() == cr, "Conc refine thread should refer to this");
cr->_threads[i] = t;
next = t;
}
*ecode = JNI_OK;
*ecode = cr->initialize();
return cr;
}
void G1ConcurrentRefine::stop() {
for (uint i = 0; i < _n_worker_threads; i++) {
_threads[i]->stop();
}
}
void G1ConcurrentRefine::update_thread_thresholds() {
for (uint i = 0; i < _n_worker_threads; i++) {
Thresholds thresholds = calc_thresholds(_green_zone, _yellow_zone, i);
_threads[i]->update_thresholds(activation_level(thresholds),
deactivation_level(thresholds));
}
_thread_control.stop();
}
G1ConcurrentRefine::~G1ConcurrentRefine() {
for (uint i = 0; i < _n_worker_threads; i++) {
delete _threads[i];
}
FREE_C_HEAP_ARRAY(G1ConcurrentRefineThread*, _threads);
}
void G1ConcurrentRefine::threads_do(ThreadClosure *tc) {
for (uint i = 0; i < _n_worker_threads; i++) {
tc->do_thread(_threads[i]);
}
_thread_control.worker_threads_do(tc);
}
uint G1ConcurrentRefine::thread_num() {
uint G1ConcurrentRefine::max_num_threads() {
return G1ConcRefinementThreads;
}
void G1ConcurrentRefine::print_threads_on(outputStream* st) const {
for (uint i = 0; i < _n_worker_threads; ++i) {
_threads[i]->print_on(st);
st->cr();
}
_thread_control.print_on(st);
}
static size_t calc_new_green_zone(size_t green,
@ -326,16 +380,15 @@ void G1ConcurrentRefine::adjust(double update_rs_time,
if (G1UseAdaptiveConcRefinement) {
update_zones(update_rs_time, update_rs_processed_buffers, goal_ms);
update_thread_thresholds();
// Change the barrier params
if (_n_worker_threads == 0) {
if (max_num_threads() == 0) {
// Disable dcqs notification when there are no threads to notify.
dcqs.set_process_completed_threshold(INT_MAX);
} else {
// Worker 0 is the primary; wakeup is via dcqs notification.
STATIC_ASSERT(max_yellow_zone <= INT_MAX);
size_t activate = _threads[0]->activation_threshold();
size_t activate = activation_threshold(0);
dcqs.set_process_completed_threshold((int)activate);
}
dcqs.set_max_completed_queue((int)red_zone());
@ -349,3 +402,42 @@ void G1ConcurrentRefine::adjust(double update_rs_time,
}
dcqs.notify_if_necessary();
}
size_t G1ConcurrentRefine::activation_threshold(uint worker_id) const {
Thresholds thresholds = calc_thresholds(_green_zone, _yellow_zone, worker_id);
return activation_level(thresholds);
}
size_t G1ConcurrentRefine::deactivation_threshold(uint worker_id) const {
Thresholds thresholds = calc_thresholds(_green_zone, _yellow_zone, worker_id);
return deactivation_level(thresholds);
}
uint G1ConcurrentRefine::worker_id_offset() {
return DirtyCardQueueSet::num_par_ids();
}
void G1ConcurrentRefine::maybe_activate_more_threads(uint worker_id, size_t num_cur_buffers) {
if (num_cur_buffers > activation_threshold(worker_id + 1)) {
_thread_control.maybe_activate_next(worker_id);
}
}
bool G1ConcurrentRefine::do_refinement_step(uint worker_id) {
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
size_t curr_buffer_num = dcqs.completed_buffers_num();
// If the number of the buffers falls down into the yellow zone,
// that means that the transition period after the evacuation pause has ended.
// Since the value written to the DCQS is the same for all threads, there is no
// need to synchronize.
if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= yellow_zone()) {
dcqs.set_completed_queue_padding(0);
}
maybe_activate_more_threads(worker_id, curr_buffer_num);
// Process the next buffer, if there are enough left.
return dcqs.refine_completed_buffer_concurrently(worker_id + worker_id_offset(),
deactivation_threshold(worker_id));
}

View File

@ -30,30 +30,63 @@
// Forward decl
class CardTableEntryClosure;
class G1ConcurrentRefine;
class G1ConcurrentRefineThread;
class outputStream;
class ThreadClosure;
class G1ConcurrentRefine : public CHeapObj<mtGC> {
// Helper class for refinement thread management. Used to start, stop and
// iterate over them.
class G1ConcurrentRefineThreadControl VALUE_OBJ_CLASS_SPEC {
G1ConcurrentRefine* _cr;
G1ConcurrentRefineThread** _threads;
uint _n_worker_threads;
/*
* The value of the update buffer queue length falls into one of 3 zones:
* green, yellow, red. If the value is in [0, green) nothing is
* done, the buffers are left unprocessed to enable the caching effect of the
* dirtied cards. In the yellow zone [green, yellow) the concurrent refinement
* threads are gradually activated. In [yellow, red) all threads are
* running. If the length becomes red (max queue length) the mutators start
* processing the buffers.
*
* There are some interesting cases (when G1UseAdaptiveConcRefinement
* is turned off):
* 1) green = yellow = red = 0. In this case the mutator will process all
* buffers. Except for those that are created by the deferred updates
* machinery during a collection.
* 2) green = 0. Means no caching. Can be a good way to minimize the
* amount of time spent updating rsets during a collection.
*/
uint _num_max_threads;
// Create the refinement thread for the given worker id.
// If initializing is true, ignore InjectGCWorkerCreationFailure.
G1ConcurrentRefineThread* create_refinement_thread(uint worker_id, bool initializing);
public:
G1ConcurrentRefineThreadControl();
~G1ConcurrentRefineThreadControl();
jint initialize(G1ConcurrentRefine* cr, uint num_max_threads);
// If there is a "successor" thread that can be activated given the current id,
// activate it.
void maybe_activate_next(uint cur_worker_id);
void print_on(outputStream* st) const;
void worker_threads_do(ThreadClosure* tc);
void stop();
};
// Controls refinement threads and their activation based on the number of completed
// buffers currently available in the global dirty card queue.
// Refinement threads pick work from the queue based on these thresholds. They are activated
// gradually based on the amount of work to do.
// Refinement thread n activates thread n+1 if the instance of this class determines there
// is enough work available. Threads deactivate themselves if the current amount of
// completed buffers falls below their individual threshold.
class G1ConcurrentRefine : public CHeapObj<mtGC> {
G1ConcurrentRefineThreadControl _thread_control;
/*
* The value of the completed dirty card queue length falls into one of 3 zones:
* green, yellow, red. If the value is in [0, green) nothing is
* done, the buffers are left unprocessed to enable the caching effect of the
* dirtied cards. In the yellow zone [green, yellow) the concurrent refinement
* threads are gradually activated. In [yellow, red) all threads are
* running. If the length becomes red (max queue length) the mutators start
* processing the buffers.
*
* There are some interesting cases (when G1UseAdaptiveConcRefinement
* is turned off):
* 1) green = yellow = red = 0. In this case the mutator will process all
* buffers. Except for those that are created by the deferred updates
* machinery during a collection.
* 2) green = 0. Means no caching. Can be a good way to minimize the
* amount of time spent updating remembered sets during a collection.
*/
size_t _green_zone;
size_t _yellow_zone;
size_t _red_zone;
@ -69,24 +102,32 @@ class G1ConcurrentRefine : public CHeapObj<mtGC> {
size_t update_rs_processed_buffers,
double goal_ms);
// Update thread thresholds to account for updated zone values.
void update_thread_thresholds();
static uint worker_id_offset();
void maybe_activate_more_threads(uint worker_id, size_t num_cur_buffers);
public:
jint initialize();
public:
~G1ConcurrentRefine();
// Returns a G1ConcurrentRefine instance if succeeded to create/initialize G1ConcurrentRefine and G1ConcurrentRefineThreads.
// Otherwise, returns NULL with error code.
// Returns a G1ConcurrentRefine instance if succeeded to create/initialize the
// G1ConcurrentRefine instance. Otherwise, returns NULL with error code.
static G1ConcurrentRefine* create(jint* ecode);
void stop();
// Adjust refinement thresholds based on work done during the pause and the goal time.
void adjust(double update_rs_time, size_t update_rs_processed_buffers, double goal_ms);
size_t activation_threshold(uint worker_id) const;
size_t deactivation_threshold(uint worker_id) const;
// Perform a single refinement step. Called by the refinement threads when woken up.
bool do_refinement_step(uint worker_id);
// Iterate over all concurrent refinement threads applying the given closure.
void threads_do(ThreadClosure *tc);
static uint thread_num();
// Maximum number of refinement threads.
static uint max_num_threads();
void print_threads_on(outputStream* st) const;

View File

@ -25,32 +25,20 @@
#include "precompiled.hpp"
#include "gc/g1/g1ConcurrentRefine.hpp"
#include "gc/g1/g1ConcurrentRefineThread.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1RemSet.hpp"
#include "gc/shared/suspendibleThreadSet.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/mutexLocker.hpp"
G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr,
G1ConcurrentRefineThread *next,
uint worker_id_offset,
uint worker_id,
size_t activate,
size_t deactivate) :
G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr, uint worker_id) :
ConcurrentGCThread(),
_worker_id_offset(worker_id_offset),
_worker_id(worker_id),
_active(false),
_next(next),
_monitor(NULL),
_cr(cr),
_vtime_accum(0.0),
_activation_threshold(activate),
_deactivation_threshold(deactivate)
_vtime_accum(0.0)
{
// Each thread has its own monitor. The i-th thread is responsible for signaling
// to thread i+1 if the number of buffers in the queue exceeds a threshold for this
// thread. Monitors are also used to wake up the threads during termination.
@ -67,13 +55,6 @@ G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr,
create_and_start();
}
void G1ConcurrentRefineThread::update_thresholds(size_t activate,
size_t deactivate) {
assert(deactivate < activate, "precondition");
_activation_threshold = activate;
_deactivation_threshold = deactivate;
}
void G1ConcurrentRefineThread::wait_for_completed_buffers() {
MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
while (!should_terminate() && !is_active()) {
@ -118,9 +99,9 @@ void G1ConcurrentRefineThread::run_service() {
}
size_t buffers_processed = 0;
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
log_debug(gc, refine)("Activated %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT,
_worker_id, _activation_threshold, dcqs.completed_buffers_num());
log_debug(gc, refine)("Activated worker %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT,
_worker_id, _cr->activation_threshold(_worker_id),
JavaThread::dirty_card_queue_set().completed_buffers_num());
{
SuspendibleThreadSetJoiner sts_join;
@ -131,33 +112,18 @@ void G1ConcurrentRefineThread::run_service() {
continue; // Re-check for termination after yield delay.
}
size_t curr_buffer_num = dcqs.completed_buffers_num();
// If the number of the buffers falls down into the yellow zone,
// that means that the transition period after the evacuation pause has ended.
if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cr()->yellow_zone()) {
dcqs.set_completed_queue_padding(0);
}
// Check if we need to activate the next thread.
if ((_next != NULL) &&
!_next->is_active() &&
(curr_buffer_num > _next->_activation_threshold)) {
_next->activate();
}
// Process the next buffer, if there are enough left.
if (!dcqs.refine_completed_buffer_concurrently(_worker_id + _worker_id_offset, _deactivation_threshold)) {
break; // Deactivate, number of buffers fell below threshold.
if (!_cr->do_refinement_step(_worker_id)) {
break;
}
++buffers_processed;
}
}
deactivate();
log_debug(gc, refine)("Deactivated %d, off threshold: " SIZE_FORMAT
log_debug(gc, refine)("Deactivated worker %d, off threshold: " SIZE_FORMAT
", current: " SIZE_FORMAT ", processed: " SIZE_FORMAT,
_worker_id, _deactivation_threshold,
dcqs.completed_buffers_num(),
_worker_id, _cr->deactivation_threshold(_worker_id),
JavaThread::dirty_card_queue_set().completed_buffers_num(),
buffers_processed);
if (os::supports_vtime()) {

View File

@ -43,43 +43,29 @@ class G1ConcurrentRefineThread: public ConcurrentGCThread {
uint _worker_id;
uint _worker_id_offset;
// The refinement threads collection is linked list. A predecessor can activate a successor
// when the number of the rset update buffer crosses a certain threshold. A successor
// would self-deactivate when the number of the buffers falls below the threshold.
bool _active;
G1ConcurrentRefineThread* _next;
Monitor* _monitor;
G1ConcurrentRefine* _cr;
// This thread's activation/deactivation thresholds
size_t _activation_threshold;
size_t _deactivation_threshold;
void wait_for_completed_buffers();
void set_active(bool x) { _active = x; }
bool is_active();
void activate();
// Deactivate this thread.
void deactivate();
bool is_primary() { return (_worker_id == 0); }
void run_service();
void stop_service();
public:
// Constructor
G1ConcurrentRefineThread(G1ConcurrentRefine* cr, G1ConcurrentRefineThread* next,
uint worker_id_offset, uint worker_id,
size_t activate, size_t deactivate);
G1ConcurrentRefineThread(G1ConcurrentRefine* cg1r, uint worker_id);
void update_thresholds(size_t activate, size_t deactivate);
size_t activation_threshold() const { return _activation_threshold; }
bool is_active();
// Activate this thread.
void activate();
// Total virtual time so far.
double vtime_accum() { return _vtime_accum; }
G1ConcurrentRefine* cr() { return _cr; }
};
#endif // SHARE_VM_GC_G1_G1CONCURRENTREFINETHREAD_HPP

View File

@ -35,6 +35,7 @@
#include "gc/g1/g1FullGCReferenceProcessorExecutor.hpp"
#include "gc/g1/g1FullGCScope.hpp"
#include "gc/g1/g1OopClosures.hpp"
#include "gc/g1/g1Policy.hpp"
#include "gc/g1/g1StringDedup.hpp"
#include "gc/shared/gcTraceTime.inline.hpp"
#include "gc/shared/preservedMarks.hpp"
@ -62,20 +63,24 @@ static void update_derived_pointers() {
#endif
}
G1FullCollector::G1FullCollector(G1FullGCScope* scope,
ReferenceProcessor* reference_processor,
G1CMBitMap* bitmap,
uint workers) :
_scope(scope),
_num_workers(workers),
_mark_bitmap(bitmap),
G1CMBitMap* G1FullCollector::mark_bitmap() {
return _heap->concurrent_mark()->next_mark_bitmap();
}
ReferenceProcessor* G1FullCollector::reference_processor() {
return _heap->ref_processor_stw();
}
G1FullCollector::G1FullCollector(G1CollectedHeap* heap, bool explicit_gc, bool clear_soft_refs) :
_heap(heap),
_scope(explicit_gc, clear_soft_refs),
_num_workers(heap->workers()->active_workers()),
_oop_queue_set(_num_workers),
_array_queue_set(_num_workers),
_preserved_marks_set(true),
_reference_processor(reference_processor),
_serial_compaction_point(),
_is_alive(_mark_bitmap),
_is_alive_mutator(_reference_processor, &_is_alive) {
_is_alive(heap->concurrent_mark()->next_mark_bitmap()),
_is_alive_mutator(heap->ref_processor_stw(), &_is_alive) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
_preserved_marks_set.init(_num_workers);
@ -99,8 +104,19 @@ G1FullCollector::~G1FullCollector() {
}
void G1FullCollector::prepare_collection() {
_reference_processor->enable_discovery();
_reference_processor->setup_policy(scope()->should_clear_soft_refs());
_heap->g1_policy()->record_full_collection_start();
_heap->print_heap_before_gc();
_heap->print_heap_regions();
_heap->abort_concurrent_cycle();
_heap->verify_before_full_collection(scope()->is_explicit_gc());
_heap->gc_prologue(true);
_heap->prepare_heap_for_full_collection();
reference_processor()->enable_discovery();
reference_processor()->setup_policy(scope()->should_clear_soft_refs());
// When collecting the permanent generation Method*s may be moving,
// so we either have to flush all bcp data or convert it into bci.
@ -139,6 +155,15 @@ void G1FullCollector::complete_collection() {
BiasedLocking::restore_marks();
CodeCache::gc_epilogue();
JvmtiExport::gc_epilogue();
_heap->prepare_heap_for_mutators();
_heap->g1_policy()->record_full_collection_end();
_heap->gc_epilogue(true);
_heap->verify_after_full_collection();
_heap->print_heap_after_full_collection(scope()->heap_transition());
}
void G1FullCollector::phase1_mark_live_objects() {
@ -164,11 +189,11 @@ void G1FullCollector::phase1_mark_live_objects() {
GCTraceTime(Debug, gc, phases) debug("Phase 1: Class Unloading and Cleanup", scope()->timer());
// Unload classes and purge the SystemDictionary.
bool purged_class = SystemDictionary::do_unloading(&_is_alive, scope()->timer());
G1CollectedHeap::heap()->complete_cleaning(&_is_alive, purged_class);
_heap->complete_cleaning(&_is_alive, purged_class);
} else {
GCTraceTime(Debug, gc, phases) debug("Phase 1: String and Symbol Tables Cleanup", scope()->timer());
// If no class unloading just clean out strings and symbols.
G1CollectedHeap::heap()->partial_cleaning(&_is_alive, true, true, G1StringDedup::is_enabled());
_heap->partial_cleaning(&_is_alive, true, true, G1StringDedup::is_enabled());
}
scope()->tracer()->report_object_count_after_gc(&_is_alive);
@ -210,13 +235,13 @@ void G1FullCollector::phase4_do_compaction() {
}
void G1FullCollector::restore_marks() {
SharedRestorePreservedMarksTaskExecutor task_executor(G1CollectedHeap::heap()->workers());
SharedRestorePreservedMarksTaskExecutor task_executor(_heap->workers());
_preserved_marks_set.restore(&task_executor);
_preserved_marks_set.reclaim();
}
void G1FullCollector::run_task(AbstractGangTask* task) {
G1CollectedHeap::heap()->workers()->run_task(task, _num_workers);
_heap->workers()->run_task(task, _num_workers);
}
void G1FullCollector::verify_after_marking() {
@ -229,7 +254,7 @@ void G1FullCollector::verify_after_marking() {
#if COMPILER2_OR_JVMCI
DerivedPointerTableDeactivate dpt_deact;
#endif
G1CollectedHeap::heap()->prepare_for_verify();
_heap->prepare_for_verify();
// Note: we can verify only the heap here. When an object is
// marked, the previous value of the mark word (including
// identity hash values, ages, etc) is preserved, and the mark
@ -241,5 +266,5 @@ void G1FullCollector::verify_after_marking() {
// (including hash values) are restored to the appropriate
// objects.
GCTraceTime(Info, gc, verify)("During GC (full)");
G1CollectedHeap::heap()->verify(VerifyOption_G1UseFullMarking);
_heap->verify(VerifyOption_G1UseFullMarking);
}

View File

@ -28,6 +28,7 @@
#include "gc/g1/g1FullGCCompactionPoint.hpp"
#include "gc/g1/g1FullGCMarker.hpp"
#include "gc/g1/g1FullGCOopClosures.hpp"
#include "gc/g1/g1FullGCScope.hpp"
#include "gc/shared/preservedMarks.hpp"
#include "gc/shared/referenceProcessor.hpp"
#include "gc/shared/taskqueue.hpp"
@ -42,41 +43,36 @@ class ReferenceProcessor;
// The G1FullCollector holds data associated with the current Full GC.
class G1FullCollector : StackObj {
G1FullGCScope* _scope;
G1CollectedHeap* _heap;
G1FullGCScope _scope;
uint _num_workers;
G1FullGCMarker** _markers;
G1FullGCCompactionPoint** _compaction_points;
G1CMBitMap* _mark_bitmap;
OopQueueSet _oop_queue_set;
ObjArrayTaskQueueSet _array_queue_set;
PreservedMarksSet _preserved_marks_set;
ReferenceProcessor* _reference_processor;
G1FullGCCompactionPoint _serial_compaction_point;
G1IsAliveClosure _is_alive;
ReferenceProcessorIsAliveMutator _is_alive_mutator;
public:
G1FullCollector(G1FullGCScope* scope,
ReferenceProcessor* reference_processor,
G1CMBitMap* mark_bitmap,
uint workers);
G1FullCollector(G1CollectedHeap* heap, bool explicit_gc, bool clear_soft_refs);
~G1FullCollector();
void prepare_collection();
void collect();
void complete_collection();
G1FullGCScope* scope() { return _scope; }
G1FullGCScope* scope() { return &_scope; }
uint workers() { return _num_workers; }
G1FullGCMarker* marker(uint id) { return _markers[id]; }
G1FullGCCompactionPoint* compaction_point(uint id) { return _compaction_points[id]; }
G1CMBitMap* mark_bitmap() { return _mark_bitmap; }
OopQueueSet* oop_queue_set() { return &_oop_queue_set; }
ObjArrayTaskQueueSet* array_queue_set() { return &_array_queue_set; }
PreservedMarksSet* preserved_mark_set() { return &_preserved_marks_set; }
ReferenceProcessor* reference_processor() { return _reference_processor; }
G1FullGCCompactionPoint* serial_compaction_point() { return &_serial_compaction_point; }
G1CMBitMap* mark_bitmap();
ReferenceProcessor* reference_processor();
private:
void phase1_mark_live_objects();

View File

@ -298,7 +298,7 @@ G1RemSet::~G1RemSet() {
}
uint G1RemSet::num_par_rem_sets() {
return MAX2(DirtyCardQueueSet::num_par_ids() + G1ConcurrentRefine::thread_num(), ParallelGCThreads);
return MAX2(DirtyCardQueueSet::num_par_ids() + G1ConcurrentRefine::max_num_threads(), ParallelGCThreads);
}
void G1RemSet::initialize(size_t capacity, uint max_regions) {

View File

@ -86,7 +86,7 @@ G1RemSetSummary::G1RemSetSummary() :
_num_processed_buf_mutator(0),
_num_processed_buf_rs_threads(0),
_num_coarsenings(0),
_num_vtimes(G1ConcurrentRefine::thread_num()),
_num_vtimes(G1ConcurrentRefine::max_num_threads()),
_rs_threads_vtimes(NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC)),
_sampling_thread_vtime(0.0f) {
@ -99,7 +99,7 @@ G1RemSetSummary::G1RemSetSummary(G1RemSet* rem_set) :
_num_processed_buf_mutator(0),
_num_processed_buf_rs_threads(0),
_num_coarsenings(0),
_num_vtimes(G1ConcurrentRefine::thread_num()),
_num_vtimes(G1ConcurrentRefine::max_num_threads()),
_rs_threads_vtimes(NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC)),
_sampling_thread_vtime(0.0f) {
update();

View File

@ -175,6 +175,9 @@ void G1SATBCardTableLoggingModRefBS::write_ref_field_post_slow(volatile jbyte* b
void
G1SATBCardTableLoggingModRefBS::invalidate(MemRegion mr) {
if (mr.is_empty()) {
return;
}
volatile jbyte* byte = byte_for(mr.start());
jbyte* last_byte = byte_for(mr.last());
Thread* thr = Thread::current();

View File

@ -32,6 +32,7 @@
#include "runtime/mutexLocker.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/thread.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vmThread.hpp"
SATBMarkQueue::SATBMarkQueue(SATBMarkQueueSet* qset, bool permanent) :
@ -214,7 +215,7 @@ void SATBMarkQueueSet::dump_active_states(bool expected_active) {
log_error(gc, verify)("Expected SATB active state: %s", expected_active ? "ACTIVE" : "INACTIVE");
log_error(gc, verify)("Actual SATB active states:");
log_error(gc, verify)(" Queue set: %s", is_active() ? "ACTIVE" : "INACTIVE");
for (JavaThread* t = Threads::first(); t; t = t->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
log_error(gc, verify)(" Thread \"%s\" queue: %s", t->name(), t->satb_mark_queue().is_active() ? "ACTIVE" : "INACTIVE");
}
log_error(gc, verify)(" Shared queue: %s", shared_satb_queue()->is_active() ? "ACTIVE" : "INACTIVE");
@ -228,7 +229,7 @@ void SATBMarkQueueSet::verify_active_states(bool expected_active) {
}
// Verify thread queue states
for (JavaThread* t = Threads::first(); t; t = t->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
if (t->satb_mark_queue().is_active() != expected_active) {
dump_active_states(expected_active);
guarantee(false, "Thread SATB queue has an unexpected active state");
@ -249,14 +250,14 @@ void SATBMarkQueueSet::set_active_all_threads(bool active, bool expected_active)
verify_active_states(expected_active);
#endif // ASSERT
_all_active = active;
for (JavaThread* t = Threads::first(); t; t = t->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
t->satb_mark_queue().set_active(active);
}
shared_satb_queue()->set_active(active);
}
void SATBMarkQueueSet::filter_thread_buffers() {
for(JavaThread* t = Threads::first(); t; t = t->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
t->satb_mark_queue().filter();
}
shared_satb_queue()->filter();
@ -309,7 +310,7 @@ void SATBMarkQueueSet::print_all(const char* msg) {
i += 1;
}
for (JavaThread* t = Threads::first(); t; t = t->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
jio_snprintf(buffer, SATB_PRINTER_BUFFER_SIZE, "Thread: %s", t->name());
t->satb_mark_queue().print(buffer);
}
@ -341,8 +342,8 @@ void SATBMarkQueueSet::abandon_partial_marking() {
}
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
// So we can safely manipulate these queues.
for (JavaThread* t = Threads::first(); t; t = t->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
t->satb_mark_queue().reset();
}
shared_satb_queue()->reset();
shared_satb_queue()->reset();
}

View File

@ -29,6 +29,7 @@
#include "oops/oop.inline.hpp"
#include "runtime/atomic.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "utilities/align.hpp"
MutableNUMASpace::MutableNUMASpace(size_t alignment) : MutableSpace(alignment), _must_use_large_pages(false) {
@ -287,7 +288,7 @@ bool MutableNUMASpace::update_layout(bool force) {
FREE_C_HEAP_ARRAY(int, lgrp_ids);
if (changed) {
for (JavaThread *thread = Threads::first(); thread; thread = thread->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
thread->set_lgrp_id(-1);
}
}

View File

@ -40,6 +40,7 @@
#include "oops/oop.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "services/heapDumper.hpp"
#include "utilities/align.hpp"
@ -540,10 +541,11 @@ void CollectedHeap::ensure_parsability(bool retire_tlabs) {
const bool deferred = _defer_initial_card_mark;
// The main thread starts allocating via a TLAB even before it
// has added itself to the threads list at vm boot-up.
assert(!use_tlab || Threads::first() != NULL,
JavaThreadIteratorWithHandle jtiwh;
assert(!use_tlab || jtiwh.length() > 0,
"Attempt to fill tlabs before main thread has been added"
" to threads list is doomed to failure!");
for (JavaThread *thread = Threads::first(); thread; thread = thread->next()) {
for (; JavaThread *thread = jtiwh.next(); ) {
if (use_tlab) thread->tlab().make_parsable(retire_tlabs);
#if COMPILER2_OR_JVMCI
// The deferred store barriers must all have been flushed to the

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,6 +29,7 @@
#include "logging/log.hpp"
#include "runtime/atomic.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
volatile jint GCLocker::_jni_lock_count = 0;
volatile bool GCLocker::_needs_gc = false;
@ -45,14 +46,16 @@ void GCLocker::verify_critical_count() {
assert(!needs_gc() || _debug_jni_lock_count == _jni_lock_count, "must agree");
int count = 0;
// Count the number of threads with critical operations in progress
for (JavaThread* thr = Threads::first(); thr; thr = thr->next()) {
JavaThreadIteratorWithHandle jtiwh;
for (; JavaThread *thr = jtiwh.next(); ) {
if (thr->in_critical()) {
count++;
}
}
if (_jni_lock_count != count) {
log_error(gc, verify)("critical counts don't match: %d != %d", _jni_lock_count, count);
for (JavaThread* thr = Threads::first(); thr; thr = thr->next()) {
jtiwh.rewind();
for (; JavaThread *thr = jtiwh.next(); ) {
if (thr->in_critical()) {
log_error(gc, verify)(INTPTR_FORMAT " in_critical %d", p2i(thr), thr->in_critical());
}

View File

@ -30,6 +30,7 @@
#include "memory/universe.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "utilities/copy.hpp"
// Thread-Local Edens support
@ -48,7 +49,7 @@ void ThreadLocalAllocBuffer::clear_before_allocation() {
void ThreadLocalAllocBuffer::accumulate_statistics_before_gc() {
global_stats()->initialize();
for (JavaThread *thread = Threads::first(); thread != NULL; thread = thread->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
thread->tlab().accumulate_statistics();
thread->tlab().initialize_statistics();
}
@ -130,7 +131,7 @@ void ThreadLocalAllocBuffer::make_parsable(bool retire, bool zap) {
void ThreadLocalAllocBuffer::resize_all_tlabs() {
if (ResizeTLAB) {
for (JavaThread *thread = Threads::first(); thread != NULL; thread = thread->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
thread->tlab().resize();
}
}

View File

@ -42,6 +42,7 @@
#include "runtime/interfaceSupport.hpp"
#include "runtime/reflection.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/threadSMR.hpp"
#include "utilities/debug.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/macros.hpp"
@ -598,12 +599,13 @@ JRT_ENTRY(jint, JVMCIRuntime::identity_hash_code(JavaThread* thread, oopDesc* ob
JRT_END
JRT_ENTRY(jboolean, JVMCIRuntime::thread_is_interrupted(JavaThread* thread, oopDesc* receiver, jboolean clear_interrupted))
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate.
// This locking requires thread_in_vm which is why this method cannot be JRT_LEAF.
Handle receiverHandle(thread, receiver);
MutexLockerEx ml(thread->threadObj() == (void*)receiver ? NULL : Threads_lock);
// A nested ThreadsListHandle may require the Threads_lock which
// requires thread_in_vm which is why this method cannot be JRT_LEAF.
ThreadsListHandle tlh;
JavaThread* receiverThread = java_lang_Thread::thread(receiverHandle());
if (receiverThread == NULL) {
if (receiverThread == NULL || (EnableThreadSMRExtraValidityChecks && !tlh.includes(receiverThread))) {
// The other thread may exit during this process, which is ok so return false.
return JNI_FALSE;
} else {

View File

@ -121,6 +121,7 @@
LOG_TAG(safepoint) \
LOG_TAG(scavenge) \
LOG_TAG(scrub) \
LOG_TAG(smr) \
LOG_TAG(stacktrace) \
LOG_TAG(stackwalk) \
LOG_TAG(start) \

View File

@ -687,6 +687,10 @@ jint universe_init() {
Metaspace::global_initialize();
// Initialize performance counters for metaspaces
MetaspaceCounters::initialize_performance_counters();
CompressedClassSpaceCounters::initialize_performance_counters();
AOTLoader::universe_init();
// Checks 'AfterMemoryInit' constraints.
@ -1085,10 +1089,6 @@ bool universe_post_init() {
// ("weak") refs processing infrastructure initialization
Universe::heap()->post_initialize();
// Initialize performance counters for metaspaces
MetaspaceCounters::initialize_performance_counters();
CompressedClassSpaceCounters::initialize_performance_counters();
MemoryService::add_metaspace_memory_pools();
MemoryService::set_universe_heap(Universe::heap());

View File

@ -71,10 +71,15 @@ void InstanceMirrorKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
Devirtualizer<nv>::do_klass(closure, klass);
}
} else {
// If klass is NULL then this a mirror for a primitive type.
// We don't have to follow them, since they are handled as strong
// roots in Universe::oops_do.
assert(java_lang_Class::is_primitive(obj), "Sanity check");
// We would like to assert here (as below) that if klass has been NULL, then
// this has been a mirror for a primitive type that we do not need to follow
// as they are always strong roots.
// However, we might get across a klass that just changed during CMS concurrent
// marking if allocation occurred in the old generation.
// This is benign here, as we keep alive all CLDs that were loaded during the
// CMS concurrent phase in the class loading, i.e. they will be iterated over
// and kept alive during remark.
// assert(java_lang_Class::is_primitive(obj), "Sanity check");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -480,6 +480,7 @@ const char* InlineTree::check_can_parse(ciMethod* callee) {
if ( callee->is_abstract()) return "abstract method";
if (!callee->has_balanced_monitors()) return "not compilable (unbalanced monitors)";
if ( callee->get_flow_analysis()->failing()) return "not compilable (flow analysis failed)";
if (!callee->can_be_parsed()) return "cannot be parsed";
return NULL;
}

View File

@ -252,6 +252,7 @@ macro(SafePoint)
macro(SafePointScalarObject)
macro(SCMemProj)
macro(SqrtD)
macro(SqrtF)
macro(Start)
macro(StartOSR)
macro(StoreB)
@ -320,6 +321,7 @@ macro(AbsVD)
macro(NegVF)
macro(NegVD)
macro(SqrtVD)
macro(SqrtVF)
macro(LShiftCntV)
macro(RShiftCntV)
macro(LShiftVB)

View File

@ -73,6 +73,21 @@ const Type* ConvD2FNode::Value(PhaseGVN* phase) const {
return TypeF::make( (float)td->getd() );
}
//------------------------------Ideal------------------------------------------
// If we see pattern ConvF2D SomeDoubleOp ConvD2F, do operation as float.
Node *ConvD2FNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if ( in(1)->Opcode() == Op_SqrtD ) {
Node* sqrtd = in(1);
if ( sqrtd->in(1)->Opcode() == Op_ConvF2D ) {
if ( Matcher::match_rule_supported(Op_SqrtF) ) {
Node* convf2d = sqrtd->in(1);
return new SqrtFNode(phase->C, sqrtd->in(0), convf2d->in(1));
}
}
}
return NULL;
}
//------------------------------Identity---------------------------------------
// Float's can be converted to doubles with no loss of bits. Hence
// converting a float to a double and back to a float is a NOP.

View File

@ -51,6 +51,7 @@ class ConvD2FNode : public Node {
virtual const Type *bottom_type() const { return Type::FLOAT; }
virtual const Type* Value(PhaseGVN* phase) const;
virtual Node* Identity(PhaseGVN* phase);
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
virtual uint ideal_reg() const { return Op_RegF; }
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,6 +29,7 @@
#include "opto/machnode.hpp"
#include "opto/parse.hpp"
#include "runtime/threadCritical.hpp"
#include "runtime/threadSMR.hpp"
#ifndef PRODUCT
@ -91,8 +92,7 @@ IdealGraphPrinter *IdealGraphPrinter::printer() {
}
void IdealGraphPrinter::clean_up() {
JavaThread *p;
for (p = Threads::first(); p; p = p->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *p = jtiwh.next(); ) {
if (p->is_Compiler_thread()) {
CompilerThread *c = (CompilerThread *)p;
IdealGraphPrinter *printer = c->ideal_graph_printer();

View File

@ -1595,3 +1595,12 @@ const Type* SqrtDNode::Value(PhaseGVN* phase) const {
if( d < 0.0 ) return Type::DOUBLE;
return TypeD::make( sqrt( d ) );
}
const Type* SqrtFNode::Value(PhaseGVN* phase) const {
const Type *t1 = phase->type( in(1) );
if( t1 == Type::TOP ) return Type::TOP;
if( t1->base() != Type::FloatCon ) return Type::FLOAT;
float f = t1->getf();
if( f < 0.0f ) return Type::FLOAT;
return TypeF::make( (float)sqrt( (double)f ) );
}

View File

@ -442,6 +442,20 @@ public:
virtual const Type* Value(PhaseGVN* phase) const;
};
//------------------------------SqrtFNode--------------------------------------
// square root a float
class SqrtFNode : public Node {
public:
SqrtFNode(Compile* C, Node *c, Node *in1) : Node(c, in1) {
init_flags(Flag_is_expensive);
C->add_expensive_node(this);
}
virtual int Opcode() const;
const Type *bottom_type() const { return Type::FLOAT; }
virtual uint ideal_reg() const { return Op_RegF; }
virtual const Type* Value(PhaseGVN* phase) const;
};
//-------------------------------ReverseBytesINode--------------------------------
// reverse bytes of an integer
class ReverseBytesINode : public Node {

View File

@ -2307,7 +2307,7 @@ void SuperWord::output() {
vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n));
vlen_in_bytes = vn->as_Vector()->length_in_bytes();
}
} else if (opc == Op_SqrtD || opc == Op_AbsF || opc == Op_AbsD || opc == Op_NegF || opc == Op_NegD) {
} else if (opc == Op_SqrtF || opc == Op_SqrtD || opc == Op_AbsF || opc == Op_AbsD || opc == Op_NegF || opc == Op_NegD) {
// Promote operand to vector (Sqrt/Abs/Neg are 2 address instructions)
Node* in = vector_opd(p, 1);
vn = VectorNode::make(opc, in, NULL, vlen, velt_basic_type(n));

View File

@ -113,6 +113,9 @@ int VectorNode::opcode(int sopc, BasicType bt) {
case Op_NegD:
assert(bt == T_DOUBLE, "must be");
return Op_NegVD;
case Op_SqrtF:
assert(bt == T_FLOAT, "must be");
return Op_SqrtVF;
case Op_SqrtD:
assert(bt == T_DOUBLE, "must be");
return Op_SqrtVD;
@ -316,7 +319,7 @@ VectorNode* VectorNode::make(int opc, Node* n1, Node* n2, uint vlen, BasicType b
case Op_NegVF: return new NegVFNode(n1, vt);
case Op_NegVD: return new NegVDNode(n1, vt);
// Currently only supports double precision sqrt
case Op_SqrtVF: return new SqrtVFNode(n1, vt);
case Op_SqrtVD: return new SqrtVDNode(n1, vt);
case Op_LShiftVB: return new LShiftVBNode(n1, n2, vt);

View File

@ -373,6 +373,14 @@ class NegVDNode : public VectorNode {
virtual int Opcode() const;
};
//------------------------------SqrtVFNode--------------------------------------
// Vector Sqrt float
class SqrtVFNode : public VectorNode {
public:
SqrtVFNode(Node* in, const TypeVect* vt) : VectorNode(in,vt) {}
virtual int Opcode() const;
};
//------------------------------SqrtVDNode--------------------------------------
// Vector Sqrt double
class SqrtVDNode : public VectorNode {

View File

@ -4119,7 +4119,7 @@ static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool dae
thread->initialize_thread_current();
if (!os::create_attached_thread(thread)) {
delete thread;
thread->smr_delete();
return JNI_ERR;
}
// Enable stack overflow checks
@ -4250,7 +4250,7 @@ jint JNICALL jni_DetachCurrentThread(JavaVM *vm) {
// (platform-dependent) methods where we do alternate stack
// maintenance work?)
thread->exit(false, JavaThread::jni_detach);
delete thread;
thread->smr_delete();
HOTSPOT_JNI_DETACHCURRENTTHREAD_RETURN(JNI_OK);
return JNI_OK;

View File

@ -66,6 +66,7 @@
#include "runtime/perfData.hpp"
#include "runtime/reflection.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vm_operations.hpp"
#include "runtime/vm_version.hpp"
@ -2737,16 +2738,12 @@ void jio_print(const char* s) {
// java.lang.Thread //////////////////////////////////////////////////////////////////////////////
// In most of the JVM Thread support functions we need to be sure to lock the Threads_lock
// to prevent the target thread from exiting after we have a pointer to the C++ Thread or
// OSThread objects. The exception to this rule is when the target object is the thread
// doing the operation, in which case we know that the thread won't exit until the
// operation is done (all exits being voluntary). There are a few cases where it is
// rather silly to do operations on yourself, like resuming yourself or asking whether
// you are alive. While these can still happen, they are not subject to deadlocks if
// the lock is held while the operation occurs (this is not the case for suspend, for
// instance), and are very unlikely. Because IsAlive needs to be fast and its
// implementation is local to this file, we always lock Threads_lock for that one.
// In most of the JVM thread support functions we need to access the
// thread through a ThreadsListHandle to prevent it from exiting and
// being reclaimed while we try to operate on it. The exceptions to this
// rule are when operating on the current thread, or if the monitor of
// the target java.lang.Thread is locked at the Java level - in both
// cases the target cannot exit.
static void thread_entry(JavaThread* thread, TRAPS) {
HandleMark hm(THREAD);
@ -2821,7 +2818,7 @@ JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
if (native_thread->osthread() == NULL) {
// No one should hold a reference to the 'native_thread'.
delete native_thread;
native_thread->smr_delete();
if (JvmtiExport::should_post_resource_exhausted()) {
JvmtiExport::post_resource_exhausted(
JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_THREADS,
@ -2835,41 +2832,45 @@ JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
JVM_END
// JVM_Stop is implemented using a VM_Operation, so threads are forced to safepoints
// before the quasi-asynchronous exception is delivered. This is a little obtrusive,
// but is thought to be reliable and simple. In the case, where the receiver is the
// same thread as the sender, no safepoint is needed.
// same thread as the sender, no VM_Operation is needed.
JVM_ENTRY(void, JVM_StopThread(JNIEnv* env, jobject jthread, jobject throwable))
JVMWrapper("JVM_StopThread");
// A nested ThreadsListHandle will grab the Threads_lock so create
// tlh before we resolve throwable.
ThreadsListHandle tlh(thread);
oop java_throwable = JNIHandles::resolve(throwable);
if (java_throwable == NULL) {
THROW(vmSymbols::java_lang_NullPointerException());
}
oop java_thread = JNIHandles::resolve_non_null(jthread);
JavaThread* receiver = java_lang_Thread::thread(java_thread);
Events::log_exception(JavaThread::current(),
oop java_thread = NULL;
JavaThread* receiver = NULL;
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, &java_thread);
Events::log_exception(thread,
"JVM_StopThread thread JavaThread " INTPTR_FORMAT " as oop " INTPTR_FORMAT " [exception " INTPTR_FORMAT "]",
p2i(receiver), p2i((address)java_thread), p2i(throwable));
// First check if thread is alive
if (receiver != NULL) {
// Check if exception is getting thrown at self (use oop equality, since the
// target object might exit)
if (java_thread == thread->threadObj()) {
if (is_alive) {
// jthread refers to a live JavaThread.
if (thread == receiver) {
// Exception is getting thrown at self so no VM_Operation needed.
THROW_OOP(java_throwable);
} else {
// Enques a VM_Operation to stop all threads and then deliver the exception...
Thread::send_async_exception(java_thread, JNIHandles::resolve(throwable));
// Use a VM_Operation to throw the exception.
Thread::send_async_exception(java_thread, java_throwable);
}
}
else {
} else {
// Either:
// - target thread has not been started before being stopped, or
// - target thread already terminated
// We could read the threadStatus to determine which case it is
// but that is overkill as it doesn't matter. We must set the
// stillborn flag for the first case, and if the thread has already
// exited setting this flag has no affect
// exited setting this flag has no effect.
java_lang_Thread::set_stillborn(java_thread);
}
JVM_END
@ -2885,12 +2886,12 @@ JVM_END
JVM_ENTRY(void, JVM_SuspendThread(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_SuspendThread");
oop java_thread = JNIHandles::resolve_non_null(jthread);
JavaThread* receiver = java_lang_Thread::thread(java_thread);
if (receiver != NULL) {
// thread has run and has not exited (still on threads list)
ThreadsListHandle tlh(thread);
JavaThread* receiver = NULL;
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
if (is_alive) {
// jthread refers to a live JavaThread.
{
MutexLockerEx ml(receiver->SR_lock(), Mutex::_no_safepoint_check_flag);
if (receiver->is_external_suspend()) {
@ -2922,30 +2923,49 @@ JVM_END
JVM_ENTRY(void, JVM_ResumeThread(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_ResumeThread");
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate.
// We need to *always* get the threads lock here, since this operation cannot be allowed during
// a safepoint. The safepoint code relies on suspending a thread to examine its state. If other
// threads randomly resumes threads, then a thread might not be suspended when the safepoint code
// looks at it.
MutexLocker ml(Threads_lock);
JavaThread* thr = java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread));
if (thr != NULL) {
// the thread has run and is not in the process of exiting
thr->java_resume();
ThreadsListHandle tlh(thread);
JavaThread* receiver = NULL;
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
if (is_alive) {
// jthread refers to a live JavaThread.
// This is the original comment for this Threads_lock grab:
// We need to *always* get the threads lock here, since this operation cannot be allowed during
// a safepoint. The safepoint code relies on suspending a thread to examine its state. If other
// threads randomly resumes threads, then a thread might not be suspended when the safepoint code
// looks at it.
//
// The above comment dates back to when we had both internal and
// external suspend APIs that shared a common underlying mechanism.
// External suspend is now entirely cooperative and doesn't share
// anything with internal suspend. That said, there are some
// assumptions in the VM that an external resume grabs the
// Threads_lock. We can't drop the Threads_lock grab here until we
// resolve the assumptions that exist elsewhere.
//
MutexLocker ml(Threads_lock);
receiver->java_resume();
}
JVM_END
JVM_ENTRY(void, JVM_SetThreadPriority(JNIEnv* env, jobject jthread, jint prio))
JVMWrapper("JVM_SetThreadPriority");
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate
MutexLocker ml(Threads_lock);
oop java_thread = JNIHandles::resolve_non_null(jthread);
ThreadsListHandle tlh(thread);
oop java_thread = NULL;
JavaThread* receiver = NULL;
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, &java_thread);
java_lang_Thread::set_priority(java_thread, (ThreadPriority)prio);
JavaThread* thr = java_lang_Thread::thread(java_thread);
if (thr != NULL) { // Thread not yet started; priority pushed down when it is
Thread::set_priority(thr, (ThreadPriority)prio);
if (is_alive) {
// jthread refers to a live JavaThread.
Thread::set_priority(receiver, (ThreadPriority)prio);
}
// Implied else: If the JavaThread hasn't started yet, then the
// priority set in the java.lang.Thread object above will be pushed
// down when it does start.
JVM_END
@ -3016,67 +3036,39 @@ JVM_END
JVM_ENTRY(jint, JVM_CountStackFrames(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_CountStackFrames");
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate
oop java_thread = JNIHandles::resolve_non_null(jthread);
bool throw_illegal_thread_state = false;
uint32_t debug_bits = 0;
ThreadsListHandle tlh(thread);
JavaThread* receiver = NULL;
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
int count = 0;
{
MutexLockerEx ml(thread->threadObj() == java_thread ? NULL : Threads_lock);
// We need to re-resolve the java_thread, since a GC might have happened during the
// acquire of the lock
JavaThread* thr = java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread));
if (thr == NULL) {
// do nothing
} else if(! thr->is_external_suspend() || ! thr->frame_anchor()->walkable()) {
// Check whether this java thread has been suspended already. If not, throws
// IllegalThreadStateException. We defer to throw that exception until
// Threads_lock is released since loading exception class has to leave VM.
// The correct way to test a thread is actually suspended is
// wait_for_ext_suspend_completion(), but we can't call that while holding
// the Threads_lock. The above tests are sufficient for our purposes
// provided the walkability of the stack is stable - which it isn't
// 100% but close enough for most practical purposes.
throw_illegal_thread_state = true;
} else {
// Count all java activation, i.e., number of vframes
for(vframeStream vfst(thr); !vfst.at_end(); vfst.next()) {
// Native frames are not counted
if (is_alive) {
// jthread refers to a live JavaThread.
if (receiver->is_thread_fully_suspended(true /* wait for suspend completion */, &debug_bits)) {
// Count all java activation, i.e., number of vframes.
for (vframeStream vfst(receiver); !vfst.at_end(); vfst.next()) {
// Native frames are not counted.
if (!vfst.method()->is_native()) count++;
}
}
} else {
THROW_MSG_0(vmSymbols::java_lang_IllegalThreadStateException(),
"this thread is not suspended");
}
}
// Implied else: if JavaThread is not alive simply return a count of 0.
if (throw_illegal_thread_state) {
THROW_MSG_0(vmSymbols::java_lang_IllegalThreadStateException(),
"this thread is not suspended");
}
return count;
JVM_END
// Consider: A better way to implement JVM_Interrupt() is to acquire
// Threads_lock to resolve the jthread into a Thread pointer, fetch
// Thread->platformevent, Thread->native_thr, Thread->parker, etc.,
// drop Threads_lock, and the perform the unpark() and thr_kill() operations
// outside the critical section. Threads_lock is hot so we want to minimize
// the hold-time. A cleaner interface would be to decompose interrupt into
// two steps. The 1st phase, performed under Threads_lock, would return
// a closure that'd be invoked after Threads_lock was dropped.
// This tactic is safe as PlatformEvent and Parkers are type-stable (TSM) and
// admit spurious wakeups.
JVM_ENTRY(void, JVM_Interrupt(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_Interrupt");
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate
oop java_thread = JNIHandles::resolve_non_null(jthread);
MutexLockerEx ml(thread->threadObj() == java_thread ? NULL : Threads_lock);
// We need to re-resolve the java_thread, since a GC might have happened during the
// acquire of the lock
JavaThread* thr = java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread));
if (thr != NULL) {
Thread::interrupt(thr);
ThreadsListHandle tlh(thread);
JavaThread* receiver = NULL;
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
if (is_alive) {
// jthread refers to a live JavaThread.
Thread::interrupt(receiver);
}
JVM_END
@ -3084,16 +3076,14 @@ JVM_END
JVM_QUICK_ENTRY(jboolean, JVM_IsInterrupted(JNIEnv* env, jobject jthread, jboolean clear_interrupted))
JVMWrapper("JVM_IsInterrupted");
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate
oop java_thread = JNIHandles::resolve_non_null(jthread);
MutexLockerEx ml(thread->threadObj() == java_thread ? NULL : Threads_lock);
// We need to re-resolve the java_thread, since a GC might have happened during the
// acquire of the lock
JavaThread* thr = java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread));
if (thr == NULL) {
return JNI_FALSE;
ThreadsListHandle tlh(thread);
JavaThread* receiver = NULL;
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
if (is_alive) {
// jthread refers to a live JavaThread.
return (jboolean) Thread::is_interrupted(receiver, clear_interrupted != 0);
} else {
return (jboolean) Thread::is_interrupted(thr, clear_interrupted != 0);
return JNI_FALSE;
}
JVM_END
@ -3122,14 +3112,16 @@ JVM_END
JVM_ENTRY(void, JVM_SetNativeThreadName(JNIEnv* env, jobject jthread, jstring name))
JVMWrapper("JVM_SetNativeThreadName");
ResourceMark rm(THREAD);
// We don't use a ThreadsListHandle here because the current thread
// must be alive.
oop java_thread = JNIHandles::resolve_non_null(jthread);
JavaThread* thr = java_lang_Thread::thread(java_thread);
// Thread naming only supported for the current thread, doesn't work for
// target threads.
if (Thread::current() == thr && !thr->has_attached_via_jni()) {
if (thread == thr && !thr->has_attached_via_jni()) {
// Thread naming is only supported for the current thread and
// we don't set the name of an attached thread to avoid stepping
// on other programs
// on other programs.
ResourceMark rm(thread);
const char *thread_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(name));
os::set_native_thread_name(thread_name);
}
@ -3671,6 +3663,8 @@ JVM_ENTRY(jobjectArray, JVM_DumpThreads(JNIEnv *env, jclass threadClass, jobject
thread_handle_array->append(h);
}
// The JavaThread references in thread_handle_array are validated
// in VM_ThreadDump::doit().
Handle stacktraces = ThreadService::dump_stack_traces(thread_handle_array, num_threads, CHECK_NULL);
return (jobjectArray)JNIHandles::make_local(env, stacktraces());

View File

@ -45,6 +45,7 @@
# include "prims/jvmtiEnter.hpp"
# include "prims/jvmtiRawMonitor.hpp"
# include "prims/jvmtiUtil.hpp"
# include "runtime/threadSMR.hpp"
</xsl:text>
@ -769,47 +770,27 @@ static jvmtiError JNICALL
<xsl:template match="jthread" mode="dochecksbody">
<xsl:param name="name"/>
<xsl:text> oop thread_oop = JNIHandles::resolve_external_guard(</xsl:text>
<xsl:text> err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), </xsl:text>
<xsl:value-of select="$name"/>
<xsl:text>);
if (thread_oop == NULL) {
<xsl:text>, &amp;java_thread, NULL);
if (err != JVMTI_ERROR_NONE) {
</xsl:text>
<xsl:apply-templates select=".." mode="traceError">
<xsl:with-param name="err">JVMTI_ERROR_INVALID_THREAD</xsl:with-param>
<xsl:with-param name="comment"> - jthread resolved to NULL - jthread = " PTR_FORMAT "</xsl:with-param>
<xsl:with-param name="err">err</xsl:with-param>
<xsl:with-param name="comment"> - jthread did not convert to a JavaThread - jthread = " PTR_FORMAT "</xsl:with-param>
<xsl:with-param name="extraValue">, p2i(<xsl:value-of select="$name"/>)</xsl:with-param>
</xsl:apply-templates>
<xsl:text>
}
if (!thread_oop-&gt;is_a(SystemDictionary::Thread_klass())) {
</xsl:text>
<xsl:apply-templates select=".." mode="traceError">
<xsl:with-param name="err">JVMTI_ERROR_INVALID_THREAD</xsl:with-param>
<xsl:with-param name="comment"> - oop is not a thread - jthread = " PTR_FORMAT "</xsl:with-param>
<xsl:with-param name="extraValue">, p2i(<xsl:value-of select="$name"/>)</xsl:with-param>
</xsl:apply-templates>
<xsl:text>
}
java_thread = java_lang_Thread::thread(thread_oop);
if (java_thread == NULL) {
</xsl:text>
<xsl:apply-templates select=".." mode="traceError">
<xsl:with-param name="err">
<xsl:text>JVMTI_ERROR_THREAD_NOT_ALIVE</xsl:text>
</xsl:with-param>
<xsl:with-param name="comment"> - not a Java thread - jthread = " PTR_FORMAT "</xsl:with-param>
<xsl:with-param name="extraValue">, p2i(<xsl:value-of select="$name"/>)</xsl:with-param>
</xsl:apply-templates>
<xsl:text>
}
</xsl:text>
</xsl:template>
<xsl:template match="jthread" mode="dochecks">
<xsl:param name="name"/>
<!-- If we convert and test threads -->
<xsl:if test="count(@impl)=0 or not(contains(@impl,'noconvert'))">
<xsl:text> JavaThread* java_thread;
<xsl:text> JavaThread* java_thread = NULL;
ThreadsListHandle tlh(this_thread);
</xsl:text>
<xsl:choose>
<xsl:when test="count(@null)=0">

View File

@ -62,6 +62,7 @@
#include "runtime/reflectionUtils.hpp"
#include "runtime/signature.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/timerTrace.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vmThread.hpp"
@ -162,7 +163,6 @@ JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) {
*data_ptr = (state == NULL) ? NULL :
state->env_thread_state(this)->get_agent_thread_local_storage_data();
} else {
// jvmti_GetThreadLocalStorage is "in native" and doesn't transition
// the thread to _thread_in_vm. However, when the TLS for a thread
// other than the current thread is required we need to transition
@ -172,17 +172,13 @@ JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) {
VM_ENTRY_BASE(jvmtiError, JvmtiEnv::GetThreadLocalStorage , current_thread)
debug_only(VMNativeEntryWrapper __vew;)
oop thread_oop = JNIHandles::resolve_external_guard(thread);
if (thread_oop == NULL) {
return JVMTI_ERROR_INVALID_THREAD;
}
if (!thread_oop->is_a(SystemDictionary::Thread_klass())) {
return JVMTI_ERROR_INVALID_THREAD;
}
JavaThread* java_thread = java_lang_Thread::thread(thread_oop);
if (java_thread == NULL) {
return JVMTI_ERROR_THREAD_NOT_ALIVE;
JavaThread* java_thread = NULL;
ThreadsListHandle tlh(current_thread);
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, NULL);
if (err != JVMTI_ERROR_NONE) {
return err;
}
JvmtiThreadState* state = java_thread->jvmti_thread_state();
*data_ptr = (state == NULL) ? NULL :
state->env_thread_state(this)->get_agent_thread_local_storage_data();
@ -518,42 +514,60 @@ JvmtiEnv::SetEventCallbacks(const jvmtiEventCallbacks* callbacks, jint size_of_c
// event_thread - NULL is a valid value, must be checked
jvmtiError
JvmtiEnv::SetEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event_type, jthread event_thread, ...) {
JavaThread* java_thread = NULL;
if (event_thread != NULL) {
oop thread_oop = JNIHandles::resolve_external_guard(event_thread);
if (thread_oop == NULL) {
return JVMTI_ERROR_INVALID_THREAD;
if (event_thread == NULL) {
// Can be called at Agent_OnLoad() time with event_thread == NULL
// when Thread::current() does not work yet so we cannot create a
// ThreadsListHandle that is common to both thread-specific and
// global code paths.
// event_type must be valid
if (!JvmtiEventController::is_valid_event_type(event_type)) {
return JVMTI_ERROR_INVALID_EVENT_TYPE;
}
if (!thread_oop->is_a(SystemDictionary::Thread_klass())) {
return JVMTI_ERROR_INVALID_THREAD;
bool enabled = (mode == JVMTI_ENABLE);
// assure that needed capabilities are present
if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) {
return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
}
java_thread = java_lang_Thread::thread(thread_oop);
if (java_thread == NULL) {
return JVMTI_ERROR_THREAD_NOT_ALIVE;
if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
record_class_file_load_hook_enabled();
}
}
JvmtiEventController::set_user_enabled(this, (JavaThread*) NULL, event_type, enabled);
} else {
// We have a specified event_thread.
// event_type must be valid
if (!JvmtiEventController::is_valid_event_type(event_type)) {
return JVMTI_ERROR_INVALID_EVENT_TYPE;
}
JavaThread* java_thread = NULL;
ThreadsListHandle tlh;
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), event_thread, &java_thread, NULL);
if (err != JVMTI_ERROR_NONE) {
return err;
}
// global events cannot be controlled at thread level.
if (java_thread != NULL && JvmtiEventController::is_global_event(event_type)) {
return JVMTI_ERROR_ILLEGAL_ARGUMENT;
}
// event_type must be valid
if (!JvmtiEventController::is_valid_event_type(event_type)) {
return JVMTI_ERROR_INVALID_EVENT_TYPE;
}
bool enabled = (mode == JVMTI_ENABLE);
// global events cannot be controlled at thread level.
if (JvmtiEventController::is_global_event(event_type)) {
return JVMTI_ERROR_ILLEGAL_ARGUMENT;
}
// assure that needed capabilities are present
if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) {
return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
}
bool enabled = (mode == JVMTI_ENABLE);
if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
record_class_file_load_hook_enabled();
// assure that needed capabilities are present
if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) {
return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
}
if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
record_class_file_load_hook_enabled();
}
JvmtiEventController::set_user_enabled(this, java_thread, event_type, enabled);
}
JvmtiEventController::set_user_enabled(this, java_thread, event_type, enabled);
return JVMTI_ERROR_NONE;
} /* end SetEventNotificationMode */
@ -817,35 +831,45 @@ JvmtiEnv::GetJLocationFormat(jvmtiJlocationFormat* format_ptr) {
// thread_state_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetThreadState(jthread thread, jint* thread_state_ptr) {
jint state;
oop thread_oop;
JavaThread* thr;
JavaThread* current_thread = JavaThread::current();
JavaThread* java_thread = NULL;
oop thread_oop = NULL;
ThreadsListHandle tlh(current_thread);
if (thread == NULL) {
thread_oop = JavaThread::current()->threadObj();
} else {
thread_oop = JNIHandles::resolve_external_guard(thread);
}
java_thread = current_thread;
thread_oop = java_thread->threadObj();
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
return JVMTI_ERROR_INVALID_THREAD;
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
return JVMTI_ERROR_INVALID_THREAD;
}
} else {
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
if (err != JVMTI_ERROR_NONE) {
// We got an error code so we don't have a JavaThread *, but
// only return an error from here if we didn't get a valid
// thread_oop.
if (thread_oop == NULL) {
return err;
}
// We have a valid thread_oop so we can return some thread state.
}
}
// get most state bits
state = (jint)java_lang_Thread::get_thread_status(thread_oop);
jint state = (jint)java_lang_Thread::get_thread_status(thread_oop);
// add more state bits
thr = java_lang_Thread::thread(thread_oop);
if (thr != NULL) {
JavaThreadState jts = thr->thread_state();
if (java_thread != NULL) {
// We have a JavaThread* so add more state bits.
JavaThreadState jts = java_thread->thread_state();
if (thr->is_being_ext_suspended()) {
if (java_thread->is_being_ext_suspended()) {
state |= JVMTI_THREAD_STATE_SUSPENDED;
}
if (jts == _thread_in_native) {
state |= JVMTI_THREAD_STATE_IN_NATIVE;
}
OSThread* osThread = thr->osthread();
OSThread* osThread = java_thread->osthread();
if (osThread != NULL && osThread->interrupted()) {
state |= JVMTI_THREAD_STATE_INTERRUPTED;
}
@ -891,7 +915,6 @@ JvmtiEnv::GetAllThreads(jint* threads_count_ptr, jthread** threads_ptr) {
thread_objs[i] = Handle(tle.get_threadObj(i));
}
// have to make global handles outside of Threads_lock
jthread *jthreads = new_jthreadArray(nthreads, thread_objs);
NULL_CHECK(jthreads, JVMTI_ERROR_OUT_OF_MEMORY);
@ -935,19 +958,12 @@ JvmtiEnv::SuspendThread(JavaThread* java_thread) {
jvmtiError
JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
int needSafepoint = 0; // > 0 if we need a safepoint
ThreadsListHandle tlh;
for (int i = 0; i < request_count; i++) {
JavaThread *java_thread = get_JavaThread(request_list[i]);
if (java_thread == NULL) {
results[i] = JVMTI_ERROR_INVALID_THREAD;
continue;
}
// the thread has not yet run or has exited (not on threads list)
if (java_thread->threadObj() == NULL) {
results[i] = JVMTI_ERROR_THREAD_NOT_ALIVE;
continue;
}
if (java_lang_Thread::thread(java_thread->threadObj()) == NULL) {
results[i] = JVMTI_ERROR_THREAD_NOT_ALIVE;
JavaThread *java_thread = NULL;
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), request_list[i], &java_thread, NULL);
if (err != JVMTI_ERROR_NONE) {
results[i] = err;
continue;
}
// don't allow hidden thread suspend request.
@ -1018,10 +1034,12 @@ JvmtiEnv::ResumeThread(JavaThread* java_thread) {
// results - pre-checked for NULL
jvmtiError
JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
ThreadsListHandle tlh;
for (int i = 0; i < request_count; i++) {
JavaThread *java_thread = get_JavaThread(request_list[i]);
if (java_thread == NULL) {
results[i] = JVMTI_ERROR_INVALID_THREAD;
JavaThread* java_thread = NULL;
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), request_list[i], &java_thread, NULL);
if (err != JVMTI_ERROR_NONE) {
results[i] = err;
continue;
}
// don't allow hidden thread resume request.
@ -1039,7 +1057,7 @@ JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmt
continue;
}
results[i] = JVMTI_ERROR_NONE; // indicate successful suspend
results[i] = JVMTI_ERROR_NONE; // indicate successful resume
}
// per-thread resume results returned via results parameter
return JVMTI_ERROR_NONE;
@ -1064,20 +1082,14 @@ JvmtiEnv::StopThread(JavaThread* java_thread, jobject exception) {
// thread - NOT pre-checked
jvmtiError
JvmtiEnv::InterruptThread(jthread thread) {
oop thread_oop = JNIHandles::resolve_external_guard(thread);
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass()))
return JVMTI_ERROR_INVALID_THREAD;
// TODO: this is very similar to JVM_Interrupt(); share code in future
JavaThread* current_thread = JavaThread::current();
// Todo: this is a duplicate of JVM_Interrupt; share code in future
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate
MutexLockerEx ml(current_thread->threadObj() == thread_oop ? NULL : Threads_lock);
// We need to re-resolve the java_thread, since a GC might have happened during the
// acquire of the lock
JavaThread* java_thread = java_lang_Thread::thread(JNIHandles::resolve_external_guard(thread));
NULL_CHECK(java_thread, JVMTI_ERROR_THREAD_NOT_ALIVE);
JavaThread* java_thread = NULL;
ThreadsListHandle tlh(current_thread);
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, NULL);
if (err != JVMTI_ERROR_NONE) {
return err;
}
Thread::interrupt(java_thread);
@ -1094,16 +1106,28 @@ JvmtiEnv::GetThreadInfo(jthread thread, jvmtiThreadInfo* info_ptr) {
HandleMark hm;
JavaThread* current_thread = JavaThread::current();
ThreadsListHandle tlh(current_thread);
// if thread is NULL the current thread is used
oop thread_oop;
oop thread_oop = NULL;
if (thread == NULL) {
thread_oop = current_thread->threadObj();
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
return JVMTI_ERROR_INVALID_THREAD;
}
} else {
thread_oop = JNIHandles::resolve_external_guard(thread);
JavaThread* java_thread = NULL;
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
if (err != JVMTI_ERROR_NONE) {
// We got an error code so we don't have a JavaThread *, but
// only return an error from here if we didn't get a valid
// thread_oop.
if (thread_oop == NULL) {
return err;
}
// We have a valid thread_oop so we can return some thread info.
}
}
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass()))
return JVMTI_ERROR_INVALID_THREAD;
Handle thread_obj(current_thread, thread_oop);
Handle name;
@ -1272,17 +1296,31 @@ JvmtiEnv::GetCurrentContendedMonitor(JavaThread* java_thread, jobject* monitor_p
// arg - NULL is a valid value, must be checked
jvmtiError
JvmtiEnv::RunAgentThread(jthread thread, jvmtiStartFunction proc, const void* arg, jint priority) {
oop thread_oop = JNIHandles::resolve_external_guard(thread);
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
JavaThread* current_thread = JavaThread::current();
JavaThread* java_thread = NULL;
oop thread_oop = NULL;
ThreadsListHandle tlh(current_thread);
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
if (err != JVMTI_ERROR_NONE) {
// We got an error code so we don't have a JavaThread *, but
// only return an error from here if we didn't get a valid
// thread_oop.
if (thread_oop == NULL) {
return err;
}
// We have a valid thread_oop.
}
if (java_thread != NULL) {
// 'thread' refers to an existing JavaThread.
return JVMTI_ERROR_INVALID_THREAD;
}
if (priority < JVMTI_THREAD_MIN_PRIORITY || priority > JVMTI_THREAD_MAX_PRIORITY) {
return JVMTI_ERROR_INVALID_PRIORITY;
}
//Thread-self
JavaThread* current_thread = JavaThread::current();
Handle thread_hndl(current_thread, thread_oop);
{
MutexLocker mu(Threads_lock); // grab Threads_lock
@ -1292,7 +1330,9 @@ JvmtiEnv::RunAgentThread(jthread thread, jvmtiStartFunction proc, const void* ar
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of memory.
if (new_thread == NULL || new_thread->osthread() == NULL) {
if (new_thread) delete new_thread;
if (new_thread != NULL) {
new_thread->smr_delete();
}
return JVMTI_ERROR_OUT_OF_MEMORY;
}
@ -1394,36 +1434,53 @@ JvmtiEnv::GetThreadGroupChildren(jthreadGroup group, jint* thread_count_ptr, jth
int ngroups = 0;
int hidden_threads = 0;
ResourceMark rm;
HandleMark hm;
ResourceMark rm(current_thread);
HandleMark hm(current_thread);
Handle group_hdl(current_thread, group_obj);
{ MutexLocker mu(Threads_lock);
{ // Cannot allow thread or group counts to change.
MutexLocker mu(Threads_lock);
nthreads = java_lang_ThreadGroup::nthreads(group_hdl());
ngroups = java_lang_ThreadGroup::ngroups(group_hdl());
if (nthreads > 0) {
ThreadsListHandle tlh(current_thread);
objArrayOop threads = java_lang_ThreadGroup::threads(group_hdl());
assert(nthreads <= threads->length(), "too many threads");
thread_objs = NEW_RESOURCE_ARRAY(Handle,nthreads);
for (int i=0, j=0; i<nthreads; i++) {
oop thread_obj = threads->obj_at(i);
assert(thread_obj != NULL, "thread_obj is NULL");
JavaThread *javathread = java_lang_Thread::thread(thread_obj);
// Filter out hidden java threads.
if (javathread != NULL && javathread->is_hidden_from_external_view()) {
hidden_threads++;
continue;
JavaThread *java_thread = NULL;
jvmtiError err = JvmtiExport::cv_oop_to_JavaThread(tlh.list(), thread_obj, &java_thread);
if (err == JVMTI_ERROR_NONE) {
// Have a valid JavaThread*.
if (java_thread->is_hidden_from_external_view()) {
// Filter out hidden java threads.
hidden_threads++;
continue;
}
} else {
// We couldn't convert thread_obj into a JavaThread*.
if (err == JVMTI_ERROR_INVALID_THREAD) {
// The thread_obj does not refer to a java.lang.Thread object
// so skip it.
hidden_threads++;
continue;
}
// We have a valid thread_obj, but no JavaThread*; the caller
// can still have limited use for the thread_obj.
}
thread_objs[j++] = Handle(current_thread, thread_obj);
}
nthreads -= hidden_threads;
}
} // ThreadsListHandle is destroyed here.
if (ngroups > 0) {
objArrayOop groups = java_lang_ThreadGroup::groups(group_hdl());
assert(ngroups <= groups->length(), "too many threads");
assert(ngroups <= groups->length(), "too many groups");
group_objs = NEW_RESOURCE_ARRAY(Handle,ngroups);
for (int i=0; i<ngroups; i++) {
oop group_obj = groups->obj_at(i);
@ -1556,7 +1613,7 @@ JvmtiEnv::PopFrame(JavaThread* java_thread) {
}
// Check if java_thread is fully suspended
if (!is_thread_fully_suspended(java_thread, true /* wait for suspend completion */, &debug_bits)) {
if (!java_thread->is_thread_fully_suspended(true /* wait for suspend completion */, &debug_bits)) {
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
}
// Check to see if a PopFrame was already in progress
@ -1686,8 +1743,8 @@ JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) {
return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
if (!JvmtiEnv::is_thread_fully_suspended(java_thread, true, &debug_bits)) {
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
if (!java_thread->is_thread_fully_suspended(true, &debug_bits)) {
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
}
if (TraceJVMTICalls) {

View File

@ -44,6 +44,7 @@
#include "runtime/objectMonitor.inline.hpp"
#include "runtime/signature.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vframe_hp.hpp"
#include "runtime/vmThread.hpp"
@ -487,37 +488,6 @@ JvmtiEnvBase::set_event_callbacks(const jvmtiEventCallbacks* callbacks,
}
}
// Called from JVMTI entry points which perform stack walking. If the
// associated JavaThread is the current thread, then wait_for_suspend
// is not used. Otherwise, it determines if we should wait for the
// "other" thread to complete external suspension. (NOTE: in future
// releases the suspension mechanism should be reimplemented so this
// is not necessary.)
//
bool
JvmtiEnvBase::is_thread_fully_suspended(JavaThread* thr, bool wait_for_suspend, uint32_t *bits) {
// "other" threads require special handling
if (thr != JavaThread::current()) {
if (wait_for_suspend) {
// We are allowed to wait for the external suspend to complete
// so give the other thread a chance to get suspended.
if (!thr->wait_for_ext_suspend_completion(SuspendRetryCount,
SuspendRetryDelay, bits)) {
// didn't make it so let the caller know
return false;
}
}
// We aren't allowed to wait for the external suspend to complete
// so if the other thread isn't externally suspended we need to
// let the caller know.
else if (!thr->is_ext_suspend_completed_with_lock(bits)) {
return false;
}
}
return true;
}
// In the fullness of time, all users of the method should instead
// directly use allocate, besides being cleaner and faster, this will
@ -560,19 +530,6 @@ JvmtiEnvBase::new_jthreadGroupArray(int length, Handle *handles) {
return (jthreadGroup *) new_jobjectArray(length,handles);
}
JavaThread *
JvmtiEnvBase::get_JavaThread(jthread jni_thread) {
oop t = JNIHandles::resolve_external_guard(jni_thread);
if (t == NULL || !t->is_a(SystemDictionary::Thread_klass())) {
return NULL;
}
// The following returns NULL if the thread has not yet run or is in
// process of exiting
return java_lang_Thread::thread(t);
}
// return the vframe on the specified thread and depth, NULL if no such frame
vframe*
JvmtiEnvBase::vframeFor(JavaThread* java_thread, jint depth) {
@ -670,7 +627,7 @@ JvmtiEnvBase::get_current_contended_monitor(JavaThread *calling_thread, JavaThre
uint32_t debug_bits = 0;
#endif
assert((SafepointSynchronize::is_at_safepoint() ||
is_thread_fully_suspended(java_thread, false, &debug_bits)),
java_thread->is_thread_fully_suspended(false, &debug_bits)),
"at safepoint or target thread is suspended");
oop obj = NULL;
ObjectMonitor *mon = java_thread->current_waiting_monitor();
@ -709,7 +666,7 @@ JvmtiEnvBase::get_owned_monitors(JavaThread *calling_thread, JavaThread* java_th
uint32_t debug_bits = 0;
#endif
assert((SafepointSynchronize::is_at_safepoint() ||
is_thread_fully_suspended(java_thread, false, &debug_bits)),
java_thread->is_thread_fully_suspended(false, &debug_bits)),
"at safepoint or target thread is suspended");
if (java_thread->has_last_Java_frame()) {
@ -831,7 +788,7 @@ JvmtiEnvBase::get_stack_trace(JavaThread *java_thread,
uint32_t debug_bits = 0;
#endif
assert((SafepointSynchronize::is_at_safepoint() ||
is_thread_fully_suspended(java_thread, false, &debug_bits)),
java_thread->is_thread_fully_suspended(false, &debug_bits)),
"at safepoint or target thread is suspended");
int count = 0;
if (java_thread->has_last_Java_frame()) {
@ -914,7 +871,7 @@ JvmtiEnvBase::get_frame_location(JavaThread *java_thread, jint depth,
uint32_t debug_bits = 0;
#endif
assert((SafepointSynchronize::is_at_safepoint() ||
is_thread_fully_suspended(java_thread, false, &debug_bits)),
java_thread->is_thread_fully_suspended(false, &debug_bits)),
"at safepoint or target thread is suspended");
Thread* current_thread = Thread::current();
ResourceMark rm(current_thread);
@ -976,7 +933,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
// first derive the object's owner and entry_count (if any)
{
// Revoke any biases before querying the mark word
if (SafepointSynchronize::is_at_safepoint()) {
if (at_safepoint) {
BiasedLocking::revoke_at_safepoint(hobj);
} else {
BiasedLocking::revoke_and_rebias(hobj, false, calling_thread);
@ -1008,11 +965,11 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
}
if (owner != NULL) {
// Use current thread since function can be called from a
// JavaThread or the VMThread.
ThreadsListHandle tlh;
// This monitor is owned so we have to find the owning JavaThread.
// Since owning_thread_from_monitor_owner() grabs a lock, GC can
// move our object at this point. However, our owner value is safe
// since it is either the Lock word on a stack or a JavaThread *.
owning_thread = Threads::owning_thread_from_monitor_owner(owner, !at_safepoint);
owning_thread = Threads::owning_thread_from_monitor_owner(tlh.list(), owner);
// Cannot assume (owning_thread != NULL) here because this function
// may not have been called at a safepoint and the owning_thread
// might not be suspended.
@ -1021,7 +978,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
// or it has to be suspended. Any of these conditions will prevent both
// contending and waiting threads from modifying the state of
// the monitor.
if (!at_safepoint && !JvmtiEnv::is_thread_fully_suspended(owning_thread, true, &debug_bits)) {
if (!at_safepoint && !owning_thread->is_thread_fully_suspended(true, &debug_bits)) {
// Don't worry! This return of JVMTI_ERROR_THREAD_NOT_SUSPENDED
// will not make it back to the JVM/TI agent. The error code will
// get intercepted in JvmtiEnv::GetObjectMonitorUsage() which
@ -1033,7 +990,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
ret.owner = (jthread)jni_reference(calling_thread, th);
}
// implied else: no owner
}
} // ThreadsListHandle is destroyed here.
if (owning_thread != NULL) { // monitor is owned
// The recursions field of a monitor does not reflect recursions
@ -1084,13 +1041,15 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
if (ret.waiter_count > 0) {
// we have contending and/or waiting threads
HandleMark hm;
// Use current thread since function can be called from a
// JavaThread or the VMThread.
ThreadsListHandle tlh;
if (nWant > 0) {
// we have contending threads
ResourceMark rm;
// get_pending_threads returns only java thread so we do not need to
// check for non java threads.
GrowableArray<JavaThread*>* wantList = Threads::get_pending_threads(
nWant, (address)mon, !at_safepoint);
// check for non java threads.
GrowableArray<JavaThread*>* wantList = Threads::get_pending_threads(tlh.list(), nWant, (address)mon);
if (wantList->length() < nWant) {
// robustness: the pending list has gotten smaller
nWant = wantList->length();
@ -1101,7 +1060,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
// thread could potentially change the state of the monitor by
// entering it. The JVM/TI spec doesn't allow this.
if (owning_thread == NULL && !at_safepoint &
!JvmtiEnv::is_thread_fully_suspended(pending_thread, true, &debug_bits)) {
!pending_thread->is_thread_fully_suspended(true, &debug_bits)) {
if (ret.owner != NULL) {
destroy_jni_reference(calling_thread, ret.owner);
}
@ -1139,7 +1098,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
waiter = mon->next_waiter(waiter);
}
}
}
} // ThreadsListHandle is destroyed here.
// Adjust count. nWant and nWait count values may be less than original.
ret.waiter_count = nWant + nWait;
@ -1291,14 +1250,23 @@ VM_GetThreadListStackTraces::doit() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
ResourceMark rm;
ThreadsListHandle tlh;
for (int i = 0; i < _thread_count; ++i) {
jthread jt = _thread_list[i];
oop thread_oop = JNIHandles::resolve_external_guard(jt);
if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
set_result(JVMTI_ERROR_INVALID_THREAD);
return;
JavaThread* java_thread = NULL;
oop thread_oop = NULL;
jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), jt, &java_thread, &thread_oop);
if (err != JVMTI_ERROR_NONE) {
// We got an error code so we don't have a JavaThread *, but
// only return an error from here if we didn't get a valid
// thread_oop.
if (thread_oop == NULL) {
set_result(err);
return;
}
// We have a valid thread_oop.
}
fill_frames(jt, java_lang_Thread::thread(thread_oop), thread_oop);
fill_frames(jt, java_thread, thread_oop);
}
allocate_and_fill_stacks(_thread_count);
}
@ -1309,7 +1277,7 @@ VM_GetAllStackTraces::doit() {
ResourceMark rm;
_final_thread_count = 0;
for (JavaThread *jt = Threads::first(); jt != NULL; jt = jt->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
oop thread_oop = jt->threadObj();
if (thread_oop != NULL &&
!jt->is_exiting() &&
@ -1404,9 +1372,7 @@ JvmtiEnvBase::force_early_return(JavaThread* java_thread, jvalue value, TosState
}
// Check if java_thread is fully suspended
if (!is_thread_fully_suspended(java_thread,
true /* wait for suspend completion */,
&debug_bits)) {
if (!java_thread->is_thread_fully_suspended(true /* wait for suspend completion */, &debug_bits)) {
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
}
@ -1521,3 +1487,79 @@ JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobje
return JVMTI_ERROR_NONE;
}
void
VM_UpdateForPopTopFrame::doit() {
JavaThread* jt = _state->get_thread();
ThreadsListHandle tlh;
if (jt != NULL && tlh.includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
_state->update_for_pop_top_frame();
} else {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
}
}
void
VM_SetFramePop::doit() {
JavaThread* jt = _state->get_thread();
ThreadsListHandle tlh;
if (jt != NULL && tlh.includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
int frame_number = _state->count_frames() - _depth;
_state->env_thread_state((JvmtiEnvBase*)_env)->set_frame_pop(frame_number);
} else {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
}
}
void
VM_GetOwnedMonitorInfo::doit() {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
ThreadsListHandle tlh;
if (_java_thread != NULL && tlh.includes(_java_thread)
&& !_java_thread->is_exiting() && _java_thread->threadObj() != NULL) {
_result = ((JvmtiEnvBase *)_env)->get_owned_monitors(_calling_thread, _java_thread,
_owned_monitors_list);
}
}
void
VM_GetCurrentContendedMonitor::doit() {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
ThreadsListHandle tlh;
if (_java_thread != NULL && tlh.includes(_java_thread)
&& !_java_thread->is_exiting() && _java_thread->threadObj() != NULL) {
_result = ((JvmtiEnvBase *)_env)->get_current_contended_monitor(_calling_thread,_java_thread,_owned_monitor_ptr);
}
}
void
VM_GetStackTrace::doit() {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
ThreadsListHandle tlh;
if (_java_thread != NULL && tlh.includes(_java_thread)
&& !_java_thread->is_exiting() && _java_thread->threadObj() != NULL) {
_result = ((JvmtiEnvBase *)_env)->get_stack_trace(_java_thread,
_start_depth, _max_count,
_frame_buffer, _count_ptr);
}
}
void
VM_GetFrameCount::doit() {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
JavaThread* jt = _state->get_thread();
ThreadsListHandle tlh;
if (jt != NULL && tlh.includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
_result = ((JvmtiEnvBase*)_env)->get_frame_count(_state, _count_ptr);
}
}
void
VM_GetFrameLocation::doit() {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
ThreadsListHandle tlh;
if (_java_thread != NULL && tlh.includes(_java_thread)
&& !_java_thread->is_exiting() && _java_thread->threadObj() != NULL) {
_result = ((JvmtiEnvBase*)_env)->get_frame_location(_java_thread, _depth,
_method_ptr, _location_ptr);
}
}

View File

@ -280,9 +280,6 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
jthread * new_jthreadArray(int length, Handle *handles);
jthreadGroup * new_jthreadGroupArray(int length, Handle *handles);
// convert from JNIHandle to JavaThread *
JavaThread * get_JavaThread(jthread jni_thread);
// convert to a jni jclass from a non-null Klass*
jclass get_jni_class_non_null(Klass* k);
@ -297,11 +294,6 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
public:
// get a field descriptor for the specified class and field
static bool get_field_descriptor(Klass* k, jfieldID field, fieldDescriptor* fd);
// test for suspend - most (all?) of these should go away
static bool is_thread_fully_suspended(JavaThread *thread,
bool wait_for_suspend,
uint32_t *bits);
// JVMTI API helper functions which are called at safepoint or thread is suspended.
jvmtiError get_frame_count(JvmtiThreadState *state, jint *count_ptr);
@ -360,14 +352,7 @@ public:
}
VMOp_Type type() const { return VMOp_UpdateForPopTopFrame; }
jvmtiError result() { return _result; }
void doit() {
JavaThread* jt = _state->get_thread();
if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
_state->update_for_pop_top_frame();
} else {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
}
}
void doit();
};
// VM operation to set frame pop.
@ -390,15 +375,7 @@ public:
bool allow_nested_vm_operations() const { return true; }
VMOp_Type type() const { return VMOp_SetFramePop; }
jvmtiError result() { return _result; }
void doit() {
JavaThread* jt = _state->get_thread();
if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
int frame_number = _state->count_frames() - _depth;
_state->env_thread_state((JvmtiEnvBase*)_env)->set_frame_pop(frame_number);
} else {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
}
}
void doit();
};
@ -422,14 +399,7 @@ public:
_result = JVMTI_ERROR_NONE;
}
VMOp_Type type() const { return VMOp_GetOwnedMonitorInfo; }
void doit() {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
if (Threads::includes(_java_thread) && !_java_thread->is_exiting()
&& _java_thread->threadObj() != NULL) {
_result = ((JvmtiEnvBase *)_env)->get_owned_monitors(_calling_thread, _java_thread,
_owned_monitors_list);
}
}
void doit();
jvmtiError result() { return _result; }
};
@ -476,13 +446,7 @@ public:
}
VMOp_Type type() const { return VMOp_GetCurrentContendedMonitor; }
jvmtiError result() { return _result; }
void doit() {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
if (Threads::includes(_java_thread) && !_java_thread->is_exiting() &&
_java_thread->threadObj() != NULL) {
_result = ((JvmtiEnvBase *)_env)->get_current_contended_monitor(_calling_thread,_java_thread,_owned_monitor_ptr);
}
}
void doit();
};
// VM operation to get stack trace at safepoint.
@ -509,15 +473,7 @@ public:
}
jvmtiError result() { return _result; }
VMOp_Type type() const { return VMOp_GetStackTrace; }
void doit() {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
if (Threads::includes(_java_thread) && !_java_thread->is_exiting()
&& _java_thread->threadObj() != NULL) {
_result = ((JvmtiEnvBase *)_env)->get_stack_trace(_java_thread,
_start_depth, _max_count,
_frame_buffer, _count_ptr);
}
}
void doit();
};
// forward declaration
@ -607,13 +563,7 @@ public:
}
VMOp_Type type() const { return VMOp_GetFrameCount; }
jvmtiError result() { return _result; }
void doit() {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
JavaThread* jt = _state->get_thread();
if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
_result = ((JvmtiEnvBase*)_env)->get_frame_count(_state, _count_ptr);
}
}
void doit();
};
// VM operation to frame location at safepoint.
@ -637,14 +587,7 @@ public:
}
VMOp_Type type() const { return VMOp_GetFrameLocation; }
jvmtiError result() { return _result; }
void doit() {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
if (Threads::includes(_java_thread) && !_java_thread->is_exiting() &&
_java_thread->threadObj() != NULL) {
_result = ((JvmtiEnvBase*)_env)->get_frame_location(_java_thread, _depth,
_method_ptr, _location_ptr);
}
}
void doit();
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,6 +35,7 @@
#include "runtime/interfaceSupport.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/signature.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vm_operations.hpp"

View File

@ -33,7 +33,8 @@
#include "prims/jvmtiImpl.hpp"
#include "prims/jvmtiThreadState.inline.hpp"
#include "runtime/frame.hpp"
#include "runtime/thread.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vframe_hp.hpp"
#include "runtime/vmThread.hpp"
@ -580,13 +581,10 @@ JvmtiEventControllerPrivate::recompute_enabled() {
// filtered events and there weren't last time
if ( (any_env_thread_enabled & THREAD_FILTERED_EVENT_BITS) != 0 &&
(was_any_env_thread_enabled & THREAD_FILTERED_EVENT_BITS) == 0) {
{
MutexLocker mu(Threads_lock); //hold the Threads_lock for the iteration
for (JavaThread *tp = Threads::first(); tp != NULL; tp = tp->next()) {
// state_for_while_locked() makes tp->is_exiting() check
JvmtiThreadState::state_for_while_locked(tp); // create the thread state if missing
}
}// release Threads_lock
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *tp = jtiwh.next(); ) {
// state_for_while_locked() makes tp->is_exiting() check
JvmtiThreadState::state_for_while_locked(tp); // create the thread state if missing
}
}
// compute and set thread-filtered events

View File

@ -53,6 +53,7 @@
#include "runtime/objectMonitor.inline.hpp"
#include "runtime/os.inline.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframe.hpp"
#include "services/serviceUtil.hpp"
#include "utilities/macros.hpp"
@ -721,6 +722,108 @@ JvmtiExport::get_all_native_method_prefixes(int* count_ptr) {
}
}
// Convert an external thread reference to a JavaThread found on the
// specified ThreadsList. The ThreadsListHandle in the caller "protects"
// the returned JavaThread *.
//
// If thread_oop_p is not NULL, then the caller wants to use the oop
// after this call so the oop is returned. On success, *jt_pp is set
// to the converted JavaThread * and JVMTI_ERROR_NONE is returned.
// On error, returns various JVMTI_ERROR_* values.
//
jvmtiError
JvmtiExport::cv_external_thread_to_JavaThread(ThreadsList * t_list,
jthread thread,
JavaThread ** jt_pp,
oop * thread_oop_p) {
assert(t_list != NULL, "must have a ThreadsList");
assert(jt_pp != NULL, "must have a return JavaThread pointer");
// thread_oop_p is optional so no assert()
oop thread_oop = JNIHandles::resolve_external_guard(thread);
if (thread_oop == NULL) {
// NULL jthread, GC'ed jthread or a bad JNI handle.
return JVMTI_ERROR_INVALID_THREAD;
}
// Looks like an oop at this point.
if (!thread_oop->is_a(SystemDictionary::Thread_klass())) {
// The oop is not a java.lang.Thread.
return JVMTI_ERROR_INVALID_THREAD;
}
// Looks like a java.lang.Thread oop at this point.
if (thread_oop_p != NULL) {
// Return the oop to the caller; the caller may still want
// the oop even if this function returns an error.
*thread_oop_p = thread_oop;
}
JavaThread * java_thread = java_lang_Thread::thread(thread_oop);
if (java_thread == NULL) {
// The java.lang.Thread does not contain a JavaThread * so it has
// not yet run or it has died.
return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
// Looks like a live JavaThread at this point.
// We do not check the EnableThreadSMRExtraValidityChecks option
// for this includes() call because JVM/TI's spec is tighter.
if (!t_list->includes(java_thread)) {
// Not on the JavaThreads list so it is not alive.
return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
// Return a live JavaThread that is "protected" by the
// ThreadsListHandle in the caller.
*jt_pp = java_thread;
return JVMTI_ERROR_NONE;
}
// Convert an oop to a JavaThread found on the specified ThreadsList.
// The ThreadsListHandle in the caller "protects" the returned
// JavaThread *.
//
// On success, *jt_pp is set to the converted JavaThread * and
// JVMTI_ERROR_NONE is returned. On error, returns various
// JVMTI_ERROR_* values.
//
jvmtiError
JvmtiExport::cv_oop_to_JavaThread(ThreadsList * t_list, oop thread_oop,
JavaThread ** jt_pp) {
assert(t_list != NULL, "must have a ThreadsList");
assert(thread_oop != NULL, "must have an oop");
assert(jt_pp != NULL, "must have a return JavaThread pointer");
if (!thread_oop->is_a(SystemDictionary::Thread_klass())) {
// The oop is not a java.lang.Thread.
return JVMTI_ERROR_INVALID_THREAD;
}
// Looks like a java.lang.Thread oop at this point.
JavaThread * java_thread = java_lang_Thread::thread(thread_oop);
if (java_thread == NULL) {
// The java.lang.Thread does not contain a JavaThread * so it has
// not yet run or it has died.
return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
// Looks like a live JavaThread at this point.
// We do not check the EnableThreadSMRExtraValidityChecks option
// for this includes() call because JVM/TI's spec is tighter.
if (!t_list->includes(java_thread)) {
// Not on the JavaThreads list so it is not alive.
return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
// Return a live JavaThread that is "protected" by the
// ThreadsListHandle in the caller.
*jt_pp = java_thread;
return JVMTI_ERROR_NONE;
}
class JvmtiClassFileLoadHookPoster : public StackObj {
private:
Symbol* _h_name;
@ -2685,8 +2788,7 @@ void JvmtiVMObjectAllocEventCollector::oops_do_for_all_threads(OopClosure* f) {
return;
}
// Runs at safepoint. So no need to acquire Threads_lock.
for (JavaThread *jthr = Threads::first(); jthr != NULL; jthr = jthr->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jthr = jtiwh.next(); ) {
JvmtiThreadState *state = jthr->jvmti_thread_state();
if (state != NULL) {
JvmtiVMObjectAllocEventCollector *collector;

View File

@ -399,6 +399,14 @@ class JvmtiExport : public AllStatic {
// SetNativeMethodPrefix support
static char** get_all_native_method_prefixes(int* count_ptr) NOT_JVMTI_RETURN_(NULL);
// JavaThread lifecycle support:
static jvmtiError cv_external_thread_to_JavaThread(ThreadsList * t_list,
jthread thread,
JavaThread ** jt_pp,
oop * thread_oop_p);
static jvmtiError cv_oop_to_JavaThread(ThreadsList * t_list, oop thread_oop,
JavaThread ** jt_pp);
};
// Support class used by JvmtiDynamicCodeEventCollector and others. It

View File

@ -46,6 +46,7 @@
#include "runtime/serviceThread.hpp"
#include "runtime/signature.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vframe_hp.hpp"
#include "runtime/vm_operations.hpp"
@ -878,10 +879,9 @@ bool JvmtiSuspendControl::resume(JavaThread *java_thread) {
void JvmtiSuspendControl::print() {
#ifndef PRODUCT
MutexLocker mu(Threads_lock);
LogStreamHandle(Trace, jvmti) log_stream;
log_stream.print("Suspended Threads: [");
for (JavaThread *thread = Threads::first(); thread != NULL; thread = thread->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
#ifdef JVMTI_TRACE
const char *name = JvmtiTrace::safe_get_thread_name(thread);
#else

View File

@ -43,6 +43,7 @@
#include "oops/oop.inline.hpp"
#include "prims/jvmtiImpl.hpp"
#include "prims/jvmtiRedefineClasses.hpp"
#include "prims/jvmtiThreadState.inline.hpp"
#include "prims/resolvedMethodTable.hpp"
#include "prims/methodComparator.hpp"
#include "runtime/deoptimization.hpp"

View File

@ -45,6 +45,8 @@
#include "runtime/mutex.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/reflectionUtils.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
@ -3174,7 +3176,7 @@ inline bool VM_HeapWalkOperation::collect_stack_roots(JavaThread* java_thread,
// stack to find all references and local JNI refs.
inline bool VM_HeapWalkOperation::collect_stack_roots() {
JNILocalRootsClosure blk;
for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
oop threadObj = thread->threadObj();
if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) {
// Collect the simple root for this thread before we

View File

@ -336,34 +336,10 @@ class JvmtiThreadState : public CHeapObj<mtInternal> {
// already holding JvmtiThreadState_lock - retrieve or create JvmtiThreadState
// Can return NULL if JavaThread is exiting.
inline static JvmtiThreadState *state_for_while_locked(JavaThread *thread) {
assert(JvmtiThreadState_lock->is_locked(), "sanity check");
JvmtiThreadState *state = thread->jvmti_thread_state();
if (state == NULL) {
if (thread->is_exiting()) {
// don't add a JvmtiThreadState to a thread that is exiting
return NULL;
}
state = new JvmtiThreadState(thread);
}
return state;
}
static JvmtiThreadState *state_for_while_locked(JavaThread *thread);
// retrieve or create JvmtiThreadState
// Can return NULL if JavaThread is exiting.
inline static JvmtiThreadState *state_for(JavaThread *thread) {
JvmtiThreadState *state = thread->jvmti_thread_state();
if (state == NULL) {
MutexLocker mu(JvmtiThreadState_lock);
// check again with the lock held
state = state_for_while_locked(thread);
} else {
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
}
return state;
}
static JvmtiThreadState *state_for(JavaThread *thread);
// JVMTI ForceEarlyReturn support

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -68,4 +68,31 @@ void JvmtiThreadState::set_head_env_thread_state(JvmtiEnvThreadState* ets) {
_head_env_thread_state = ets;
}
inline JvmtiThreadState* JvmtiThreadState::state_for_while_locked(JavaThread *thread) {
assert(JvmtiThreadState_lock->is_locked(), "sanity check");
JvmtiThreadState *state = thread->jvmti_thread_state();
if (state == NULL) {
if (thread->is_exiting()) {
// don't add a JvmtiThreadState to a thread that is exiting
return NULL;
}
state = new JvmtiThreadState(thread);
}
return state;
}
inline JvmtiThreadState* JvmtiThreadState::state_for(JavaThread *thread) {
JvmtiThreadState *state = thread->jvmti_thread_state();
if (state == NULL) {
MutexLocker mu(JvmtiThreadState_lock);
// check again with the lock held
state = state_for_while_locked(thread);
} else {
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
}
return state;
}
#endif // SHARE_VM_PRIMS_JVMTITHREADSTATE_INLINE_HPP

View File

@ -39,6 +39,8 @@
#include "runtime/interfaceSupport.hpp"
#include "runtime/orderAccess.inline.hpp"
#include "runtime/reflection.hpp"
#include "runtime/thread.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vm_version.hpp"
#include "services/threadService.hpp"
#include "trace/tracing.hpp"
@ -937,8 +939,12 @@ UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread))
Parker* p = NULL;
if (jthread != NULL) {
oop java_thread = JNIHandles::resolve_non_null(jthread);
ThreadsListHandle tlh;
JavaThread* thr = NULL;
oop java_thread = NULL;
(void) tlh.cv_internal_thread_to_JavaThread(jthread, &thr, &java_thread);
if (java_thread != NULL) {
// This is a valid oop.
jlong lp = java_lang_Thread::park_event(java_thread);
if (lp != 0) {
// This cast is OK even though the jlong might have been read
@ -946,22 +952,19 @@ UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread))
// always be zero anyway and the value set is always the same
p = (Parker*)addr_from_java(lp);
} else {
// Grab lock if apparently null or using older version of library
MutexLocker mu(Threads_lock);
java_thread = JNIHandles::resolve_non_null(jthread);
if (java_thread != NULL) {
JavaThread* thr = java_lang_Thread::thread(java_thread);
if (thr != NULL) {
p = thr->parker();
if (p != NULL) { // Bind to Java thread for next time.
java_lang_Thread::set_park_event(java_thread, addr_to_java(p));
}
// Not cached in the java.lang.Thread oop yet (could be an
// older version of library).
if (thr != NULL) {
// The JavaThread is alive.
p = thr->parker();
if (p != NULL) {
// Cache the Parker in the java.lang.Thread oop for next time.
java_lang_Thread::set_park_event(java_thread, addr_to_java(p));
}
}
}
}
}
} // ThreadsListHandle is destroyed here.
if (p != NULL) {
HOTSPOT_THREAD_UNPARK((uintptr_t) p);

View File

@ -55,6 +55,7 @@
#include "runtime/os.hpp"
#include "runtime/sweeper.hpp"
#include "runtime/thread.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/align.hpp"
#include "utilities/debug.hpp"
@ -665,7 +666,7 @@ class VM_WhiteBoxDeoptimizeFrames : public VM_WhiteBoxOperation {
int result() const { return _result; }
void doit() {
for (JavaThread* t = Threads::first(); t != NULL; t = t->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
if (t->has_last_Java_frame()) {
for (StackFrameStream fst(t, UseBiasedLocking); !fst.is_done(); fst.next()) {
frame* f = fst.current();

View File

@ -497,7 +497,7 @@ bool Arguments::is_obsolete_flag(const char *flag_name, JDK_Version* version) {
SpecialFlag flag;
if (lookup_special_flag(flag_name, flag)) {
if (!flag.obsolete_in.is_undefined()) {
if (version_less_than(JDK_Version::current(), flag.expired_in)) {
if (!version_less_than(JDK_Version::current(), flag.obsolete_in)) {
*version = flag.obsolete_in;
return true;
}

View File

@ -32,6 +32,7 @@
#include "runtime/basicLock.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/task.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
@ -214,12 +215,8 @@ static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_
if (requesting_thread == biased_thread) {
thread_is_alive = true;
} else {
for (JavaThread* cur_thread = Threads::first(); cur_thread != NULL; cur_thread = cur_thread->next()) {
if (cur_thread == biased_thread) {
thread_is_alive = true;
break;
}
}
ThreadsListHandle tlh;
thread_is_alive = tlh.includes(biased_thread);
}
if (!thread_is_alive) {
if (allow_rebias) {
@ -390,72 +387,76 @@ static BiasedLocking::Condition bulk_revoke_or_rebias_at_safepoint(oop o,
Klass* k_o = o->klass();
Klass* klass = k_o;
if (bulk_rebias) {
// Use the epoch in the klass of the object to implicitly revoke
// all biases of objects of this data type and force them to be
// reacquired. However, we also need to walk the stacks of all
// threads and update the headers of lightweight locked objects
// with biases to have the current epoch.
{
JavaThreadIteratorWithHandle jtiwh;
// If the prototype header doesn't have the bias pattern, don't
// try to update the epoch -- assume another VM operation came in
// and reset the header to the unbiased state, which will
// implicitly cause all existing biases to be revoked
if (klass->prototype_header()->has_bias_pattern()) {
int prev_epoch = klass->prototype_header()->bias_epoch();
klass->set_prototype_header(klass->prototype_header()->incr_bias_epoch());
int cur_epoch = klass->prototype_header()->bias_epoch();
if (bulk_rebias) {
// Use the epoch in the klass of the object to implicitly revoke
// all biases of objects of this data type and force them to be
// reacquired. However, we also need to walk the stacks of all
// threads and update the headers of lightweight locked objects
// with biases to have the current epoch.
// Now walk all threads' stacks and adjust epochs of any biased
// and locked objects of this data type we encounter
for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) {
// If the prototype header doesn't have the bias pattern, don't
// try to update the epoch -- assume another VM operation came in
// and reset the header to the unbiased state, which will
// implicitly cause all existing biases to be revoked
if (klass->prototype_header()->has_bias_pattern()) {
int prev_epoch = klass->prototype_header()->bias_epoch();
klass->set_prototype_header(klass->prototype_header()->incr_bias_epoch());
int cur_epoch = klass->prototype_header()->bias_epoch();
// Now walk all threads' stacks and adjust epochs of any biased
// and locked objects of this data type we encounter
for (; JavaThread *thr = jtiwh.next(); ) {
GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(thr);
for (int i = 0; i < cached_monitor_info->length(); i++) {
MonitorInfo* mon_info = cached_monitor_info->at(i);
oop owner = mon_info->owner();
markOop mark = owner->mark();
if ((owner->klass() == k_o) && mark->has_bias_pattern()) {
// We might have encountered this object already in the case of recursive locking
assert(mark->bias_epoch() == prev_epoch || mark->bias_epoch() == cur_epoch, "error in bias epoch adjustment");
owner->set_mark(mark->set_bias_epoch(cur_epoch));
}
}
}
}
// At this point we're done. All we have to do is potentially
// adjust the header of the given object to revoke its bias.
revoke_bias(o, attempt_rebias_of_object && klass->prototype_header()->has_bias_pattern(), true, requesting_thread, NULL);
} else {
if (log_is_enabled(Info, biasedlocking)) {
ResourceMark rm;
log_info(biasedlocking)("* Disabling biased locking for type %s", klass->external_name());
}
// Disable biased locking for this data type. Not only will this
// cause future instances to not be biased, but existing biased
// instances will notice that this implicitly caused their biases
// to be revoked.
klass->set_prototype_header(markOopDesc::prototype());
// Now walk all threads' stacks and forcibly revoke the biases of
// any locked and biased objects of this data type we encounter.
for (; JavaThread *thr = jtiwh.next(); ) {
GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(thr);
for (int i = 0; i < cached_monitor_info->length(); i++) {
MonitorInfo* mon_info = cached_monitor_info->at(i);
oop owner = mon_info->owner();
markOop mark = owner->mark();
if ((owner->klass() == k_o) && mark->has_bias_pattern()) {
// We might have encountered this object already in the case of recursive locking
assert(mark->bias_epoch() == prev_epoch || mark->bias_epoch() == cur_epoch, "error in bias epoch adjustment");
owner->set_mark(mark->set_bias_epoch(cur_epoch));
revoke_bias(owner, false, true, requesting_thread, NULL);
}
}
}
// Must force the bias of the passed object to be forcibly revoked
// as well to ensure guarantees to callers
revoke_bias(o, false, true, requesting_thread, NULL);
}
// At this point we're done. All we have to do is potentially
// adjust the header of the given object to revoke its bias.
revoke_bias(o, attempt_rebias_of_object && klass->prototype_header()->has_bias_pattern(), true, requesting_thread, NULL);
} else {
if (log_is_enabled(Info, biasedlocking)) {
ResourceMark rm;
log_info(biasedlocking)("* Disabling biased locking for type %s", klass->external_name());
}
// Disable biased locking for this data type. Not only will this
// cause future instances to not be biased, but existing biased
// instances will notice that this implicitly caused their biases
// to be revoked.
klass->set_prototype_header(markOopDesc::prototype());
// Now walk all threads' stacks and forcibly revoke the biases of
// any locked and biased objects of this data type we encounter.
for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) {
GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(thr);
for (int i = 0; i < cached_monitor_info->length(); i++) {
MonitorInfo* mon_info = cached_monitor_info->at(i);
oop owner = mon_info->owner();
markOop mark = owner->mark();
if ((owner->klass() == k_o) && mark->has_bias_pattern()) {
revoke_bias(owner, false, true, requesting_thread, NULL);
}
}
}
// Must force the bias of the passed object to be forcibly revoked
// as well to ensure guarantees to callers
revoke_bias(o, false, true, requesting_thread, NULL);
}
} // ThreadsListHandle is destroyed here.
log_info(biasedlocking)("* Ending bulk revocation");
@ -481,7 +482,7 @@ static BiasedLocking::Condition bulk_revoke_or_rebias_at_safepoint(oop o,
static void clean_up_cached_monitor_info() {
// Walk the thread list clearing out the cached monitors
for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thr = jtiwh.next(); ) {
thr->set_cached_monitor_info(NULL);
}
}
@ -768,7 +769,7 @@ void BiasedLocking::preserve_marks() {
ResourceMark rm;
Thread* cur = Thread::current();
for (JavaThread* thread = Threads::first(); thread != NULL; thread = thread->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
if (thread->has_last_Java_frame()) {
RegisterMap rm(thread);
for (javaVFrame* vf = thread->last_java_vframe(&rm); vf != NULL; vf = vf->java_sender()) {

View File

@ -50,6 +50,7 @@
#include "runtime/signature.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vframeArray.hpp"
#include "runtime/vframe_hp.hpp"
@ -1297,7 +1298,7 @@ void Deoptimization::revoke_biases_of_monitors(CodeBlob* cb) {
assert(SafepointSynchronize::is_at_safepoint(), "must only be called from safepoint");
GrowableArray<Handle>* objects_to_revoke = new GrowableArray<Handle>();
for (JavaThread* jt = Threads::first(); jt != NULL ; jt = jt->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
if (jt->has_last_Java_frame()) {
StackFrameStream sfs(jt, true);
while (!sfs.is_done()) {

View File

@ -2484,6 +2484,12 @@ public:
LP64_ONLY(range(-1, max_intx/MICROUNITS)) \
NOT_LP64(range(-1, max_intx)) \
\
diagnostic(bool, EnableThreadSMRExtraValidityChecks, true, \
"Enable Thread SMR extra validity checks") \
\
diagnostic(bool, EnableThreadSMRStatistics, true, \
"Enable Thread SMR Statistics") \
\
product(bool, Inline, true, \
"Enable inlining") \
\

View File

@ -37,8 +37,6 @@
#include "utilities/formatBuffer.hpp"
#include "utilities/preserveException.hpp"
#define ALL_JAVA_THREADS(X) for (JavaThread* X = Threads::first(); X; X = X->next())
class HandshakeOperation: public StackObj {
public:
virtual void do_handshake(JavaThread* thread) = 0;
@ -94,8 +92,7 @@ bool VM_Handshake::handshake_has_timed_out(jlong start_time) {
void VM_Handshake::handle_timeout() {
LogStreamHandle(Warning, handshake) log_stream;
MutexLockerEx ml(Threads_lock, Mutex::_no_safepoint_check_flag);
ALL_JAVA_THREADS(thr) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thr = jtiwh.next(); ) {
if (thr->has_handshake()) {
log_stream.print("Thread " PTR_FORMAT " has not cleared its handshake op", p2i(thr));
thr->print_thread_state_on(&log_stream);
@ -117,8 +114,8 @@ class VM_HandshakeOneThread: public VM_Handshake {
TraceTime timer("Performing single-target operation (vmoperation doit)", TRACETIME_LOG(Info, handshake));
{
MutexLockerEx ml(Threads_lock, Mutex::_no_safepoint_check_flag);
if (Threads::includes(_target)) {
ThreadsListHandle tlh;
if (tlh.includes(_target)) {
set_handshake(_target);
_thread_alive = true;
}
@ -139,9 +136,24 @@ class VM_HandshakeOneThread: public VM_Handshake {
handle_timeout();
}
// We need to re-think this with SMR ThreadsList.
// There is an assumption in the code that the Threads_lock should be
// locked during certain phases.
MutexLockerEx ml(Threads_lock, Mutex::_no_safepoint_check_flag);
_target->handshake_process_by_vmthread();
ThreadsListHandle tlh;
if (tlh.includes(_target)) {
// Warning _target's address might be re-used.
// handshake_process_by_vmthread will check the semaphore for us again.
// Since we can't have more then one handshake in flight a reuse of
// _target's address should be okay since the new thread will not have
// an operation.
_target->handshake_process_by_vmthread();
} else {
// We can't warn here since the thread does cancel_handshake after
// it has been removed from the ThreadsList. So we should just keep
// looping here until while below returns false. If we have a bug,
// then we hang here, which is good for debugging.
}
} while (!poll_for_completed_thread());
}
@ -157,15 +169,15 @@ class VM_HandshakeAllThreads: public VM_Handshake {
void doit() {
TraceTime timer("Performing operation (vmoperation doit)", TRACETIME_LOG(Info, handshake));
int number_of_threads_issued = -1;
int number_of_threads_completed = 0;
{
MutexLockerEx ml(Threads_lock, Mutex::_no_safepoint_check_flag);
number_of_threads_issued = Threads::number_of_threads();
int number_of_threads_issued = 0;
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thr = jtiwh.next(); ) {
set_handshake(thr);
number_of_threads_issued++;
}
ALL_JAVA_THREADS(thr) {
set_handshake(thr);
}
if (number_of_threads_issued < 1) {
log_debug(handshake)("No threads to handshake.");
return;
}
if (!UseMembar) {
@ -174,6 +186,7 @@ class VM_HandshakeAllThreads: public VM_Handshake {
log_debug(handshake)("Threads signaled, begin processing blocked threads by VMThtread");
const jlong start_time = os::elapsed_counter();
int number_of_threads_completed = 0;
do {
// Check if handshake operation has timed out
if (handshake_has_timed_out(start_time)) {
@ -184,13 +197,19 @@ class VM_HandshakeAllThreads: public VM_Handshake {
// Observing a blocked state may of course be transient but the processing is guarded
// by semaphores and we optimistically begin by working on the blocked threads
{
// We need to re-think this with SMR ThreadsList.
// There is an assumption in the code that the Threads_lock should
// be locked during certain phases.
MutexLockerEx ml(Threads_lock, Mutex::_no_safepoint_check_flag);
ALL_JAVA_THREADS(thr) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thr = jtiwh.next(); ) {
// A new thread on the ThreadsList will not have an operation,
// hence it is skipped in handshake_process_by_vmthread.
thr->handshake_process_by_vmthread();
}
}
while (poll_for_completed_thread()) {
// Includes canceled operations by exiting threads.
number_of_threads_completed++;
}
@ -212,7 +231,7 @@ public:
_thread_cl(cl), _target_thread(target), _all_threads(false), _thread_alive(false) {}
void doit() {
ALL_JAVA_THREADS(t) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
if (_all_threads || t == _target_thread) {
if (t == _target_thread) {
_thread_alive = true;
@ -298,8 +317,8 @@ void HandshakeState::cancel_inner(JavaThread* thread) {
assert(thread->thread_state() == _thread_in_vm, "must be in vm state");
#ifdef DEBUG
{
MutexLockerEx ml(Threads_lock, Mutex::_no_safepoint_check_flag);
assert(!Threads::includes(thread), "java thread must not be on threads list");
ThreadsListHandle tlh;
assert(!tlh.includes(_target), "java thread must not be on threads list");
}
#endif
HandshakeOperation* op = _operation;

View File

@ -356,6 +356,8 @@ void print_statistics() {
if (PrintNMTStatistics) {
MemTracker::final_report(tty);
}
Threads::log_smr_statistics();
}
#else // PRODUCT MODE STATISTICS
@ -396,6 +398,8 @@ void print_statistics() {
if (LogTouchedMethods && PrintTouchedMethodsAtExit) {
Method::print_touched_methods(tty);
}
Threads::log_smr_statistics();
}
#endif

View File

@ -36,6 +36,7 @@
#include "runtime/os.hpp"
#include "runtime/task.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vmThread.hpp"
#ifndef PRODUCT
@ -51,8 +52,6 @@ class MemProfilerTask : public PeriodicTask {
void MemProfilerTask::task() {
// Get thread lock to provide mutual exclusion, and so we can iterate safely over the thread list.
MutexLocker mu(Threads_lock);
MemProfiler::do_trace();
}
@ -109,20 +108,21 @@ void MemProfiler::do_trace() {
// Calculate thread local sizes
size_t handles_memory_usage = VMThread::vm_thread()->handle_area()->size_in_bytes();
size_t resource_memory_usage = VMThread::vm_thread()->resource_area()->size_in_bytes();
JavaThread *cur = Threads::first();
while (cur != NULL) {
handles_memory_usage += cur->handle_area()->size_in_bytes();
resource_memory_usage += cur->resource_area()->size_in_bytes();
cur = cur->next();
}
{
JavaThreadIteratorWithHandle jtiwh;
for (; JavaThread *cur = jtiwh.next(); ) {
handles_memory_usage += cur->handle_area()->size_in_bytes();
resource_memory_usage += cur->resource_area()->size_in_bytes();
}
// Print trace line in log
fprintf(_log_fp, "%6.1f,%5d,%5d," UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) ",",
os::elapsedTime(),
Threads::number_of_threads(),
InstanceKlass::number_of_instance_classes(),
Universe::heap()->used() / K,
Universe::heap()->capacity() / K);
// Print trace line in log
fprintf(_log_fp, "%6.1f,%5d,%5d," UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) ",",
os::elapsedTime(),
jtiwh.length(),
InstanceKlass::number_of_instance_classes(),
Universe::heap()->used() / K,
Universe::heap()->capacity() / K);
}
fprintf(_log_fp, UINTX_FORMAT_W(6) ",", CodeCache::capacity() / K);

View File

@ -54,6 +54,7 @@
#include "runtime/os.inline.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vm_version.hpp"
#include "services/attachListener.hpp"
#include "services/mallocTracker.hpp"
@ -197,15 +198,7 @@ char* os::iso8601_time(char* buffer, size_t buffer_length, bool utc) {
}
OSReturn os::set_priority(Thread* thread, ThreadPriority p) {
#ifdef ASSERT
if (!(!thread->is_Java_thread() ||
Thread::current() == thread ||
Threads_lock->owned_by_self()
|| thread->is_Compiler_thread()
)) {
assert(false, "possibility of dangling Thread pointer");
}
#endif
debug_only(Thread::check_for_dangling_thread_pointer(thread);)
if (p >= MinPriority && p <= MaxPriority) {
int priority = java_to_os_priority[p];
@ -1100,7 +1093,7 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) {
}
#endif
for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
// Check for privilege stack
if (thread->privileged_stack_top() != NULL &&
thread->privileged_stack_top()->contains(addr)) {
@ -1126,7 +1119,6 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) {
if (verbose) thread->print_on(st);
return;
}
}
// Check if in metaspace and print types that have vptrs (only method now)
@ -1665,7 +1657,6 @@ void os::initialize_initial_active_processor_count() {
}
void os::SuspendedThreadTask::run() {
assert(Threads_lock->owned_by_self() || (_thread == VMThread::vm_thread()), "must have threads lock to call this");
internal_do_task();
_done = true;
}

View File

@ -59,6 +59,7 @@
#include "runtime/sweeper.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/timerTrace.hpp"
#include "services/runtimeService.hpp"
#include "trace/tracing.hpp"
@ -174,7 +175,7 @@ void SafepointSynchronize::begin() {
if (SafepointMechanism::uses_thread_local_poll()) {
// Arming the per thread poll while having _state != _not_synchronized means safepointing
log_trace(safepoint)("Setting thread local yield flag for threads");
for (JavaThread *cur = Threads::first(); cur != NULL; cur = cur->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur = jtiwh.next(); ) {
// Make sure the threads start polling, it is time to yield.
SafepointMechanism::arm_local_poll(cur); // release store, global state -> local state
}
@ -200,133 +201,137 @@ void SafepointSynchronize::begin() {
// Consider using active_processor_count() ... but that call is expensive.
int ncpus = os::processor_count() ;
unsigned int iterations = 0;
{
JavaThreadIteratorWithHandle jtiwh;
#ifdef ASSERT
for (JavaThread *cur = Threads::first(); cur != NULL; cur = cur->next()) {
assert(cur->safepoint_state()->is_running(), "Illegal initial state");
// Clear the visited flag to ensure that the critical counts are collected properly.
cur->set_visited_for_critical_count(false);
}
for (; JavaThread *cur = jtiwh.next(); ) {
assert(cur->safepoint_state()->is_running(), "Illegal initial state");
// Clear the visited flag to ensure that the critical counts are collected properly.
cur->set_visited_for_critical_count(false);
}
#endif // ASSERT
if (SafepointTimeout)
safepoint_limit_time = os::javaTimeNanos() + (jlong)SafepointTimeoutDelay * MICROUNITS;
if (SafepointTimeout)
safepoint_limit_time = os::javaTimeNanos() + (jlong)SafepointTimeoutDelay * MICROUNITS;
// Iterate through all threads until it have been determined how to stop them all at a safepoint
unsigned int iterations = 0;
int steps = 0 ;
while(still_running > 0) {
for (JavaThread *cur = Threads::first(); cur != NULL; cur = cur->next()) {
assert(!cur->is_ConcurrentGC_thread(), "A concurrent GC thread is unexpectly being suspended");
ThreadSafepointState *cur_state = cur->safepoint_state();
if (cur_state->is_running()) {
cur_state->examine_state_of_thread();
if (!cur_state->is_running()) {
still_running--;
// consider adjusting steps downward:
// steps = 0
// steps -= NNN
// steps >>= 1
// steps = MIN(steps, 2000-100)
// if (iterations != 0) steps -= NNN
}
LogTarget(Trace, safepoint) lt;
if (lt.is_enabled()) {
ResourceMark rm;
LogStream ls(lt);
cur_state->print_on(&ls);
// Iterate through all threads until it have been determined how to stop them all at a safepoint
int steps = 0 ;
while(still_running > 0) {
jtiwh.rewind();
for (; JavaThread *cur = jtiwh.next(); ) {
assert(!cur->is_ConcurrentGC_thread(), "A concurrent GC thread is unexpectly being suspended");
ThreadSafepointState *cur_state = cur->safepoint_state();
if (cur_state->is_running()) {
cur_state->examine_state_of_thread();
if (!cur_state->is_running()) {
still_running--;
// consider adjusting steps downward:
// steps = 0
// steps -= NNN
// steps >>= 1
// steps = MIN(steps, 2000-100)
// if (iterations != 0) steps -= NNN
}
LogTarget(Trace, safepoint) lt;
if (lt.is_enabled()) {
ResourceMark rm;
LogStream ls(lt);
cur_state->print_on(&ls);
}
}
}
}
if (iterations == 0) {
initial_running = still_running;
if (PrintSafepointStatistics) {
begin_statistics(nof_threads, still_running);
}
}
if (still_running > 0) {
// Check for if it takes to long
if (SafepointTimeout && safepoint_limit_time < os::javaTimeNanos()) {
print_safepoint_timeout(_spinning_timeout);
if (iterations == 0) {
initial_running = still_running;
if (PrintSafepointStatistics) {
begin_statistics(nof_threads, still_running);
}
}
// Spin to avoid context switching.
// There's a tension between allowing the mutators to run (and rendezvous)
// vs spinning. As the VM thread spins, wasting cycles, it consumes CPU that
// a mutator might otherwise use profitably to reach a safepoint. Excessive
// spinning by the VM thread on a saturated system can increase rendezvous latency.
// Blocking or yielding incur their own penalties in the form of context switching
// and the resultant loss of $ residency.
//
// Further complicating matters is that yield() does not work as naively expected
// on many platforms -- yield() does not guarantee that any other ready threads
// will run. As such we revert to naked_short_sleep() after some number of iterations.
// nakes_short_sleep() is implemented as a short unconditional sleep.
// Typical operating systems round a "short" sleep period up to 10 msecs, so sleeping
// can actually increase the time it takes the VM thread to detect that a system-wide
// stop-the-world safepoint has been reached. In a pathological scenario such as that
// described in CR6415670 the VMthread may sleep just before the mutator(s) become safe.
// In that case the mutators will be stalled waiting for the safepoint to complete and the
// the VMthread will be sleeping, waiting for the mutators to rendezvous. The VMthread
// will eventually wake up and detect that all mutators are safe, at which point
// we'll again make progress.
//
// Beware too that that the VMThread typically runs at elevated priority.
// Its default priority is higher than the default mutator priority.
// Obviously, this complicates spinning.
//
// Note too that on Windows XP SwitchThreadTo() has quite different behavior than Sleep(0).
// Sleep(0) will _not yield to lower priority threads, while SwitchThreadTo() will.
//
// See the comments in synchronizer.cpp for additional remarks on spinning.
//
// In the future we might:
// 1. Modify the safepoint scheme to avoid potentially unbounded spinning.
// This is tricky as the path used by a thread exiting the JVM (say on
// on JNI call-out) simply stores into its state field. The burden
// is placed on the VM thread, which must poll (spin).
// 2. Find something useful to do while spinning. If the safepoint is GC-related
// we might aggressively scan the stacks of threads that are already safe.
// 3. Use Solaris schedctl to examine the state of the still-running mutators.
// If all the mutators are ONPROC there's no reason to sleep or yield.
// 4. YieldTo() any still-running mutators that are ready but OFFPROC.
// 5. Check system saturation. If the system is not fully saturated then
// simply spin and avoid sleep/yield.
// 6. As still-running mutators rendezvous they could unpark the sleeping
// VMthread. This works well for still-running mutators that become
// safe. The VMthread must still poll for mutators that call-out.
// 7. Drive the policy on time-since-begin instead of iterations.
// 8. Consider making the spin duration a function of the # of CPUs:
// Spin = (((ncpus-1) * M) + K) + F(still_running)
// Alternately, instead of counting iterations of the outer loop
// we could count the # of threads visited in the inner loop, above.
// 9. On windows consider using the return value from SwitchThreadTo()
// to drive subsequent spin/SwitchThreadTo()/Sleep(N) decisions.
if (SafepointMechanism::uses_global_page_poll() && int(iterations) == DeferPollingPageLoopCount) {
guarantee (PageArmed == 0, "invariant") ;
PageArmed = 1 ;
os::make_polling_page_unreadable();
}
// Instead of (ncpus > 1) consider either (still_running < (ncpus + EPSILON)) or
// ((still_running + _waiting_to_block - TryingToBlock)) < ncpus)
++steps ;
if (ncpus > 1 && steps < SafepointSpinBeforeYield) {
SpinPause() ; // MP-Polite spin
} else
if (steps < DeferThrSuspendLoopCount) {
os::naked_yield() ;
} else {
os::naked_short_sleep(1);
if (still_running > 0) {
// Check for if it takes to long
if (SafepointTimeout && safepoint_limit_time < os::javaTimeNanos()) {
print_safepoint_timeout(_spinning_timeout);
}
iterations ++ ;
// Spin to avoid context switching.
// There's a tension between allowing the mutators to run (and rendezvous)
// vs spinning. As the VM thread spins, wasting cycles, it consumes CPU that
// a mutator might otherwise use profitably to reach a safepoint. Excessive
// spinning by the VM thread on a saturated system can increase rendezvous latency.
// Blocking or yielding incur their own penalties in the form of context switching
// and the resultant loss of $ residency.
//
// Further complicating matters is that yield() does not work as naively expected
// on many platforms -- yield() does not guarantee that any other ready threads
// will run. As such we revert to naked_short_sleep() after some number of iterations.
// nakes_short_sleep() is implemented as a short unconditional sleep.
// Typical operating systems round a "short" sleep period up to 10 msecs, so sleeping
// can actually increase the time it takes the VM thread to detect that a system-wide
// stop-the-world safepoint has been reached. In a pathological scenario such as that
// described in CR6415670 the VMthread may sleep just before the mutator(s) become safe.
// In that case the mutators will be stalled waiting for the safepoint to complete and the
// the VMthread will be sleeping, waiting for the mutators to rendezvous. The VMthread
// will eventually wake up and detect that all mutators are safe, at which point
// we'll again make progress.
//
// Beware too that that the VMThread typically runs at elevated priority.
// Its default priority is higher than the default mutator priority.
// Obviously, this complicates spinning.
//
// Note too that on Windows XP SwitchThreadTo() has quite different behavior than Sleep(0).
// Sleep(0) will _not yield to lower priority threads, while SwitchThreadTo() will.
//
// See the comments in synchronizer.cpp for additional remarks on spinning.
//
// In the future we might:
// 1. Modify the safepoint scheme to avoid potentially unbounded spinning.
// This is tricky as the path used by a thread exiting the JVM (say on
// on JNI call-out) simply stores into its state field. The burden
// is placed on the VM thread, which must poll (spin).
// 2. Find something useful to do while spinning. If the safepoint is GC-related
// we might aggressively scan the stacks of threads that are already safe.
// 3. Use Solaris schedctl to examine the state of the still-running mutators.
// If all the mutators are ONPROC there's no reason to sleep or yield.
// 4. YieldTo() any still-running mutators that are ready but OFFPROC.
// 5. Check system saturation. If the system is not fully saturated then
// simply spin and avoid sleep/yield.
// 6. As still-running mutators rendezvous they could unpark the sleeping
// VMthread. This works well for still-running mutators that become
// safe. The VMthread must still poll for mutators that call-out.
// 7. Drive the policy on time-since-begin instead of iterations.
// 8. Consider making the spin duration a function of the # of CPUs:
// Spin = (((ncpus-1) * M) + K) + F(still_running)
// Alternately, instead of counting iterations of the outer loop
// we could count the # of threads visited in the inner loop, above.
// 9. On windows consider using the return value from SwitchThreadTo()
// to drive subsequent spin/SwitchThreadTo()/Sleep(N) decisions.
if (SafepointMechanism::uses_global_page_poll() && int(iterations) == DeferPollingPageLoopCount) {
guarantee (PageArmed == 0, "invariant") ;
PageArmed = 1 ;
os::make_polling_page_unreadable();
}
// Instead of (ncpus > 1) consider either (still_running < (ncpus + EPSILON)) or
// ((still_running + _waiting_to_block - TryingToBlock)) < ncpus)
++steps ;
if (ncpus > 1 && steps < SafepointSpinBeforeYield) {
SpinPause() ; // MP-Polite spin
} else
if (steps < DeferThrSuspendLoopCount) {
os::naked_yield() ;
} else {
os::naked_short_sleep(1);
}
iterations ++ ;
}
assert(iterations < (uint)max_jint, "We have been iterating in the safepoint loop too long");
}
assert(iterations < (uint)max_jint, "We have been iterating in the safepoint loop too long");
}
} // ThreadsListHandle destroyed here.
assert(still_running == 0, "sanity check");
if (PrintSafepointStatistics) {
@ -341,7 +346,7 @@ void SafepointSynchronize::begin() {
sync_event.set_iterations(iterations);
sync_event.commit();
}
} //EventSafepointStateSync
} // EventSafepointStateSynchronization destroyed here.
// wait until all threads are stopped
{
@ -393,8 +398,8 @@ void SafepointSynchronize::begin() {
} // EventSafepointWaitBlocked
#ifdef ASSERT
for (JavaThread *cur = Threads::first(); cur != NULL; cur = cur->next()) {
// make sure all the threads were visited
// Make sure all the threads were visited.
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur = jtiwh.next(); ) {
assert(cur->was_visited_for_critical_count(), "missed a thread");
}
#endif // ASSERT
@ -452,81 +457,86 @@ void SafepointSynchronize::end() {
end_statistics(os::javaTimeNanos());
}
{
JavaThreadIteratorWithHandle jtiwh;
#ifdef ASSERT
// A pending_exception cannot be installed during a safepoint. The threads
// may install an async exception after they come back from a safepoint into
// pending_exception after they unblock. But that should happen later.
for (JavaThread *cur = Threads::first(); cur; cur = cur->next()) {
assert (!(cur->has_pending_exception() &&
cur->safepoint_state()->is_at_poll_safepoint()),
"safepoint installed a pending exception");
}
// A pending_exception cannot be installed during a safepoint. The threads
// may install an async exception after they come back from a safepoint into
// pending_exception after they unblock. But that should happen later.
for (; JavaThread *cur = jtiwh.next(); ) {
assert (!(cur->has_pending_exception() &&
cur->safepoint_state()->is_at_poll_safepoint()),
"safepoint installed a pending exception");
}
#endif // ASSERT
if (PageArmed) {
assert(SafepointMechanism::uses_global_page_poll(), "sanity");
// Make polling safepoint aware
os::make_polling_page_readable();
PageArmed = 0 ;
}
if (SafepointMechanism::uses_global_page_poll()) {
// Remove safepoint check from interpreter
Interpreter::ignore_safepoints();
}
{
MutexLocker mu(Safepoint_lock);
assert(_state == _synchronized, "must be synchronized before ending safepoint synchronization");
if (SafepointMechanism::uses_thread_local_poll()) {
_state = _not_synchronized;
OrderAccess::storestore(); // global state -> local state
for (JavaThread *current = Threads::first(); current; current = current->next()) {
ThreadSafepointState* cur_state = current->safepoint_state();
cur_state->restart(); // TSS _running
SafepointMechanism::disarm_local_poll(current); // release store, local state -> polling page
}
log_debug(safepoint)("Leaving safepoint region");
} else {
// Set to not synchronized, so the threads will not go into the signal_thread_blocked method
// when they get restarted.
_state = _not_synchronized;
OrderAccess::fence();
log_debug(safepoint)("Leaving safepoint region");
// Start suspended threads
for (JavaThread *current = Threads::first(); current; current = current->next()) {
// A problem occurring on Solaris is when attempting to restart threads
// the first #cpus - 1 go well, but then the VMThread is preempted when we get
// to the next one (since it has been running the longest). We then have
// to wait for a cpu to become available before we can continue restarting
// threads.
// FIXME: This causes the performance of the VM to degrade when active and with
// large numbers of threads. Apparently this is due to the synchronous nature
// of suspending threads.
//
// TODO-FIXME: the comments above are vestigial and no longer apply.
// Furthermore, using solaris' schedctl in this particular context confers no benefit
if (VMThreadHintNoPreempt) {
os::hint_no_preempt();
}
ThreadSafepointState* cur_state = current->safepoint_state();
assert(cur_state->type() != ThreadSafepointState::_running, "Thread not suspended at safepoint");
cur_state->restart();
assert(cur_state->is_running(), "safepoint state has not been reset");
}
if (PageArmed) {
assert(SafepointMechanism::uses_global_page_poll(), "sanity");
// Make polling safepoint aware
os::make_polling_page_readable();
PageArmed = 0 ;
}
RuntimeService::record_safepoint_end();
if (SafepointMechanism::uses_global_page_poll()) {
// Remove safepoint check from interpreter
Interpreter::ignore_safepoints();
}
// Release threads lock, so threads can be created/destroyed again. It will also starts all threads
// blocked in signal_thread_blocked
Threads_lock->unlock();
{
MutexLocker mu(Safepoint_lock);
assert(_state == _synchronized, "must be synchronized before ending safepoint synchronization");
if (SafepointMechanism::uses_thread_local_poll()) {
_state = _not_synchronized;
OrderAccess::storestore(); // global state -> local state
jtiwh.rewind();
for (; JavaThread *current = jtiwh.next(); ) {
ThreadSafepointState* cur_state = current->safepoint_state();
cur_state->restart(); // TSS _running
SafepointMechanism::disarm_local_poll(current); // release store, local state -> polling page
}
log_debug(safepoint)("Leaving safepoint region");
} else {
// Set to not synchronized, so the threads will not go into the signal_thread_blocked method
// when they get restarted.
_state = _not_synchronized;
OrderAccess::fence();
log_debug(safepoint)("Leaving safepoint region");
// Start suspended threads
jtiwh.rewind();
for (; JavaThread *current = jtiwh.next(); ) {
// A problem occurring on Solaris is when attempting to restart threads
// the first #cpus - 1 go well, but then the VMThread is preempted when we get
// to the next one (since it has been running the longest). We then have
// to wait for a cpu to become available before we can continue restarting
// threads.
// FIXME: This causes the performance of the VM to degrade when active and with
// large numbers of threads. Apparently this is due to the synchronous nature
// of suspending threads.
//
// TODO-FIXME: the comments above are vestigial and no longer apply.
// Furthermore, using solaris' schedctl in this particular context confers no benefit
if (VMThreadHintNoPreempt) {
os::hint_no_preempt();
}
ThreadSafepointState* cur_state = current->safepoint_state();
assert(cur_state->type() != ThreadSafepointState::_running, "Thread not suspended at safepoint");
cur_state->restart();
assert(cur_state->is_running(), "safepoint state has not been reset");
}
}
RuntimeService::record_safepoint_end();
// Release threads lock, so threads can be created/destroyed again.
// It will also release all threads blocked in signal_thread_blocked.
Threads_lock->unlock();
}
} // ThreadsListHandle destroyed here.
}
Universe::heap()->safepoint_synchronize_end();
// record this time so VMThread can keep track how much time has elapsed
// since last safepoint.
@ -915,12 +925,11 @@ void SafepointSynchronize::print_safepoint_timeout(SafepointTimeoutReason reason
tty->print_cr("# SafepointSynchronize::begin: Threads which did not reach the safepoint:");
ThreadSafepointState *cur_state;
ResourceMark rm;
for (JavaThread *cur_thread = Threads::first(); cur_thread;
cur_thread = cur_thread->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur_thread = jtiwh.next(); ) {
cur_state = cur_thread->safepoint_state();
if (cur_thread->thread_state() != _thread_blocked &&
((reason == _spinning_timeout && cur_state->is_running()) ||
((reason == _spinning_timeout && cur_state->is_running()) ||
(reason == _blocking_timeout && !cur_state->has_called_back()))) {
tty->print("# ");
cur_thread->print();
@ -1427,7 +1436,7 @@ void SafepointSynchronize::print_state() {
tty->print_cr("State: %s", (_state == _synchronizing) ? "synchronizing" :
"synchronized");
for (JavaThread *cur = Threads::first(); cur; cur = cur->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur = jtiwh.next(); ) {
cur->safepoint_state()->print();
}
}

View File

@ -894,7 +894,7 @@ ObjectSynchronizer::LockOwnership ObjectSynchronizer::query_lock_ownership
}
// FIXME: jvmti should call this
JavaThread* ObjectSynchronizer::get_lock_owner(Handle h_obj, bool doLock) {
JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_obj) {
if (UseBiasedLocking) {
if (SafepointSynchronize::is_at_safepoint()) {
BiasedLocking::revoke_at_safepoint(h_obj);
@ -923,7 +923,7 @@ JavaThread* ObjectSynchronizer::get_lock_owner(Handle h_obj, bool doLock) {
if (owner != NULL) {
// owning_thread_from_monitor_owner() may also return NULL here
return Threads::owning_thread_from_monitor_owner(owner, doLock);
return Threads::owning_thread_from_monitor_owner(t_list, owner);
}
// Unlocked case, header in place

View File

@ -32,6 +32,7 @@
#include "runtime/perfData.hpp"
class ObjectMonitor;
class ThreadsList;
struct DeflateMonitorCounters {
int nInuse; // currently associated with objects
@ -125,7 +126,7 @@ class ObjectSynchronizer : AllStatic {
static bool current_thread_holds_lock(JavaThread* thread, Handle h_obj);
static LockOwnership query_lock_ownership(JavaThread * self, Handle h_obj);
static JavaThread* get_lock_owner(Handle h_obj, bool doLock);
static JavaThread* get_lock_owner(ThreadsList * t_list, Handle h_obj);
// JNI detach support
static void release_monitors_owned_by_thread(TRAPS);

File diff suppressed because it is too large Load Diff

View File

@ -57,6 +57,8 @@
#endif
class ThreadSafepointState;
class ThreadsList;
class NestedThreadsList;
class JvmtiThreadState;
class JvmtiGetLoadedClassesClosure;
@ -101,6 +103,7 @@ class WorkerThread;
// - WatcherThread
class Thread: public ThreadShadow {
friend class Threads;
friend class VMStructs;
friend class JVMCIVMStructs;
private:
@ -118,6 +121,47 @@ class Thread: public ThreadShadow {
protected:
// Support for forcing alignment of thread objects for biased locking
void* _real_malloc_address;
// JavaThread lifecycle support:
friend class ScanHazardPtrGatherProtectedThreadsClosure;
friend class ScanHazardPtrGatherThreadsListClosure;
friend class ScanHazardPtrPrintMatchingThreadsClosure;
friend class ThreadsListHandle;
friend class ThreadsListSetter;
ThreadsList* volatile _threads_hazard_ptr;
ThreadsList* cmpxchg_threads_hazard_ptr(ThreadsList* exchange_value, ThreadsList* compare_value);
ThreadsList* get_threads_hazard_ptr();
void set_threads_hazard_ptr(ThreadsList* new_list);
static bool is_hazard_ptr_tagged(ThreadsList* list) {
return (intptr_t(list) & intptr_t(1)) == intptr_t(1);
}
static ThreadsList* tag_hazard_ptr(ThreadsList* list) {
return (ThreadsList*)(intptr_t(list) | intptr_t(1));
}
static ThreadsList* untag_hazard_ptr(ThreadsList* list) {
return (ThreadsList*)(intptr_t(list) & ~intptr_t(1));
}
NestedThreadsList* _nested_threads_hazard_ptr;
NestedThreadsList* get_nested_threads_hazard_ptr() {
return _nested_threads_hazard_ptr;
}
void set_nested_threads_hazard_ptr(NestedThreadsList* value) {
assert(Threads_lock->owned_by_self(),
"must own Threads_lock for _nested_threads_hazard_ptr to be valid.");
_nested_threads_hazard_ptr = value;
}
// This field is enabled via -XX:+EnableThreadSMRStatistics:
uint _nested_threads_hazard_ptr_cnt;
void dec_nested_threads_hazard_ptr_cnt() {
assert(_nested_threads_hazard_ptr_cnt != 0, "mismatched {dec,inc}_nested_threads_hazard_ptr_cnt()");
_nested_threads_hazard_ptr_cnt--;
}
void inc_nested_threads_hazard_ptr_cnt() {
_nested_threads_hazard_ptr_cnt++;
}
uint nested_threads_hazard_ptr_cnt() {
return _nested_threads_hazard_ptr_cnt;
}
public:
void* operator new(size_t size) throw() { return allocate(size, true); }
void* operator new(size_t size, const std::nothrow_t& nothrow_constant) throw() {
@ -359,6 +403,9 @@ class Thread: public ThreadShadow {
static inline Thread* current_or_null_safe();
// Common thread operations
#ifdef ASSERT
static void check_for_dangling_thread_pointer(Thread *thread);
#endif
static void set_priority(Thread* thread, ThreadPriority priority);
static ThreadPriority get_priority(const Thread* const thread);
static void start(Thread* thread);
@ -576,6 +623,7 @@ protected:
// Printing
virtual void print_on(outputStream* st) const;
virtual void print_nested_threads_hazard_ptrs_on(outputStream* st) const;
void print() const { print_on(tty); }
virtual void print_on_error(outputStream* st, char* buf, int buflen) const;
void print_value_on(outputStream* st) const;
@ -798,6 +846,7 @@ class JavaThread: public Thread {
friend class WhiteBox;
private:
JavaThread* _next; // The next thread in the Threads list
bool _on_thread_list; // Is set when this JavaThread is added to the Threads list
oop _threadObj; // The Java level thread object
#ifdef ASSERT
@ -1125,15 +1174,23 @@ class JavaThread: public Thread {
void set_safepoint_state(ThreadSafepointState *state) { _safepoint_state = state; }
bool is_at_poll_safepoint() { return _safepoint_state->is_at_poll_safepoint(); }
// JavaThread termination and lifecycle support:
void smr_delete();
bool on_thread_list() const { return _on_thread_list; }
void set_on_thread_list() { _on_thread_list = true; }
// thread has called JavaThread::exit() or is terminated
bool is_exiting() { return _terminated == _thread_exiting || is_terminated(); }
bool is_exiting() const;
// thread is terminated (no longer on the threads list); we compare
// against the two non-terminated values so that a freed JavaThread
// will also be considered terminated.
bool is_terminated() { return _terminated != _not_terminated && _terminated != _thread_exiting; }
void set_terminated(TerminatedTypes t) { _terminated = t; }
bool check_is_terminated(TerminatedTypes l_terminated) const {
return l_terminated != _not_terminated && l_terminated != _thread_exiting;
}
bool is_terminated() const;
void set_terminated(TerminatedTypes t);
// special for Threads::remove() which is static:
void set_terminated_value() { _terminated = _thread_terminated; }
void set_terminated_value();
void block_if_vm_exited();
bool doing_unsafe_access() { return _doing_unsafe_access; }
@ -1220,6 +1277,9 @@ class JavaThread: public Thread {
// via the appropriate -XX options.
bool wait_for_ext_suspend_completion(int count, int delay, uint32_t *bits);
// test for suspend - most (all?) of these should go away
bool is_thread_fully_suspended(bool wait_for_suspend, uint32_t *bits);
inline void set_external_suspend();
inline void clear_external_suspend();
@ -2066,28 +2126,84 @@ inline CompilerThread* CompilerThread::current() {
class Threads: AllStatic {
friend class VMStructs;
private:
static JavaThread* _thread_list;
static int _number_of_threads;
static int _number_of_non_daemon_threads;
static int _return_code;
static int _thread_claim_parity;
// Safe Memory Reclamation (SMR) support:
static Monitor* _smr_delete_lock;
// The '_cnt', '_max' and '_times" fields are enabled via
// -XX:+EnableThreadSMRStatistics (see thread.cpp for a
// description about each field):
static uint _smr_delete_lock_wait_cnt;
static uint _smr_delete_lock_wait_max;
static volatile uint _smr_delete_notify;
static volatile uint _smr_deleted_thread_cnt;
static volatile uint _smr_deleted_thread_time_max;
static volatile uint _smr_deleted_thread_times;
static ThreadsList* volatile _smr_java_thread_list;
static ThreadsList* get_smr_java_thread_list();
static ThreadsList* xchg_smr_java_thread_list(ThreadsList* new_list);
static uint64_t _smr_java_thread_list_alloc_cnt;
static uint64_t _smr_java_thread_list_free_cnt;
static uint _smr_java_thread_list_max;
static uint _smr_nested_thread_list_max;
static volatile uint _smr_tlh_cnt;
static volatile uint _smr_tlh_time_max;
static volatile uint _smr_tlh_times;
static ThreadsList* _smr_to_delete_list;
static uint _smr_to_delete_list_cnt;
static uint _smr_to_delete_list_max;
static JavaThread* _thread_list;
static int _number_of_threads;
static int _number_of_non_daemon_threads;
static int _return_code;
static int _thread_claim_parity;
#ifdef ASSERT
static bool _vm_complete;
static bool _vm_complete;
#endif
static void initialize_java_lang_classes(JavaThread* main_thread, TRAPS);
static void initialize_jsr292_core_classes(TRAPS);
static void smr_free_list(ThreadsList* threads);
public:
// Thread management
// force_daemon is a concession to JNI, where we may need to add a
// thread to the thread list before allocating its thread object
static void add(JavaThread* p, bool force_daemon = false);
static void remove(JavaThread* p);
static bool includes(JavaThread* p);
static JavaThread* first() { return _thread_list; }
static void threads_do(ThreadClosure* tc);
static void possibly_parallel_threads_do(bool is_par, ThreadClosure* tc);
// SMR support:
static ThreadsList *acquire_stable_list(Thread *self, bool is_ThreadsListSetter);
static ThreadsList *acquire_stable_list_fast_path(Thread *self);
static ThreadsList *acquire_stable_list_nested_path(Thread *self);
static void release_stable_list(Thread *self);
static void release_stable_list_fast_path(Thread *self);
static void release_stable_list_nested_path(Thread *self);
static void release_stable_list_wake_up(char *log_str);
static bool is_a_protected_JavaThread(JavaThread *thread);
static bool is_a_protected_JavaThread_with_lock(JavaThread *thread) {
MutexLockerEx ml(Threads_lock->owned_by_self() ? NULL : Threads_lock);
return is_a_protected_JavaThread(thread);
}
static void smr_delete(JavaThread *thread);
// The coordination between Threads::release_stable_list() and
// Threads::smr_delete() uses the smr_delete_lock in order to
// reduce the traffic on the Threads_lock.
static Monitor* smr_delete_lock() { return _smr_delete_lock; }
// The smr_delete_notify flag is used for proper double-check
// locking in order to reduce the traffic on the smr_delete_lock.
static bool smr_delete_notify();
static void set_smr_delete_notify();
static void clear_smr_delete_notify();
static void inc_smr_deleted_thread_cnt();
static void update_smr_deleted_thread_time_max(uint new_value);
static void add_smr_deleted_thread_times(uint add_value);
static void inc_smr_tlh_cnt();
static void update_smr_tlh_time_max(uint new_value);
static void add_smr_tlh_times(uint add_value);
// Initializes the vm and creates the vm thread
static jint create_vm(JavaVMInitArgs* args, bool* canTryAgain);
static void convert_vm_init_libraries_to_agents();
@ -2148,7 +2264,10 @@ class Threads: AllStatic {
// Verification
static void verify();
static void log_smr_statistics();
static void print_on(outputStream* st, bool print_stacks, bool internal_format, bool print_concurrent_locks);
static void print_smr_info_on(outputStream* st);
static void print_smr_info_elements_on(outputStream* st, ThreadsList* t_list);
static void print(bool print_stacks, bool internal_format) {
// this function is only used by debug.cpp
print_on(tty, print_stacks, internal_format, false /* no concurrent lock printed */);
@ -2158,17 +2277,13 @@ class Threads: AllStatic {
int buflen, bool* found_current);
static void print_threads_compiling(outputStream* st, char* buf, int buflen);
// Get Java threads that are waiting to enter a monitor. If doLock
// is true, then Threads_lock is grabbed as needed. Otherwise, the
// VM needs to be at a safepoint.
static GrowableArray<JavaThread*>* get_pending_threads(int count,
address monitor, bool doLock);
// Get Java threads that are waiting to enter a monitor.
static GrowableArray<JavaThread*>* get_pending_threads(ThreadsList * t_list,
int count, address monitor);
// Get owning Java thread from the monitor's owner field. If doLock
// is true, then Threads_lock is grabbed as needed. Otherwise, the
// VM needs to be at a safepoint.
static JavaThread *owning_thread_from_monitor_owner(address owner,
bool doLock);
// Get owning Java thread from the monitor's owner field.
static JavaThread *owning_thread_from_monitor_owner(ThreadsList * t_list,
address owner);
// Number of threads on the active threads list
static int number_of_threads() { return _number_of_threads; }
@ -2177,9 +2292,6 @@ class Threads: AllStatic {
// Deoptimizes all frames tied to marked nmethods
static void deoptimized_wrt_marked_nmethods();
static JavaThread* find_java_thread_from_java_tid(jlong java_tid);
};

View File

@ -25,13 +25,10 @@
#ifndef SHARE_VM_RUNTIME_THREAD_INLINE_HPP
#define SHARE_VM_RUNTIME_THREAD_INLINE_HPP
#define SHARE_VM_RUNTIME_THREAD_INLINE_HPP_SCOPE
#include "runtime/atomic.hpp"
#include "runtime/os.inline.hpp"
#include "runtime/thread.hpp"
#undef SHARE_VM_RUNTIME_THREAD_INLINE_HPP_SCOPE
#include "runtime/threadSMR.hpp"
inline void Thread::set_suspend_flag(SuspendFlags f) {
assert(sizeof(jint) == sizeof(_suspend_flags), "size mismatch");
@ -89,6 +86,18 @@ inline jlong Thread::cooked_allocated_bytes() {
return allocated_bytes;
}
inline ThreadsList* Thread::cmpxchg_threads_hazard_ptr(ThreadsList* exchange_value, ThreadsList* compare_value) {
return (ThreadsList*)Atomic::cmpxchg(exchange_value, &_threads_hazard_ptr, compare_value);
}
inline ThreadsList* Thread::get_threads_hazard_ptr() {
return (ThreadsList*)OrderAccess::load_acquire(&_threads_hazard_ptr);
}
inline void Thread::set_threads_hazard_ptr(ThreadsList* new_list) {
OrderAccess::release_store_fence(&_threads_hazard_ptr, new_list);
}
inline void JavaThread::set_ext_suspended() {
set_suspend_flag (_ext_suspended);
}
@ -176,4 +185,83 @@ inline volatile void* JavaThread::get_polling_page() {
return OrderAccess::load_acquire(polling_page_addr());
}
inline bool JavaThread::is_exiting() const {
// Use load-acquire so that setting of _terminated by
// JavaThread::exit() is seen more quickly.
TerminatedTypes l_terminated = (TerminatedTypes)
OrderAccess::load_acquire((volatile jint *) &_terminated);
return l_terminated == _thread_exiting || check_is_terminated(l_terminated);
}
inline bool JavaThread::is_terminated() const {
// Use load-acquire so that setting of _terminated by
// JavaThread::exit() is seen more quickly.
TerminatedTypes l_terminated = (TerminatedTypes)
OrderAccess::load_acquire((volatile jint *) &_terminated);
return check_is_terminated(l_terminated);
}
inline void JavaThread::set_terminated(TerminatedTypes t) {
// use release-store so the setting of _terminated is seen more quickly
OrderAccess::release_store((volatile jint *) &_terminated, (jint) t);
}
// special for Threads::remove() which is static:
inline void JavaThread::set_terminated_value() {
// use release-store so the setting of _terminated is seen more quickly
OrderAccess::release_store((volatile jint *) &_terminated, (jint) _thread_terminated);
}
inline ThreadsList* Threads::get_smr_java_thread_list() {
return (ThreadsList*)OrderAccess::load_acquire(&_smr_java_thread_list);
}
inline ThreadsList* Threads::xchg_smr_java_thread_list(ThreadsList* new_list) {
return (ThreadsList*)Atomic::xchg(new_list, &_smr_java_thread_list);
}
inline void Threads::inc_smr_deleted_thread_cnt() {
Atomic::inc(&_smr_deleted_thread_cnt);
}
inline void Threads::update_smr_deleted_thread_time_max(uint new_value) {
while (true) {
uint cur_value = _smr_deleted_thread_time_max;
if (new_value <= cur_value) {
// No need to update max value so we're done.
break;
}
if (Atomic::cmpxchg(new_value, &_smr_deleted_thread_time_max, cur_value) == cur_value) {
// Updated max value so we're done. Otherwise try it all again.
break;
}
}
}
inline void Threads::add_smr_deleted_thread_times(uint add_value) {
Atomic::add(add_value, &_smr_deleted_thread_times);
}
inline void Threads::inc_smr_tlh_cnt() {
Atomic::inc(&_smr_tlh_cnt);
}
inline void Threads::update_smr_tlh_time_max(uint new_value) {
while (true) {
uint cur_value = _smr_tlh_time_max;
if (new_value <= cur_value) {
// No need to update max value so we're done.
break;
}
if (Atomic::cmpxchg(new_value, &_smr_tlh_time_max, cur_value) == cur_value) {
// Updated max value so we're done. Otherwise try it all again.
break;
}
}
}
inline void Threads::add_smr_tlh_times(uint add_value) {
Atomic::add(add_value, &_smr_tlh_times);
}
#endif // SHARE_VM_RUNTIME_THREAD_INLINE_HPP

View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "memory/allocation.inline.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "services/threadService.hpp"
// 'entries + 1' so we always have at least one entry.
ThreadsList::ThreadsList(int entries) : _length(entries), _threads(NEW_C_HEAP_ARRAY(JavaThread*, entries + 1, mtThread)), _next_list(NULL) {
*(JavaThread**)(_threads + entries) = NULL; // Make sure the extra entry is NULL.
}
ThreadsList::~ThreadsList() {
FREE_C_HEAP_ARRAY(JavaThread*, _threads);
}
ThreadsListSetter::~ThreadsListSetter() {
if (_target_needs_release) {
// The hazard ptr in the target needs to be released.
Threads::release_stable_list(_target);
}
}
void ThreadsListSetter::set() {
assert(_target->get_threads_hazard_ptr() == NULL, "hazard ptr should not already be set");
(void) Threads::acquire_stable_list(_target, /* is_ThreadsListSetter */ true);
_target_needs_release = true;
}
ThreadsListHandle::ThreadsListHandle(Thread *self) : _list(Threads::acquire_stable_list(self, /* is_ThreadsListSetter */ false)), _self(self) {
assert(self == Thread::current(), "sanity check");
if (EnableThreadSMRStatistics) {
_timer.start();
}
}
ThreadsListHandle::~ThreadsListHandle() {
Threads::release_stable_list(_self);
if (EnableThreadSMRStatistics) {
_timer.stop();
uint millis = (uint)_timer.milliseconds();
Threads::inc_smr_tlh_cnt();
Threads::add_smr_tlh_times(millis);
Threads::update_smr_tlh_time_max(millis);
}
}
// Convert an internal thread reference to a JavaThread found on the
// associated ThreadsList. This ThreadsListHandle "protects" the
// returned JavaThread *.
//
// If thread_oop_p is not NULL, then the caller wants to use the oop
// after this call so the oop is returned. On success, *jt_pp is set
// to the converted JavaThread * and true is returned. On error,
// returns false.
//
bool ThreadsListHandle::cv_internal_thread_to_JavaThread(jobject jthread,
JavaThread ** jt_pp,
oop * thread_oop_p) {
assert(this->list() != NULL, "must have a ThreadsList");
assert(jt_pp != NULL, "must have a return JavaThread pointer");
// thread_oop_p is optional so no assert()
// The JVM_* interfaces don't allow a NULL thread parameter; JVM/TI
// allows a NULL thread parameter to signify "current thread" which
// allows us to avoid calling cv_external_thread_to_JavaThread().
// The JVM_* interfaces have no such leeway.
oop thread_oop = JNIHandles::resolve_non_null(jthread);
// Looks like an oop at this point.
if (thread_oop_p != NULL) {
// Return the oop to the caller; the caller may still want
// the oop even if this function returns false.
*thread_oop_p = thread_oop;
}
JavaThread *java_thread = java_lang_Thread::thread(thread_oop);
if (java_thread == NULL) {
// The java.lang.Thread does not contain a JavaThread * so it has
// not yet run or it has died.
return false;
}
// Looks like a live JavaThread at this point.
if (java_thread != JavaThread::current()) {
// jthread is not for the current JavaThread so have to verify
// the JavaThread * against the ThreadsList.
if (EnableThreadSMRExtraValidityChecks && !includes(java_thread)) {
// Not on the JavaThreads list so it is not alive.
return false;
}
}
// Return a live JavaThread that is "protected" by the
// ThreadsListHandle in the caller.
*jt_pp = java_thread;
return true;
}

View File

@ -0,0 +1,257 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_RUNTIME_THREADSMR_HPP
#define SHARE_VM_RUNTIME_THREADSMR_HPP
#include "memory/allocation.hpp"
#include "runtime/timer.hpp"
// Thread Safe Memory Reclamation (Thread-SMR) support.
//
// ThreadsListHandles are used to safely perform operations on one or more
// threads without the risk of the thread or threads exiting during the
// operation. It is no longer necessary to hold the Threads_lock to safely
// perform an operation on a target thread.
//
// There are several different ways to refer to java.lang.Thread objects
// so we have a few ways to get a protected JavaThread *:
//
// JNI jobject example:
// jobject jthread = ...;
// :
// ThreadsListHandle tlh;
// JavaThread* jt = NULL;
// bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &jt, NULL);
// if (is_alive) {
// : // do stuff with 'jt'...
// }
//
// JVM/TI jthread example:
// jthread thread = ...;
// :
// JavaThread* jt = NULL;
// ThreadsListHandle tlh;
// jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &jt, NULL);
// if (err != JVMTI_ERROR_NONE) {
// return err;
// }
// : // do stuff with 'jt'...
//
// JVM/TI oop example (this one should be very rare):
// oop thread_obj = ...;
// :
// JavaThread *jt = NULL;
// ThreadsListHandle tlh;
// jvmtiError err = JvmtiExport::cv_oop_to_JavaThread(tlh.list(), thread_obj, &jt);
// if (err != JVMTI_ERROR_NONE) {
// return err;
// }
// : // do stuff with 'jt'...
//
// A JavaThread * that is included in the ThreadsList that is held by
// a ThreadsListHandle is protected as long as the ThreadsListHandle
// remains in scope. The target JavaThread * may have logically exited,
// but that target JavaThread * will not be deleted until it is no
// longer protected by a ThreadsListHandle.
// A fast list of JavaThreads.
//
class ThreadsList : public CHeapObj<mtThread> {
friend class ScanHazardPtrGatherProtectedThreadsClosure;
friend class Threads;
const uint _length;
ThreadsList* _next_list;
JavaThread *const *const _threads;
template <class T>
void threads_do_dispatch(T *cl, JavaThread *const thread) const;
ThreadsList *next_list() const { return _next_list; }
void set_next_list(ThreadsList *list) { _next_list = list; }
public:
ThreadsList(int entries);
~ThreadsList();
template <class T>
void threads_do(T *cl) const;
uint length() const { return _length; }
JavaThread *const thread_at(uint i) const { return _threads[i]; }
JavaThread *const *threads() const { return _threads; }
// Returns -1 if target is not found.
int find_index_of_JavaThread(JavaThread* target);
JavaThread* find_JavaThread_from_java_tid(jlong java_tid) const;
bool includes(const JavaThread * const p) const;
static ThreadsList* add_thread(ThreadsList* list, JavaThread* java_thread);
static ThreadsList* remove_thread(ThreadsList* list, JavaThread* java_thread);
};
// Linked list of ThreadsLists to support nested ThreadsListHandles.
class NestedThreadsList : public CHeapObj<mtThread> {
ThreadsList*const _t_list;
NestedThreadsList* _next;
public:
NestedThreadsList(ThreadsList* t_list) : _t_list(t_list) {
assert(Threads_lock->owned_by_self(),
"must own Threads_lock for saved t_list to be valid.");
}
ThreadsList* t_list() { return _t_list; }
NestedThreadsList* next() { return _next; }
void set_next(NestedThreadsList* value) { _next = value; }
};
// A helper to optionally set the hazard ptr in ourself. This helper can
// be used by ourself or by another thread. If the hazard ptr is set(),
// then the destructor will release it.
//
class ThreadsListSetter : public StackObj {
private:
bool _target_needs_release; // needs release only when set()
Thread * _target;
public:
ThreadsListSetter() : _target_needs_release(false), _target(Thread::current()) {
}
~ThreadsListSetter();
ThreadsList* list();
void set();
bool target_needs_release() { return _target_needs_release; }
};
// This stack allocated ThreadsListHandle keeps all JavaThreads in the
// ThreadsList from being deleted until it is safe.
//
class ThreadsListHandle : public StackObj {
ThreadsList * _list;
Thread *const _self;
elapsedTimer _timer; // Enabled via -XX:+EnableThreadSMRStatistics.
public:
ThreadsListHandle(Thread *self = Thread::current());
~ThreadsListHandle();
ThreadsList *list() const {
return _list;
}
template <class T>
void threads_do(T *cl) const {
return _list->threads_do(cl);
}
bool cv_internal_thread_to_JavaThread(jobject jthread, JavaThread ** jt_pp, oop * thread_oop_p);
bool includes(JavaThread* p) {
return _list->includes(p);
}
uint length() const {
return _list->length();
}
};
// This stack allocated JavaThreadIterator is used to walk the
// specified ThreadsList using the following style:
//
// JavaThreadIterator jti(t_list);
// for (JavaThread *jt = jti.first(); jt != NULL; jt = jti.next()) {
// ...
// }
//
class JavaThreadIterator : public StackObj {
ThreadsList * _list;
uint _index;
public:
JavaThreadIterator(ThreadsList *list) : _list(list), _index(0) {
assert(list != NULL, "ThreadsList must not be NULL.");
}
JavaThread *first() {
_index = 0;
return _list->thread_at(_index);
}
uint length() const {
return _list->length();
}
ThreadsList *list() const {
return _list;
}
JavaThread *next() {
if (++_index >= length()) {
return NULL;
}
return _list->thread_at(_index);
}
};
// This stack allocated ThreadsListHandle and JavaThreadIterator combo
// is used to walk the ThreadsList in the included ThreadsListHandle
// using the following style:
//
// for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
// ...
// }
//
class JavaThreadIteratorWithHandle : public StackObj {
ThreadsListHandle _tlh;
uint _index;
public:
JavaThreadIteratorWithHandle() : _index(0) {}
uint length() const {
return _tlh.length();
}
ThreadsList *list() const {
return _tlh.list();
}
JavaThread *next() {
if (_index >= length()) {
return NULL;
}
return _tlh.list()->thread_at(_index++);
}
void rewind() {
_index = 0;
}
};
#endif // SHARE_VM_RUNTIME_THREADSMR_HPP

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_RUNTIME_THREADSMR_INLINE_HPP
#define SHARE_VM_RUNTIME_THREADSMR_INLINE_HPP
#include "runtime/atomic.hpp"
#include "runtime/prefetch.inline.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
// Devirtualize known thread closure types.
template <class T>
inline void ThreadsList::threads_do_dispatch(T *cl, JavaThread *const thread) const {
cl->T::do_thread(thread);
}
template <>
inline void ThreadsList::threads_do_dispatch<ThreadClosure>(ThreadClosure *cl, JavaThread *const thread) const {
cl->do_thread(thread);
}
template <class T>
inline void ThreadsList::threads_do(T *cl) const {
const intx scan_interval = PrefetchScanIntervalInBytes;
JavaThread *const *const end = _threads + _length;
for (JavaThread *const *current_p = _threads; current_p != end; current_p++) {
Prefetch::read((void*)current_p, scan_interval);
JavaThread *const current = *current_p;
threads_do_dispatch(cl, current);
}
}
inline ThreadsList* ThreadsListSetter::list() {
ThreadsList *ret = _target->get_threads_hazard_ptr();
assert(ret != NULL, "hazard ptr should be set");
assert(!Thread::is_hazard_ptr_tagged(ret), "hazard ptr should be validated");
return ret;
}
#endif // SHARE_VM_RUNTIME_THREADSMR_INLINE_HPP

View File

@ -830,7 +830,7 @@ typedef PaddedEnd<ObjectMonitor> PaddedObjectMonitor;
nonstatic_field(nmethod, _osr_link, nmethod*) \
nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \
nonstatic_field(nmethod, _scavenge_root_state, jbyte) \
nonstatic_field(nmethod, _state, volatile char) \
nonstatic_field(nmethod, _state, volatile signed char) \
nonstatic_field(nmethod, _exception_offset, int) \
nonstatic_field(nmethod, _orig_pc_offset, int) \
nonstatic_field(nmethod, _stub_offset, int) \
@ -1350,8 +1350,8 @@ typedef PaddedEnd<ObjectMonitor> PaddedObjectMonitor;
declare_integer_type(int) \
declare_integer_type(long) \
declare_integer_type(char) \
declare_integer_type(volatile signed char) \
declare_unsigned_integer_type(unsigned char) \
declare_unsigned_integer_type(volatile char) \
declare_unsigned_integer_type(u_char) \
declare_unsigned_integer_type(unsigned int) \
declare_unsigned_integer_type(uint) \
@ -1958,6 +1958,7 @@ typedef PaddedEnd<ObjectMonitor> PaddedObjectMonitor;
declare_c2_type(NegFNode, NegNode) \
declare_c2_type(NegDNode, NegNode) \
declare_c2_type(AtanDNode, Node) \
declare_c2_type(SqrtFNode, Node) \
declare_c2_type(SqrtDNode, Node) \
declare_c2_type(ReverseBytesINode, Node) \
declare_c2_type(ReverseBytesLNode, Node) \

View File

@ -38,6 +38,7 @@
#include "runtime/interfaceSupport.hpp"
#include "runtime/sweeper.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.inline.hpp"
#include "runtime/vm_operations.hpp"
#include "services/threadService.hpp"
#include "trace/tracing.hpp"
@ -96,11 +97,12 @@ void VM_Operation::print_on_error(outputStream* st) const {
void VM_ThreadStop::doit() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
ThreadsListHandle tlh;
JavaThread* target = java_lang_Thread::thread(target_thread());
// Note that this now allows multiple ThreadDeath exceptions to be
// thrown at a thread.
if (target != NULL) {
// the thread has run and is not already in the process of exiting
if (target != NULL && (!EnableThreadSMRExtraValidityChecks || tlh.includes(target))) {
// The target thread has run and has not exited yet.
target->send_thread_stop(throwable());
}
}
@ -146,9 +148,10 @@ void VM_DeoptimizeFrame::doit() {
void VM_DeoptimizeAll::doit() {
DeoptimizationMarker dm;
JavaThreadIteratorWithHandle jtiwh;
// deoptimize all java threads in the system
if (DeoptimizeALot) {
for (JavaThread* thread = Threads::first(); thread != NULL; thread = thread->next()) {
for (; JavaThread *thread = jtiwh.next(); ) {
if (thread->has_last_Java_frame()) {
thread->deoptimize();
}
@ -159,7 +162,7 @@ void VM_DeoptimizeAll::doit() {
int tnum = os::random() & 0x3;
int fnum = os::random() & 0x3;
int tcount = 0;
for (JavaThread* thread = Threads::first(); thread != NULL; thread = thread->next()) {
for (; JavaThread *thread = jtiwh.next(); ) {
if (thread->has_last_Java_frame()) {
if (tcount++ == tnum) {
tcount = 0;
@ -259,12 +262,19 @@ bool VM_FindDeadlocks::doit_prologue() {
}
void VM_FindDeadlocks::doit() {
_deadlocks = ThreadService::find_deadlocks_at_safepoint(_concurrent_locks);
// Update the hazard ptr in the originating thread to the current
// list of threads. This VM operation needs the current list of
// threads for proper deadlock detection and those are the
// JavaThreads we need to be protected when we return info to the
// originating thread.
_setter.set();
_deadlocks = ThreadService::find_deadlocks_at_safepoint(_setter.list(), _concurrent_locks);
if (_out != NULL) {
int num_deadlocks = 0;
for (DeadlockCycle* cycle = _deadlocks; cycle != NULL; cycle = cycle->next()) {
num_deadlocks++;
cycle->print_on(_out);
cycle->print_on_with(_setter.list(), _out);
}
if (num_deadlocks == 1) {
@ -331,6 +341,12 @@ void VM_ThreadDump::doit_epilogue() {
void VM_ThreadDump::doit() {
ResourceMark rm;
// Set the hazard ptr in the originating thread to protect the
// current list of threads. This VM operation needs the current list
// of threads for a proper dump and those are the JavaThreads we need
// to be protected when we return info to the originating thread.
_result->set_t_list();
ConcurrentLocksDump concurrent_locks(true);
if (_with_locked_synchronizers) {
concurrent_locks.dump_at_safepoint();
@ -338,7 +354,9 @@ void VM_ThreadDump::doit() {
if (_num_threads == 0) {
// Snapshot all live threads
for (JavaThread* jt = Threads::first(); jt != NULL; jt = jt->next()) {
for (uint i = 0; i < _result->t_list()->length(); i++) {
JavaThread* jt = _result->t_list()->thread_at(i);
if (jt->is_exiting() ||
jt->is_hidden_from_external_view()) {
// skip terminating threads and hidden threads
@ -354,6 +372,7 @@ void VM_ThreadDump::doit() {
} else {
// Snapshot threads in the given _threads array
// A dummy snapshot is created if a thread doesn't exist
for (int i = 0; i < _num_threads; i++) {
instanceHandle th = _threads->at(i);
if (th() == NULL) {
@ -366,6 +385,12 @@ void VM_ThreadDump::doit() {
// Dump thread stack only if the thread is alive and not exiting
// and not VM internal thread.
JavaThread* jt = java_lang_Thread::thread(th());
if (jt != NULL && !_result->t_list()->includes(jt)) {
// _threads[i] doesn't refer to a valid JavaThread; this check
// is primarily for JVM_DumpThreads() which doesn't have a good
// way to validate the _threads array.
jt = NULL;
}
if (jt == NULL || /* thread not alive */
jt->is_exiting() ||
jt->is_hidden_from_external_view()) {
@ -384,7 +409,7 @@ void VM_ThreadDump::doit() {
}
ThreadSnapshot* VM_ThreadDump::snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl) {
ThreadSnapshot* snapshot = new ThreadSnapshot(java_thread);
ThreadSnapshot* snapshot = new ThreadSnapshot(_result->t_list(), java_thread);
snapshot->dump_stack_at_safepoint(_max_depth, _with_locked_monitors);
snapshot->set_concurrent_locks(tcl);
return snapshot;
@ -403,11 +428,12 @@ int VM_Exit::set_vm_exited() {
_shutdown_thread = thr_cur;
_vm_exited = true; // global flag
for(JavaThread *thr = Threads::first(); thr != NULL; thr = thr->next())
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thr = jtiwh.next(); ) {
if (thr!=thr_cur && thr->thread_state() == _thread_in_native) {
++num_active;
thr->set_terminated(JavaThread::_vm_exited); // per-thread flag
}
}
return num_active;
}
@ -435,11 +461,13 @@ int VM_Exit::wait_for_threads_in_native_to_block() {
int max_wait = max_wait_compiler_thread;
int attempts = 0;
JavaThreadIteratorWithHandle jtiwh;
while (true) {
int num_active = 0;
int num_active_compiler_thread = 0;
for(JavaThread *thr = Threads::first(); thr != NULL; thr = thr->next()) {
jtiwh.rewind();
for (; JavaThread *thr = jtiwh.next(); ) {
if (thr!=thr_cur && thr->thread_state() == _thread_in_native) {
num_active++;
if (thr->is_Compiler_thread()) {

View File

@ -392,12 +392,14 @@ class VM_PrintMetadata : public VM_Operation {
class DeadlockCycle;
class VM_FindDeadlocks: public VM_Operation {
private:
bool _concurrent_locks;
DeadlockCycle* _deadlocks;
outputStream* _out;
bool _concurrent_locks;
DeadlockCycle* _deadlocks;
outputStream* _out;
ThreadsListSetter _setter; // Helper to set hazard ptr in the originating thread
// which protects the JavaThreads in _deadlocks.
public:
VM_FindDeadlocks(bool concurrent_locks) : _concurrent_locks(concurrent_locks), _out(NULL), _deadlocks(NULL) {};
VM_FindDeadlocks(bool concurrent_locks) : _concurrent_locks(concurrent_locks), _out(NULL), _deadlocks(NULL), _setter() {};
VM_FindDeadlocks(outputStream* st) : _concurrent_locks(true), _out(st), _deadlocks(NULL) {};
~VM_FindDeadlocks();

View File

@ -39,6 +39,8 @@
#include "runtime/jniHandles.hpp"
#include "runtime/os.hpp"
#include "runtime/reflectionUtils.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
@ -1895,7 +1897,7 @@ void VM_HeapDumper::dump_stack_traces() {
_stack_traces = NEW_C_HEAP_ARRAY(ThreadStackTrace*, Threads::number_of_threads(), mtInternal);
int frame_serial_num = 0;
for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
oop threadObj = thread->threadObj();
if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) {
// dump thread stack trace

View File

@ -1,345 +0,0 @@
/*
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef _JAVA_JMM_H_
#define _JAVA_JMM_H_
/*
* This is a private interface used by JDK for JVM monitoring
* and management.
*
* Bump the version number when either of the following happens:
*
* 1. There is a change in functions in JmmInterface.
*
* 2. There is a change in the contract between VM and Java classes.
*/
#include "jni.h"
#ifdef __cplusplus
extern "C" {
#endif
enum {
JMM_VERSION_1 = 0x20010000,
JMM_VERSION_1_0 = 0x20010000,
JMM_VERSION_1_1 = 0x20010100, // JDK 6
JMM_VERSION_1_2 = 0x20010200, // JDK 7
JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA
JMM_VERSION_1_2_2 = 0x20010202,
JMM_VERSION_2 = 0x20020000, // JDK 10
JMM_VERSION = 0x20020000
};
typedef struct {
unsigned int isLowMemoryDetectionSupported : 1;
unsigned int isCompilationTimeMonitoringSupported : 1;
unsigned int isThreadContentionMonitoringSupported : 1;
unsigned int isCurrentThreadCpuTimeSupported : 1;
unsigned int isOtherThreadCpuTimeSupported : 1;
unsigned int isObjectMonitorUsageSupported : 1;
unsigned int isSynchronizerUsageSupported : 1;
unsigned int isThreadAllocatedMemorySupported : 1;
unsigned int isRemoteDiagnosticCommandsSupported : 1;
unsigned int : 22;
} jmmOptionalSupport;
typedef enum {
JMM_CLASS_LOADED_COUNT = 1, /* Total number of loaded classes */
JMM_CLASS_UNLOADED_COUNT = 2, /* Total number of unloaded classes */
JMM_THREAD_TOTAL_COUNT = 3, /* Total number of threads that have been started */
JMM_THREAD_LIVE_COUNT = 4, /* Current number of live threads */
JMM_THREAD_PEAK_COUNT = 5, /* Peak number of live threads */
JMM_THREAD_DAEMON_COUNT = 6, /* Current number of daemon threads */
JMM_JVM_INIT_DONE_TIME_MS = 7, /* Time when the JVM finished initialization */
JMM_COMPILE_TOTAL_TIME_MS = 8, /* Total accumulated time spent in compilation */
JMM_GC_TIME_MS = 9, /* Total accumulated time spent in collection */
JMM_GC_COUNT = 10, /* Total number of collections */
JMM_JVM_UPTIME_MS = 11, /* The JVM uptime in milliseconds */
JMM_INTERNAL_ATTRIBUTE_INDEX = 100,
JMM_CLASS_LOADED_BYTES = 101, /* Number of bytes loaded instance classes */
JMM_CLASS_UNLOADED_BYTES = 102, /* Number of bytes unloaded instance classes */
JMM_TOTAL_CLASSLOAD_TIME_MS = 103, /* Accumulated VM class loader time (TraceClassLoadingTime) */
JMM_VM_GLOBAL_COUNT = 104, /* Number of VM internal flags */
JMM_SAFEPOINT_COUNT = 105, /* Total number of safepoints */
JMM_TOTAL_SAFEPOINTSYNC_TIME_MS = 106, /* Accumulated time spent getting to safepoints */
JMM_TOTAL_STOPPED_TIME_MS = 107, /* Accumulated time spent at safepoints */
JMM_TOTAL_APP_TIME_MS = 108, /* Accumulated time spent in Java application */
JMM_VM_THREAD_COUNT = 109, /* Current number of VM internal threads */
JMM_CLASS_INIT_TOTAL_COUNT = 110, /* Number of classes for which initializers were run */
JMM_CLASS_INIT_TOTAL_TIME_MS = 111, /* Accumulated time spent in class initializers */
JMM_METHOD_DATA_SIZE_BYTES = 112, /* Size of method data in memory */
JMM_CLASS_VERIFY_TOTAL_TIME_MS = 113, /* Accumulated time spent in class verifier */
JMM_SHARED_CLASS_LOADED_COUNT = 114, /* Number of shared classes loaded */
JMM_SHARED_CLASS_UNLOADED_COUNT = 115, /* Number of shared classes unloaded */
JMM_SHARED_CLASS_LOADED_BYTES = 116, /* Number of bytes loaded shared classes */
JMM_SHARED_CLASS_UNLOADED_BYTES = 117, /* Number of bytes unloaded shared classes */
JMM_OS_ATTRIBUTE_INDEX = 200,
JMM_OS_PROCESS_ID = 201, /* Process id of the JVM */
JMM_OS_MEM_TOTAL_PHYSICAL_BYTES = 202, /* Physical memory size */
JMM_GC_EXT_ATTRIBUTE_INFO_SIZE = 401 /* the size of the GC specific attributes for a given GC memory manager */
} jmmLongAttribute;
typedef enum {
JMM_VERBOSE_GC = 21,
JMM_VERBOSE_CLASS = 22,
JMM_THREAD_CONTENTION_MONITORING = 23,
JMM_THREAD_CPU_TIME = 24,
JMM_THREAD_ALLOCATED_MEMORY = 25
} jmmBoolAttribute;
enum {
JMM_THREAD_STATE_FLAG_SUSPENDED = 0x00100000,
JMM_THREAD_STATE_FLAG_NATIVE = 0x00400000
};
#define JMM_THREAD_STATE_FLAG_MASK 0xFFF00000
typedef enum {
JMM_STAT_PEAK_THREAD_COUNT = 801,
JMM_STAT_THREAD_CONTENTION_COUNT = 802,
JMM_STAT_THREAD_CONTENTION_TIME = 803,
JMM_STAT_THREAD_CONTENTION_STAT = 804,
JMM_STAT_PEAK_POOL_USAGE = 805,
JMM_STAT_GC_STAT = 806
} jmmStatisticType;
typedef enum {
JMM_USAGE_THRESHOLD_HIGH = 901,
JMM_USAGE_THRESHOLD_LOW = 902,
JMM_COLLECTION_USAGE_THRESHOLD_HIGH = 903,
JMM_COLLECTION_USAGE_THRESHOLD_LOW = 904
} jmmThresholdType;
/* Should match what is allowed in globals.hpp */
typedef enum {
JMM_VMGLOBAL_TYPE_UNKNOWN = 0,
JMM_VMGLOBAL_TYPE_JBOOLEAN = 1,
JMM_VMGLOBAL_TYPE_JSTRING = 2,
JMM_VMGLOBAL_TYPE_JLONG = 3,
JMM_VMGLOBAL_TYPE_JDOUBLE = 4
} jmmVMGlobalType;
typedef enum {
JMM_VMGLOBAL_ORIGIN_DEFAULT = 1, /* Default value */
JMM_VMGLOBAL_ORIGIN_COMMAND_LINE = 2, /* Set at command line (or JNI invocation) */
JMM_VMGLOBAL_ORIGIN_MANAGEMENT = 3, /* Set via management interface */
JMM_VMGLOBAL_ORIGIN_ENVIRON_VAR = 4, /* Set via environment variables */
JMM_VMGLOBAL_ORIGIN_CONFIG_FILE = 5, /* Set via config file (such as .hotspotrc) */
JMM_VMGLOBAL_ORIGIN_ERGONOMIC = 6, /* Set via ergonomic */
JMM_VMGLOBAL_ORIGIN_ATTACH_ON_DEMAND = 7, /* Set via attach */
JMM_VMGLOBAL_ORIGIN_OTHER = 99 /* Set via some other mechanism */
} jmmVMGlobalOrigin;
typedef struct {
jstring name;
jvalue value;
jmmVMGlobalType type; /* Data type */
jmmVMGlobalOrigin origin; /* Default or non-default value */
unsigned int writeable : 1; /* dynamically writeable */
unsigned int external : 1; /* external supported interface */
unsigned int reserved : 30;
void *reserved1;
void *reserved2;
} jmmVMGlobal;
typedef struct {
const char* name;
char type;
const char* description;
} jmmExtAttributeInfo;
/* Caller has to set the following fields before calling GetLastGCStat
* o usage_before_gc - array of MemoryUsage objects
* o usage_after_gc - array of MemoryUsage objects
* o gc_ext_attribute_values_size - size of gc_ext_atttribute_values array
* o gc_ext_attribtue_values - array of jvalues
*/
typedef struct {
jlong gc_index; /* Index of the collections */
jlong start_time; /* Start time of the GC */
jlong end_time; /* End time of the GC */
jobjectArray usage_before_gc; /* Memory usage array before GC */
jobjectArray usage_after_gc; /* Memory usage array after GC */
jint gc_ext_attribute_values_size; /* set by the caller of GetGCStat */
jvalue* gc_ext_attribute_values; /* Array of jvalue for GC extension attributes */
jint num_gc_ext_attributes; /* number of GC extension attribute values s are filled */
/* -1 indicates gc_ext_attribute_values is not big enough */
} jmmGCStat;
typedef struct {
const char* name; /* Name of the diagnostic command */
const char* description; /* Short description */
const char* impact; /* Impact on the JVM */
const char* permission_class; /* Class name of the required permission if any */
const char* permission_name; /* Permission name of the required permission if any */
const char* permission_action; /* Action name of the required permission if any*/
int num_arguments; /* Number of supported options or arguments */
jboolean enabled; /* True if the diagnostic command can be invoked, false otherwise */
} dcmdInfo;
typedef struct {
const char* name; /* Option/Argument name*/
const char* description; /* Short description */
const char* type; /* Type: STRING, BOOLEAN, etc. */
const char* default_string; /* Default value in a parsable string */
jboolean mandatory; /* True if the option/argument is mandatory */
jboolean option; /* True if it is an option, false if it is an argument */
/* (see diagnosticFramework.hpp for option/argument definitions) */
jboolean multiple; /* True if the option can be specified several time */
int position; /* Expected position for this argument (this field is */
/* meaningless for options) */
} dcmdArgInfo;
typedef struct jmmInterface_1_ {
void* reserved1;
void* reserved2;
jint (JNICALL *GetVersion) (JNIEnv *env);
jint (JNICALL *GetOptionalSupport) (JNIEnv *env,
jmmOptionalSupport* support_ptr);
jint (JNICALL *GetThreadInfo) (JNIEnv *env,
jlongArray ids,
jint maxDepth,
jobjectArray infoArray);
jobjectArray (JNICALL *GetMemoryPools) (JNIEnv* env, jobject mgr);
jobjectArray (JNICALL *GetMemoryManagers) (JNIEnv* env, jobject pool);
jobject (JNICALL *GetMemoryPoolUsage) (JNIEnv* env, jobject pool);
jobject (JNICALL *GetPeakMemoryPoolUsage) (JNIEnv* env, jobject pool);
void (JNICALL *GetThreadAllocatedMemory)
(JNIEnv *env,
jlongArray ids,
jlongArray sizeArray);
jobject (JNICALL *GetMemoryUsage) (JNIEnv* env, jboolean heap);
jlong (JNICALL *GetLongAttribute) (JNIEnv *env, jobject obj, jmmLongAttribute att);
jboolean (JNICALL *GetBoolAttribute) (JNIEnv *env, jmmBoolAttribute att);
jboolean (JNICALL *SetBoolAttribute) (JNIEnv *env, jmmBoolAttribute att, jboolean flag);
jint (JNICALL *GetLongAttributes) (JNIEnv *env,
jobject obj,
jmmLongAttribute* atts,
jint count,
jlong* result);
jobjectArray (JNICALL *FindCircularBlockedThreads) (JNIEnv *env);
// Not used in JDK 6 or JDK 7
jlong (JNICALL *GetThreadCpuTime) (JNIEnv *env, jlong thread_id);
jobjectArray (JNICALL *GetVMGlobalNames) (JNIEnv *env);
jint (JNICALL *GetVMGlobals) (JNIEnv *env,
jobjectArray names,
jmmVMGlobal *globals,
jint count);
jint (JNICALL *GetInternalThreadTimes) (JNIEnv *env,
jobjectArray names,
jlongArray times);
jboolean (JNICALL *ResetStatistic) (JNIEnv *env,
jvalue obj,
jmmStatisticType type);
void (JNICALL *SetPoolSensor) (JNIEnv *env,
jobject pool,
jmmThresholdType type,
jobject sensor);
jlong (JNICALL *SetPoolThreshold) (JNIEnv *env,
jobject pool,
jmmThresholdType type,
jlong threshold);
jobject (JNICALL *GetPoolCollectionUsage) (JNIEnv* env, jobject pool);
jint (JNICALL *GetGCExtAttributeInfo) (JNIEnv *env,
jobject mgr,
jmmExtAttributeInfo *ext_info,
jint count);
void (JNICALL *GetLastGCStat) (JNIEnv *env,
jobject mgr,
jmmGCStat *gc_stat);
jlong (JNICALL *GetThreadCpuTimeWithKind)
(JNIEnv *env,
jlong thread_id,
jboolean user_sys_cpu_time);
void (JNICALL *GetThreadCpuTimesWithKind)
(JNIEnv *env,
jlongArray ids,
jlongArray timeArray,
jboolean user_sys_cpu_time);
jint (JNICALL *DumpHeap0) (JNIEnv *env,
jstring outputfile,
jboolean live);
jobjectArray (JNICALL *FindDeadlocks) (JNIEnv *env,
jboolean object_monitors_only);
void (JNICALL *SetVMGlobal) (JNIEnv *env,
jstring flag_name,
jvalue new_value);
void* reserved6;
jobjectArray (JNICALL *DumpThreads) (JNIEnv *env,
jlongArray ids,
jboolean lockedMonitors,
jboolean lockedSynchronizers,
jint maxDepth);
void (JNICALL *SetGCNotificationEnabled) (JNIEnv *env,
jobject mgr,
jboolean enabled);
jobjectArray (JNICALL *GetDiagnosticCommands) (JNIEnv *env);
void (JNICALL *GetDiagnosticCommandInfo)
(JNIEnv *env,
jobjectArray cmds,
dcmdInfo *infoArray);
void (JNICALL *GetDiagnosticCommandArgumentsInfo)
(JNIEnv *env,
jstring commandName,
dcmdArgInfo *infoArray);
jstring (JNICALL *ExecuteDiagnosticCommand)
(JNIEnv *env,
jstring command);
void (JNICALL *SetDiagnosticFrameworkNotificationEnabled)
(JNIEnv *env,
jboolean enabled);
} JmmInterface;
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* !_JAVA_JMM_H_ */

View File

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "jmm.h"
#include "classfile/systemDictionary.hpp"
#include "compiler/compileBroker.hpp"
#include "memory/iterator.hpp"
@ -41,12 +42,12 @@
#include "runtime/os.hpp"
#include "runtime/serviceThread.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "services/classLoadingService.hpp"
#include "services/diagnosticCommand.hpp"
#include "services/diagnosticFramework.hpp"
#include "services/writeableFlags.hpp"
#include "services/heapDumper.hpp"
#include "services/jmm.h"
#include "services/lowMemoryDetector.hpp"
#include "services/gcNotifier.hpp"
#include "services/nmtDCmd.hpp"
@ -1025,11 +1026,15 @@ static void do_thread_dump(ThreadDumpResult* dump_result,
// First get an array of threadObj handles.
// A JavaThread may terminate before we get the stack trace.
GrowableArray<instanceHandle>* thread_handle_array = new GrowableArray<instanceHandle>(num_threads);
{
MutexLockerEx ml(Threads_lock);
// Need this ThreadsListHandle for converting Java thread IDs into
// threadObj handles; dump_result->set_t_list() is called in the
// VM op below so we can't use it yet.
ThreadsListHandle tlh;
for (int i = 0; i < num_threads; i++) {
jlong tid = ids_ah->long_at(i);
JavaThread* jt = Threads::find_java_thread_from_java_tid(tid);
JavaThread* jt = tlh.list()->find_JavaThread_from_java_tid(tid);
oop thread_obj = (jt != NULL ? jt->threadObj() : (oop)NULL);
instanceHandle threadObj_h(THREAD, (instanceOop) thread_obj);
thread_handle_array->append(threadObj_h);
@ -1101,22 +1106,21 @@ JVM_ENTRY(jint, jmm_GetThreadInfo(JNIEnv *env, jlongArray ids, jint maxDepth, jo
ThreadDumpResult dump_result(num_threads);
if (maxDepth == 0) {
// no stack trace dumped - do not need to stop the world
{
MutexLockerEx ml(Threads_lock);
for (int i = 0; i < num_threads; i++) {
jlong tid = ids_ah->long_at(i);
JavaThread* jt = Threads::find_java_thread_from_java_tid(tid);
ThreadSnapshot* ts;
if (jt == NULL) {
// if the thread does not exist or now it is terminated,
// create dummy snapshot
ts = new ThreadSnapshot();
} else {
ts = new ThreadSnapshot(jt);
}
dump_result.add_thread_snapshot(ts);
// No stack trace to dump so we do not need to stop the world.
// Since we never do the VM op here we must set the threads list.
dump_result.set_t_list();
for (int i = 0; i < num_threads; i++) {
jlong tid = ids_ah->long_at(i);
JavaThread* jt = dump_result.t_list()->find_JavaThread_from_java_tid(tid);
ThreadSnapshot* ts;
if (jt == NULL) {
// if the thread does not exist or now it is terminated,
// create dummy snapshot
ts = new ThreadSnapshot();
} else {
ts = new ThreadSnapshot(dump_result.t_list(), jt);
}
dump_result.add_thread_snapshot(ts);
}
} else {
// obtain thread dump with the specific list of threads with stack trace
@ -1131,6 +1135,7 @@ JVM_ENTRY(jint, jmm_GetThreadInfo(JNIEnv *env, jlongArray ids, jint maxDepth, jo
int num_snapshots = dump_result.num_snapshots();
assert(num_snapshots == num_threads, "Must match the number of thread snapshots");
assert(num_snapshots == 0 || dump_result.t_list_has_been_set(), "ThreadsList must have been set if we have a snapshot");
int index = 0;
for (ThreadSnapshot* ts = dump_result.snapshots(); ts != NULL; index++, ts = ts->next()) {
// For each thread, create an java/lang/management/ThreadInfo object
@ -1196,6 +1201,7 @@ JVM_ENTRY(jobjectArray, jmm_DumpThreads(JNIEnv *env, jlongArray thread_ids, jboo
}
int num_snapshots = dump_result.num_snapshots();
assert(num_snapshots == 0 || dump_result.t_list_has_been_set(), "ThreadsList must have been set if we have a snapshot");
// create the result ThreadInfo[] object
InstanceKlass* ik = Management::java_lang_management_ThreadInfo_klass(CHECK_NULL);
@ -1319,10 +1325,10 @@ JVM_ENTRY(jboolean, jmm_ResetStatistic(JNIEnv *env, jvalue obj, jmmStatisticType
}
// Look for the JavaThread of this given tid
MutexLockerEx ml(Threads_lock);
JavaThreadIteratorWithHandle jtiwh;
if (tid == 0) {
// reset contention statistics for all threads if tid == 0
for (JavaThread* java_thread = Threads::first(); java_thread != NULL; java_thread = java_thread->next()) {
for (; JavaThread *java_thread = jtiwh.next(); ) {
if (type == JMM_STAT_THREAD_CONTENTION_COUNT) {
ThreadService::reset_contention_count_stat(java_thread);
} else {
@ -1331,7 +1337,7 @@ JVM_ENTRY(jboolean, jmm_ResetStatistic(JNIEnv *env, jvalue obj, jmmStatisticType
}
} else {
// reset contention statistics for a given thread
JavaThread* java_thread = Threads::find_java_thread_from_java_tid(tid);
JavaThread* java_thread = jtiwh.list()->find_JavaThread_from_java_tid(tid);
if (java_thread == NULL) {
return false;
}
@ -1399,8 +1405,8 @@ JVM_ENTRY(jlong, jmm_GetThreadCpuTime(JNIEnv *env, jlong thread_id))
// current thread
return os::current_thread_cpu_time();
} else {
MutexLockerEx ml(Threads_lock);
java_thread = Threads::find_java_thread_from_java_tid(thread_id);
ThreadsListHandle tlh;
java_thread = tlh.list()->find_JavaThread_from_java_tid(thread_id);
if (java_thread != NULL) {
return os::thread_cpu_time((Thread*) java_thread);
}
@ -1649,6 +1655,7 @@ ThreadTimesClosure::ThreadTimesClosure(objArrayHandle names,
// Called with Threads_lock held
//
void ThreadTimesClosure::do_thread(Thread* thread) {
assert(Threads_lock->owned_by_self(), "Must hold Threads_lock");
assert(thread != NULL, "thread was NULL");
// exclude externally visible JavaThreads
@ -2109,9 +2116,9 @@ JVM_ENTRY(void, jmm_GetThreadAllocatedMemory(JNIEnv *env, jlongArray ids,
"the given array of thread IDs");
}
MutexLockerEx ml(Threads_lock);
ThreadsListHandle tlh;
for (int i = 0; i < num_threads; i++) {
JavaThread* java_thread = Threads::find_java_thread_from_java_tid(ids_ah->long_at(i));
JavaThread* java_thread = tlh.list()->find_JavaThread_from_java_tid(ids_ah->long_at(i));
if (java_thread != NULL) {
sizeArray_h->long_at_put(i, java_thread->cooked_allocated_bytes());
}
@ -2138,8 +2145,8 @@ JVM_ENTRY(jlong, jmm_GetThreadCpuTimeWithKind(JNIEnv *env, jlong thread_id, jboo
// current thread
return os::current_thread_cpu_time(user_sys_cpu_time != 0);
} else {
MutexLockerEx ml(Threads_lock);
java_thread = Threads::find_java_thread_from_java_tid(thread_id);
ThreadsListHandle tlh;
java_thread = tlh.list()->find_JavaThread_from_java_tid(thread_id);
if (java_thread != NULL) {
return os::thread_cpu_time((Thread*) java_thread, user_sys_cpu_time != 0);
}
@ -2180,9 +2187,9 @@ JVM_ENTRY(void, jmm_GetThreadCpuTimesWithKind(JNIEnv *env, jlongArray ids,
"the given array of thread IDs");
}
MutexLockerEx ml(Threads_lock);
ThreadsListHandle tlh;
for (int i = 0; i < num_threads; i++) {
JavaThread* java_thread = Threads::find_java_thread_from_java_tid(ids_ah->long_at(i));
JavaThread* java_thread = tlh.list()->find_JavaThread_from_java_tid(ids_ah->long_at(i));
if (java_thread != NULL) {
timeArray_h->long_at_put(i, os::thread_cpu_time((Thread*)java_thread,
user_sys_cpu_time != 0));

View File

@ -25,10 +25,10 @@
#ifndef SHARE_VM_SERVICES_MANAGEMENT_HPP
#define SHARE_VM_SERVICES_MANAGEMENT_HPP
#include "jmm.h"
#include "memory/allocation.hpp"
#include "runtime/handles.hpp"
#include "runtime/timer.hpp"
#include "services/jmm.h"
class OopClosure;
class ThreadSnapshot;

View File

@ -34,9 +34,9 @@
#include "runtime/atomic.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/thread.hpp"
#include "runtime/vframe.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.inline.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
#include "services/threadService.hpp"
@ -148,7 +148,7 @@ void ThreadService::current_thread_exiting(JavaThread* jt) {
// FIXME: JVMTI should call this function
Handle ThreadService::get_current_contended_monitor(JavaThread* thread) {
assert(thread != NULL, "should be non-NULL");
assert(Threads_lock->owned_by_self(), "must grab Threads_lock or be at safepoint");
debug_only(Thread::check_for_dangling_thread_pointer(thread);)
ObjectMonitor *wait_obj = thread->current_waiting_monitor();
@ -266,6 +266,7 @@ Handle ThreadService::dump_stack_traces(GrowableArray<instanceHandle>* threads,
int num_snapshots = dump_result.num_snapshots();
assert(num_snapshots == num_threads, "Must have num_threads thread snapshots");
assert(num_snapshots == 0 || dump_result.t_list_has_been_set(), "ThreadsList must have been set if we have a snapshot");
int i = 0;
for (ThreadSnapshot* ts = dump_result.snapshots(); ts != NULL; i++, ts = ts->next()) {
ThreadStackTrace* stacktrace = ts->get_stack_trace();
@ -297,7 +298,9 @@ void ThreadService::reset_contention_time_stat(JavaThread* thread) {
}
// Find deadlocks involving object monitors and concurrent locks if concurrent_locks is true
DeadlockCycle* ThreadService::find_deadlocks_at_safepoint(bool concurrent_locks) {
DeadlockCycle* ThreadService::find_deadlocks_at_safepoint(ThreadsList * t_list, bool concurrent_locks) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
// This code was modified from the original Threads::find_deadlocks code.
int globalDfn = 0, thisDfn;
ObjectMonitor* waitingToLockMonitor = NULL;
@ -306,15 +309,16 @@ DeadlockCycle* ThreadService::find_deadlocks_at_safepoint(bool concurrent_locks)
JavaThread *currentThread, *previousThread;
int num_deadlocks = 0;
for (JavaThread* p = Threads::first(); p != NULL; p = p->next()) {
// Initialize the depth-first-number
p->set_depth_first_number(-1);
// Initialize the depth-first-number for each JavaThread.
JavaThreadIterator jti(t_list);
for (JavaThread* jt = jti.first(); jt != NULL; jt = jti.next()) {
jt->set_depth_first_number(-1);
}
DeadlockCycle* deadlocks = NULL;
DeadlockCycle* last = NULL;
DeadlockCycle* cycle = new DeadlockCycle();
for (JavaThread* jt = Threads::first(); jt != NULL; jt = jt->next()) {
for (JavaThread* jt = jti.first(); jt != NULL; jt = jti.next()) {
if (jt->depth_first_number() >= 0) {
// this thread was already visited
continue;
@ -339,9 +343,8 @@ DeadlockCycle* ThreadService::find_deadlocks_at_safepoint(bool concurrent_locks)
if (waitingToLockMonitor != NULL) {
address currentOwner = (address)waitingToLockMonitor->owner();
if (currentOwner != NULL) {
currentThread = Threads::owning_thread_from_monitor_owner(
currentOwner,
false /* no locking needed */);
currentThread = Threads::owning_thread_from_monitor_owner(t_list,
currentOwner);
if (currentThread == NULL) {
// This function is called at a safepoint so the JavaThread
// that owns waitingToLockMonitor should be findable, but
@ -366,6 +369,8 @@ DeadlockCycle* ThreadService::find_deadlocks_at_safepoint(bool concurrent_locks)
if (concurrent_locks) {
if (waitingToLockBlocker->is_a(SystemDictionary::abstract_ownable_synchronizer_klass())) {
oop threadObj = java_util_concurrent_locks_AbstractOwnableSynchronizer::get_owner_threadObj(waitingToLockBlocker);
// This JavaThread (if there is one) is protected by the
// ThreadsListSetter in VM_FindDeadlocks::doit().
currentThread = threadObj != NULL ? java_lang_Thread::thread(threadObj) : NULL;
} else {
currentThread = NULL;
@ -414,7 +419,7 @@ DeadlockCycle* ThreadService::find_deadlocks_at_safepoint(bool concurrent_locks)
return deadlocks;
}
ThreadDumpResult::ThreadDumpResult() : _num_threads(0), _num_snapshots(0), _snapshots(NULL), _next(NULL), _last(NULL) {
ThreadDumpResult::ThreadDumpResult() : _num_threads(0), _num_snapshots(0), _snapshots(NULL), _next(NULL), _last(NULL), _setter() {
// Create a new ThreadDumpResult object and append to the list.
// If GC happens before this function returns, Method*
@ -422,7 +427,7 @@ ThreadDumpResult::ThreadDumpResult() : _num_threads(0), _num_snapshots(0), _snap
ThreadService::add_thread_dump(this);
}
ThreadDumpResult::ThreadDumpResult(int num_threads) : _num_threads(num_threads), _num_snapshots(0), _snapshots(NULL), _next(NULL), _last(NULL) {
ThreadDumpResult::ThreadDumpResult(int num_threads) : _num_threads(num_threads), _num_snapshots(0), _snapshots(NULL), _next(NULL), _last(NULL), _setter() {
// Create a new ThreadDumpResult object and append to the list.
// If GC happens before this function returns, oops
// will be visited.
@ -467,6 +472,10 @@ void ThreadDumpResult::metadata_do(void f(Metadata*)) {
}
}
ThreadsList* ThreadDumpResult::t_list() {
return _setter.list();
}
StackFrameInfo::StackFrameInfo(javaVFrame* jvf, bool with_lock_info) {
_method = jvf->method();
_bci = jvf->bci();
@ -683,6 +692,8 @@ void ConcurrentLocksDump::build_map(GrowableArray<oop>* aos_objects) {
oop o = aos_objects->at(i);
oop owner_thread_obj = java_util_concurrent_locks_AbstractOwnableSynchronizer::get_owner_threadObj(o);
if (owner_thread_obj != NULL) {
// See comments in ThreadConcurrentLocks to see how this
// JavaThread* is protected.
JavaThread* thread = java_lang_Thread::thread(owner_thread_obj);
assert(o->is_instance(), "Must be an instanceOop");
add_lock(thread, (instanceOop) o);
@ -764,7 +775,7 @@ ThreadStatistics::ThreadStatistics() {
memset((void*) _perf_recursion_counts, 0, sizeof(_perf_recursion_counts));
}
ThreadSnapshot::ThreadSnapshot(JavaThread* thread) {
ThreadSnapshot::ThreadSnapshot(ThreadsList * t_list, JavaThread* thread) {
_thread = thread;
_threadObj = thread->threadObj();
_stack_trace = NULL;
@ -796,7 +807,7 @@ ThreadSnapshot::ThreadSnapshot(JavaThread* thread) {
_thread_status = java_lang_Thread::RUNNABLE;
} else {
_blocker_object = obj();
JavaThread* owner = ObjectSynchronizer::get_lock_owner(obj, false);
JavaThread* owner = ObjectSynchronizer::get_lock_owner(t_list, obj);
if ((owner == NULL && _thread_status == java_lang_Thread::BLOCKED_ON_MONITOR_ENTER)
|| (owner != NULL && owner->is_attaching_via_jni())) {
// ownership information of the monitor is not available
@ -865,7 +876,7 @@ DeadlockCycle::~DeadlockCycle() {
delete _threads;
}
void DeadlockCycle::print_on(outputStream* st) const {
void DeadlockCycle::print_on_with(ThreadsList * t_list, outputStream* st) const {
st->cr();
st->print_cr("Found one Java-level deadlock:");
st->print("=============================");
@ -895,9 +906,8 @@ void DeadlockCycle::print_on(outputStream* st) const {
// No Java object associated - a JVMTI raw monitor
owner_desc = " (JVMTI raw monitor),\n which is held by";
}
currentThread = Threads::owning_thread_from_monitor_owner(
(address)waitingToLockMonitor->owner(),
false /* no locking needed */);
currentThread = Threads::owning_thread_from_monitor_owner(t_list,
(address)waitingToLockMonitor->owner());
if (currentThread == NULL) {
// The deadlock was detected at a safepoint so the JavaThread
// that owns waitingToLockMonitor should be findable, but
@ -915,6 +925,7 @@ void DeadlockCycle::print_on(outputStream* st) const {
"Must be an AbstractOwnableSynchronizer");
oop ownerObj = java_util_concurrent_locks_AbstractOwnableSynchronizer::get_owner_threadObj(waitingToLockBlocker);
currentThread = java_lang_Thread::thread(ownerObj);
assert(currentThread != NULL, "AbstractOwnableSynchronizer owning thread is unexpectedly NULL");
}
st->print("%s \"%s\"", owner_desc, currentThread->get_thread_name());
}
@ -943,9 +954,7 @@ ThreadsListEnumerator::ThreadsListEnumerator(Thread* cur_thread,
int init_size = ThreadService::get_live_thread_count();
_threads_array = new GrowableArray<instanceHandle>(init_size);
MutexLockerEx ml(Threads_lock);
for (JavaThread* jt = Threads::first(); jt != NULL; jt = jt->next()) {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
// skips JavaThreads in the process of exiting
// and also skips VM internal JavaThreads
// Threads in _thread_new or _thread_new_trans state are included.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -32,6 +32,7 @@
#include "runtime/objectMonitor.hpp"
#include "runtime/objectMonitor.inline.hpp"
#include "runtime/perfData.hpp"
#include "runtime/thread.hpp"
#include "services/management.hpp"
#include "services/serviceUtil.hpp"
@ -109,7 +110,7 @@ public:
static void reset_contention_count_stat(JavaThread* thread);
static void reset_contention_time_stat(JavaThread* thread);
static DeadlockCycle* find_deadlocks_at_safepoint(bool object_monitors_only);
static DeadlockCycle* find_deadlocks_at_safepoint(ThreadsList * t_list, bool object_monitors_only);
// GC support
static void oops_do(OopClosure* f);
@ -189,6 +190,8 @@ public:
// Thread snapshot to represent the thread state and statistics
class ThreadSnapshot : public CHeapObj<mtInternal> {
private:
// This JavaThread* is protected by being stored in objects that are
// protected by a ThreadsListSetter (ThreadDumpResult).
JavaThread* _thread;
oop _threadObj;
java_lang_Thread::ThreadStatus _thread_status;
@ -213,7 +216,7 @@ public:
// Dummy snapshot
ThreadSnapshot() : _thread(NULL), _threadObj(NULL), _stack_trace(NULL), _concurrent_locks(NULL), _next(NULL),
_blocker_object(NULL), _blocker_object_owner(NULL) {};
ThreadSnapshot(JavaThread* thread);
ThreadSnapshot(ThreadsList * t_list, JavaThread* thread);
~ThreadSnapshot();
java_lang_Thread::ThreadStatus thread_status() { return _thread_status; }
@ -310,6 +313,12 @@ class ThreadConcurrentLocks : public CHeapObj<mtInternal> {
private:
GrowableArray<instanceOop>* _owned_locks;
ThreadConcurrentLocks* _next;
// This JavaThread* is protected in one of two different ways
// depending on the usage of the ThreadConcurrentLocks object:
// 1) by being stored in objects that are only allocated and used at a
// safepoint (ConcurrentLocksDump), or 2) by being stored in objects
// that are protected by a ThreadsListSetter (ThreadSnapshot inside
// ThreadDumpResult).
JavaThread* _thread;
public:
ThreadConcurrentLocks(JavaThread* thread);
@ -333,8 +342,12 @@ class ConcurrentLocksDump : public StackObj {
void add_lock(JavaThread* thread, instanceOop o);
public:
ConcurrentLocksDump(bool retain_map_on_free) : _map(NULL), _last(NULL), _retain_map_on_free(retain_map_on_free) {};
ConcurrentLocksDump() : _map(NULL), _last(NULL), _retain_map_on_free(false) {};
ConcurrentLocksDump(bool retain_map_on_free) : _map(NULL), _last(NULL), _retain_map_on_free(retain_map_on_free) {
assert(SafepointSynchronize::is_at_safepoint(), "Must be constructed at a safepoint.");
};
ConcurrentLocksDump() : _map(NULL), _last(NULL), _retain_map_on_free(false) {
assert(SafepointSynchronize::is_at_safepoint(), "Must be constructed at a safepoint.");
};
~ConcurrentLocksDump();
void dump_at_safepoint();
@ -349,6 +362,9 @@ class ThreadDumpResult : public StackObj {
ThreadSnapshot* _snapshots;
ThreadSnapshot* _last;
ThreadDumpResult* _next;
ThreadsListSetter _setter; // Helper to set hazard ptr in the originating thread
// which protects the JavaThreads in _snapshots.
public:
ThreadDumpResult();
ThreadDumpResult(int num_threads);
@ -360,6 +376,9 @@ class ThreadDumpResult : public StackObj {
int num_threads() { return _num_threads; }
int num_snapshots() { return _num_snapshots; }
ThreadSnapshot* snapshots() { return _snapshots; }
void set_t_list() { _setter.set(); }
ThreadsList* t_list();
bool t_list_has_been_set() { return _setter.target_needs_release(); }
void oops_do(OopClosure* f);
void metadata_do(void f(Metadata*));
};
@ -381,7 +400,7 @@ class DeadlockCycle : public CHeapObj<mtInternal> {
bool is_deadlock() { return _is_deadlock; }
int num_threads() { return _threads->length(); }
GrowableArray<JavaThread*>* threads() { return _threads; }
void print_on(outputStream* st) const;
void print_on_with(ThreadsList * t_list, outputStream* st) const;
};
// Utility class to get list of java threads.

View File

@ -36,6 +36,7 @@
#include "runtime/init.hpp"
#include "runtime/os.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
#include "runtime/vm_version.hpp"
@ -1655,7 +1656,12 @@ void VMError::controlled_crash(int how) {
char * const dataPtr = NULL; // bad data pointer
const void (*funcPtr)(void) = (const void(*)()) 0xF; // bad function pointer
// Keep this in sync with test/runtime/ErrorHandling/ErrorHandler.java
// Keep this in sync with test/hotspot/jtreg/runtime/ErrorHandling/ErrorHandler.java
// which tests cases 1 thru 13.
// Case 14 is tested by test/hotspot/jtreg/runtime/ErrorHandling/SafeFetchInErrorHandlingTest.java.
// Case 15 is tested by test/hotspot/jtreg/runtime/ErrorHandling/SecondaryErrorTest.java.
// Case 16 is tested by test/hotspot/jtreg/runtime/ErrorHandling/ThreadsListHandleInErrorHandlingTest.java.
// Case 17 is tested by test/hotspot/jtreg/runtime/ErrorHandling/NestedThreadsListHandleInErrorHandlingTest.java.
switch (how) {
case 1: vmassert(str == NULL, "expected null");
case 2: vmassert(num == 1023 && *str == 'X',
@ -1683,6 +1689,17 @@ void VMError::controlled_crash(int how) {
case 13: (*funcPtr)(); break;
case 14: crash_with_segfault(); break;
case 15: crash_with_sigfpe(); break;
case 16: {
ThreadsListHandle tlh;
fatal("Force crash with an active ThreadsListHandle.");
}
case 17: {
ThreadsListHandle tlh;
{
ThreadsListHandle tlh2;
fatal("Force crash with a nested ThreadsListHandle.");
}
}
default: tty->print_cr("ERROR: %d: unexpected test_num value.", how);
}

View File

@ -62,8 +62,12 @@ ifeq ($(findstring CYGWIN,$(UNAME_S)), CYGWIN)
endif
endif
ifndef CONCURRENCY_FACTOR
CONCURRENCY_FACTOR = 1
endif
# Concurrency based on min(cores / 2, 12)
CONCURRENCY := $(shell expr $(NUM_CORES) / 2)
CONCURRENCY := $(shell awk 'BEGIN { printf "%.0f", $(NUM_CORES) / 2 * $(CONCURRENCY_FACTOR) }')
ifeq ($(CONCURRENCY), 0)
CONCURRENCY := 1
else ifeq ($(shell expr $(CONCURRENCY) \> 12), 1)

View File

@ -24,7 +24,7 @@
/*
* @test TestFullGCALot
* @key gc
* @bug 4187687
* @bug 4187687 8187819
* @summary Ensure no access violation when using FullGCALot
* @requires vm.debug
* @run main/othervm -XX:NewSize=10m -XX:+FullGCALot -XX:FullGCALotInterval=120 TestFullGCALot

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