Merge
This commit is contained in:
commit
b809fe8c7b
@ -289,3 +289,4 @@ f7c11da0b0481d49cc7a65a453336c108191e821 jdk9-b42
|
|||||||
8994f5d87b3bb5e8d317d4e8ccb326da1a73684a jdk9-b44
|
8994f5d87b3bb5e8d317d4e8ccb326da1a73684a jdk9-b44
|
||||||
3dd628fde2086218d548841022ee8436b6b88185 jdk9-b45
|
3dd628fde2086218d548841022ee8436b6b88185 jdk9-b45
|
||||||
12f1e276447bcc81516e85367d53e4f08897049d jdk9-b46
|
12f1e276447bcc81516e85367d53e4f08897049d jdk9-b46
|
||||||
|
b6cca3e6175a69f39e5799b7349ddb0176630291 jdk9-b47
|
||||||
|
@ -289,3 +289,4 @@ e27c725d6c9d155667b35255f442d4ceb8c3c084 jdk9-b40
|
|||||||
1f57bd728c9e6865ccb9d43ccd80a1c11230a32f jdk9-b44
|
1f57bd728c9e6865ccb9d43ccd80a1c11230a32f jdk9-b44
|
||||||
9e3f2bed80c0e5a84a256ce41f1d10c5ade48466 jdk9-b45
|
9e3f2bed80c0e5a84a256ce41f1d10c5ade48466 jdk9-b45
|
||||||
326f2068b4a4c05e2fa27d6acf93eba7b54b090d jdk9-b46
|
326f2068b4a4c05e2fa27d6acf93eba7b54b090d jdk9-b46
|
||||||
|
ee8447ca632e1d39180b4767c749db101bff7314 jdk9-b47
|
||||||
|
@ -449,3 +449,4 @@ c363a8b87e477ee45d6d3cb2a36cb365141bc596 jdk9-b38
|
|||||||
43a44b56dca61a4d766a20f0528fdd8b5ceff873 jdk9-b44
|
43a44b56dca61a4d766a20f0528fdd8b5ceff873 jdk9-b44
|
||||||
5dc8184af1e2bb30b0103113d1f1a58a21a80c37 jdk9-b45
|
5dc8184af1e2bb30b0103113d1f1a58a21a80c37 jdk9-b45
|
||||||
a184ee1d717297bd35b7c3e35393e137921a3ed2 jdk9-b46
|
a184ee1d717297bd35b7c3e35393e137921a3ed2 jdk9-b46
|
||||||
|
3b241fb72b8925b75941d612db762a6d5da66d02 jdk9-b47
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright 2012, 2013 SAP AG. All rights reserved.
|
* Copyright 2012, 2015 SAP AG. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -284,19 +284,20 @@ class Assembler : public AbstractAssembler {
|
|||||||
MTCTR_OPCODE = (MTSPR_OPCODE | 9 << SPR_0_4_SHIFT),
|
MTCTR_OPCODE = (MTSPR_OPCODE | 9 << SPR_0_4_SHIFT),
|
||||||
MFCTR_OPCODE = (MFSPR_OPCODE | 9 << SPR_0_4_SHIFT),
|
MFCTR_OPCODE = (MFSPR_OPCODE | 9 << SPR_0_4_SHIFT),
|
||||||
|
|
||||||
MTTFHAR_OPCODE = (MTSPR_OPCODE | 128 << SPR_0_4_SHIFT),
|
// Attention: Higher and lower half are inserted in reversed order.
|
||||||
MFTFHAR_OPCODE = (MFSPR_OPCODE | 128 << SPR_0_4_SHIFT),
|
MTTFHAR_OPCODE = (MTSPR_OPCODE | 4 << SPR_5_9_SHIFT | 0 << SPR_0_4_SHIFT),
|
||||||
MTTFIAR_OPCODE = (MTSPR_OPCODE | 129 << SPR_0_4_SHIFT),
|
MFTFHAR_OPCODE = (MFSPR_OPCODE | 4 << SPR_5_9_SHIFT | 0 << SPR_0_4_SHIFT),
|
||||||
MFTFIAR_OPCODE = (MFSPR_OPCODE | 129 << SPR_0_4_SHIFT),
|
MTTFIAR_OPCODE = (MTSPR_OPCODE | 4 << SPR_5_9_SHIFT | 1 << SPR_0_4_SHIFT),
|
||||||
MTTEXASR_OPCODE = (MTSPR_OPCODE | 130 << SPR_0_4_SHIFT),
|
MFTFIAR_OPCODE = (MFSPR_OPCODE | 4 << SPR_5_9_SHIFT | 1 << SPR_0_4_SHIFT),
|
||||||
MFTEXASR_OPCODE = (MFSPR_OPCODE | 130 << SPR_0_4_SHIFT),
|
MTTEXASR_OPCODE = (MTSPR_OPCODE | 4 << SPR_5_9_SHIFT | 2 << SPR_0_4_SHIFT),
|
||||||
MTTEXASRU_OPCODE = (MTSPR_OPCODE | 131 << SPR_0_4_SHIFT),
|
MFTEXASR_OPCODE = (MFSPR_OPCODE | 4 << SPR_5_9_SHIFT | 2 << SPR_0_4_SHIFT),
|
||||||
MFTEXASRU_OPCODE = (MFSPR_OPCODE | 131 << SPR_0_4_SHIFT),
|
MTTEXASRU_OPCODE = (MTSPR_OPCODE | 4 << SPR_5_9_SHIFT | 3 << SPR_0_4_SHIFT),
|
||||||
|
MFTEXASRU_OPCODE = (MFSPR_OPCODE | 4 << SPR_5_9_SHIFT | 3 << SPR_0_4_SHIFT),
|
||||||
|
|
||||||
MTVRSAVE_OPCODE = (MTSPR_OPCODE | 256 << SPR_0_4_SHIFT),
|
MTVRSAVE_OPCODE = (MTSPR_OPCODE | 8 << SPR_5_9_SHIFT | 0 << SPR_0_4_SHIFT),
|
||||||
MFVRSAVE_OPCODE = (MFSPR_OPCODE | 256 << SPR_0_4_SHIFT),
|
MFVRSAVE_OPCODE = (MFSPR_OPCODE | 8 << SPR_5_9_SHIFT | 0 << SPR_0_4_SHIFT),
|
||||||
|
|
||||||
MFTB_OPCODE = (MFSPR_OPCODE | 268 << SPR_0_4_SHIFT),
|
MFTB_OPCODE = (MFSPR_OPCODE | 8 << SPR_5_9_SHIFT | 12 << SPR_0_4_SHIFT),
|
||||||
|
|
||||||
MTCRF_OPCODE = (31u << OPCODE_SHIFT | 144u << 1),
|
MTCRF_OPCODE = (31u << OPCODE_SHIFT | 144u << 1),
|
||||||
MFCR_OPCODE = (31u << OPCODE_SHIFT | 19u << 1),
|
MFCR_OPCODE = (31u << OPCODE_SHIFT | 19u << 1),
|
||||||
@ -1494,6 +1495,26 @@ class Assembler : public AbstractAssembler {
|
|||||||
inline void mftexasr(Register d);
|
inline void mftexasr(Register d);
|
||||||
inline void mftexasru(Register d);
|
inline void mftexasru(Register d);
|
||||||
|
|
||||||
|
// TEXASR bit description
|
||||||
|
enum transaction_failure_reason {
|
||||||
|
// Upper half (TEXASRU):
|
||||||
|
tm_failure_persistent = 7, // The failure is likely to recur on each execution.
|
||||||
|
tm_disallowed = 8, // The instruction is not permitted.
|
||||||
|
tm_nesting_of = 9, // The maximum transaction level was exceeded.
|
||||||
|
tm_footprint_of = 10, // The tracking limit for transactional storage accesses was exceeded.
|
||||||
|
tm_self_induced_cf = 11, // A self-induced conflict occurred in Suspended state.
|
||||||
|
tm_non_trans_cf = 12, // A conflict occurred with a non-transactional access by another processor.
|
||||||
|
tm_trans_cf = 13, // A conflict occurred with another transaction.
|
||||||
|
tm_translation_cf = 14, // A conflict occurred with a TLB invalidation.
|
||||||
|
tm_inst_fetch_cf = 16, // An instruction fetch was performed from a block that was previously written transactionally.
|
||||||
|
tm_tabort = 31, // Termination was caused by the execution of an abort instruction.
|
||||||
|
// Lower half:
|
||||||
|
tm_suspended = 32, // Failure was recorded in Suspended state.
|
||||||
|
tm_failure_summary = 36, // Failure has been detected and recorded.
|
||||||
|
tm_tfiar_exact = 37, // Value in the TFIAR is exact.
|
||||||
|
tm_rot = 38, // Rollback-only transaction.
|
||||||
|
};
|
||||||
|
|
||||||
// PPC 1, section 2.4.1 Branch Instructions
|
// PPC 1, section 2.4.1 Branch Instructions
|
||||||
inline void b( address a, relocInfo::relocType rt = relocInfo::none);
|
inline void b( address a, relocInfo::relocType rt = relocInfo::none);
|
||||||
inline void b( Label& L);
|
inline void b( Label& L);
|
||||||
@ -1581,6 +1602,7 @@ class Assembler : public AbstractAssembler {
|
|||||||
inline void bnectrl(ConditionRegister crx, relocInfo::relocType rt = relocInfo::none);
|
inline void bnectrl(ConditionRegister crx, relocInfo::relocType rt = relocInfo::none);
|
||||||
|
|
||||||
// condition register logic instructions
|
// condition register logic instructions
|
||||||
|
// NOTE: There's a preferred form: d and s2 should point into the same condition register.
|
||||||
inline void crand( int d, int s1, int s2);
|
inline void crand( int d, int s1, int s2);
|
||||||
inline void crnand(int d, int s1, int s2);
|
inline void crnand(int d, int s1, int s2);
|
||||||
inline void cror( int d, int s1, int s2);
|
inline void cror( int d, int s1, int s2);
|
||||||
@ -1590,6 +1612,19 @@ class Assembler : public AbstractAssembler {
|
|||||||
inline void crandc(int d, int s1, int s2);
|
inline void crandc(int d, int s1, int s2);
|
||||||
inline void crorc( int d, int s1, int s2);
|
inline void crorc( int d, int s1, int s2);
|
||||||
|
|
||||||
|
// More convenient version.
|
||||||
|
int condition_register_bit(ConditionRegister cr, Condition c) {
|
||||||
|
return 4 * (int)(intptr_t)cr + c;
|
||||||
|
}
|
||||||
|
void crand( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc);
|
||||||
|
void crnand(ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc);
|
||||||
|
void cror( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc);
|
||||||
|
void crxor( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc);
|
||||||
|
void crnor( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc);
|
||||||
|
void creqv( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc);
|
||||||
|
void crandc(ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc);
|
||||||
|
void crorc( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc);
|
||||||
|
|
||||||
// icache and dcache related instructions
|
// icache and dcache related instructions
|
||||||
inline void icbi( Register s1, Register s2);
|
inline void icbi( Register s1, Register s2);
|
||||||
//inline void dcba(Register s1, Register s2); // Instruction for embedded processor only.
|
//inline void dcba(Register s1, Register s2); // Instruction for embedded processor only.
|
||||||
@ -1673,6 +1708,10 @@ class Assembler : public AbstractAssembler {
|
|||||||
inline void smt_prio_low();
|
inline void smt_prio_low();
|
||||||
inline void smt_prio_medium_low();
|
inline void smt_prio_medium_low();
|
||||||
inline void smt_prio_medium();
|
inline void smt_prio_medium();
|
||||||
|
// >= Power7
|
||||||
|
inline void smt_yield();
|
||||||
|
inline void smt_mdoio();
|
||||||
|
inline void smt_mdoom();
|
||||||
|
|
||||||
// trap instructions
|
// trap instructions
|
||||||
inline void twi_0(Register a); // for load with acquire semantics use load+twi_0+isync (trap can't occur)
|
inline void twi_0(Register a); // for load with acquire semantics use load+twi_0+isync (trap can't occur)
|
||||||
@ -1958,6 +1997,7 @@ class Assembler : public AbstractAssembler {
|
|||||||
inline void tbeginrot_(); // R=1 Rollback-Only Transaction
|
inline void tbeginrot_(); // R=1 Rollback-Only Transaction
|
||||||
inline void tend_(); // A=0
|
inline void tend_(); // A=0
|
||||||
inline void tendall_(); // A=1
|
inline void tendall_(); // A=1
|
||||||
|
inline void tabort_();
|
||||||
inline void tabort_(Register a);
|
inline void tabort_(Register a);
|
||||||
inline void tabortwc_(int t, Register a, Register b);
|
inline void tabortwc_(int t, Register a, Register b);
|
||||||
inline void tabortwci_(int t, Register a, int si);
|
inline void tabortwci_(int t, Register a, int si);
|
||||||
@ -1967,6 +2007,10 @@ class Assembler : public AbstractAssembler {
|
|||||||
inline void tresume_(); // tsr with L=1
|
inline void tresume_(); // tsr with L=1
|
||||||
inline void tcheck(int f);
|
inline void tcheck(int f);
|
||||||
|
|
||||||
|
static bool is_tbegin(int x) {
|
||||||
|
return TBEGIN_OPCODE == (x & (0x3f << OPCODE_SHIFT | 0x3ff << 1));
|
||||||
|
}
|
||||||
|
|
||||||
// The following encoders use r0 as second operand. These instructions
|
// The following encoders use r0 as second operand. These instructions
|
||||||
// read r0 as '0'.
|
// read r0 as '0'.
|
||||||
inline void lwzx( Register d, Register s2);
|
inline void lwzx( Register d, Register s2);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright 2012, 2014 SAP AG. All rights reserved.
|
* Copyright 2012, 2015 SAP AG. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -453,6 +453,48 @@ inline void Assembler::creqv( int d, int s1, int s2) { emit_int32(CREQV_OPCODE
|
|||||||
inline void Assembler::crandc(int d, int s1, int s2) { emit_int32(CRANDC_OPCODE | bt(d) | ba(s1) | bb(s2)); }
|
inline void Assembler::crandc(int d, int s1, int s2) { emit_int32(CRANDC_OPCODE | bt(d) | ba(s1) | bb(s2)); }
|
||||||
inline void Assembler::crorc( int d, int s1, int s2) { emit_int32(CRORC_OPCODE | bt(d) | ba(s1) | bb(s2)); }
|
inline void Assembler::crorc( int d, int s1, int s2) { emit_int32(CRORC_OPCODE | bt(d) | ba(s1) | bb(s2)); }
|
||||||
|
|
||||||
|
// More convenient version.
|
||||||
|
inline void Assembler::crand( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) {
|
||||||
|
int dst_bit = condition_register_bit(crdst, cdst),
|
||||||
|
src_bit = condition_register_bit(crsrc, csrc);
|
||||||
|
crand(dst_bit, src_bit, dst_bit);
|
||||||
|
}
|
||||||
|
inline void Assembler::crnand(ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) {
|
||||||
|
int dst_bit = condition_register_bit(crdst, cdst),
|
||||||
|
src_bit = condition_register_bit(crsrc, csrc);
|
||||||
|
crnand(dst_bit, src_bit, dst_bit);
|
||||||
|
}
|
||||||
|
inline void Assembler::cror( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) {
|
||||||
|
int dst_bit = condition_register_bit(crdst, cdst),
|
||||||
|
src_bit = condition_register_bit(crsrc, csrc);
|
||||||
|
cror(dst_bit, src_bit, dst_bit);
|
||||||
|
}
|
||||||
|
inline void Assembler::crxor( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) {
|
||||||
|
int dst_bit = condition_register_bit(crdst, cdst),
|
||||||
|
src_bit = condition_register_bit(crsrc, csrc);
|
||||||
|
crxor(dst_bit, src_bit, dst_bit);
|
||||||
|
}
|
||||||
|
inline void Assembler::crnor( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) {
|
||||||
|
int dst_bit = condition_register_bit(crdst, cdst),
|
||||||
|
src_bit = condition_register_bit(crsrc, csrc);
|
||||||
|
crnor(dst_bit, src_bit, dst_bit);
|
||||||
|
}
|
||||||
|
inline void Assembler::creqv( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) {
|
||||||
|
int dst_bit = condition_register_bit(crdst, cdst),
|
||||||
|
src_bit = condition_register_bit(crsrc, csrc);
|
||||||
|
creqv(dst_bit, src_bit, dst_bit);
|
||||||
|
}
|
||||||
|
inline void Assembler::crandc(ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) {
|
||||||
|
int dst_bit = condition_register_bit(crdst, cdst),
|
||||||
|
src_bit = condition_register_bit(crsrc, csrc);
|
||||||
|
crandc(dst_bit, src_bit, dst_bit);
|
||||||
|
}
|
||||||
|
inline void Assembler::crorc( ConditionRegister crdst, Condition cdst, ConditionRegister crsrc, Condition csrc) {
|
||||||
|
int dst_bit = condition_register_bit(crdst, cdst),
|
||||||
|
src_bit = condition_register_bit(crsrc, csrc);
|
||||||
|
crorc(dst_bit, src_bit, dst_bit);
|
||||||
|
}
|
||||||
|
|
||||||
// Conditional move (>= Power7)
|
// Conditional move (>= Power7)
|
||||||
inline void Assembler::isel(Register d, ConditionRegister cr, Condition cc, bool inv, Register a, Register b) {
|
inline void Assembler::isel(Register d, ConditionRegister cr, Condition cc, bool inv, Register a, Register b) {
|
||||||
if (b == noreg) {
|
if (b == noreg) {
|
||||||
@ -516,6 +558,10 @@ inline void Assembler::smt_prio_medium_low() { Assembler::or_unchecked(R6, R6,
|
|||||||
inline void Assembler::smt_prio_medium() { Assembler::or_unchecked(R2, R2, R2); }
|
inline void Assembler::smt_prio_medium() { Assembler::or_unchecked(R2, R2, R2); }
|
||||||
inline void Assembler::smt_prio_medium_high() { Assembler::or_unchecked(R5, R5, R5); }
|
inline void Assembler::smt_prio_medium_high() { Assembler::or_unchecked(R5, R5, R5); }
|
||||||
inline void Assembler::smt_prio_high() { Assembler::or_unchecked(R3, R3, R3); }
|
inline void Assembler::smt_prio_high() { Assembler::or_unchecked(R3, R3, R3); }
|
||||||
|
// >= Power7
|
||||||
|
inline void Assembler::smt_yield() { Assembler::or_unchecked(R27, R27, R27); }
|
||||||
|
inline void Assembler::smt_mdoio() { Assembler::or_unchecked(R29, R29, R29); }
|
||||||
|
inline void Assembler::smt_mdoom() { Assembler::or_unchecked(R30, R30, R30); }
|
||||||
|
|
||||||
inline void Assembler::twi_0(Register a) { twi_unchecked(0, a, 0);}
|
inline void Assembler::twi_0(Register a) { twi_unchecked(0, a, 0);}
|
||||||
|
|
||||||
@ -778,7 +824,8 @@ inline void Assembler::tbegin_() { emit_int32( TB
|
|||||||
inline void Assembler::tbeginrot_() { emit_int32( TBEGIN_OPCODE | /*R=1*/ 1u << (31-10) | rc(1)); }
|
inline void Assembler::tbeginrot_() { emit_int32( TBEGIN_OPCODE | /*R=1*/ 1u << (31-10) | rc(1)); }
|
||||||
inline void Assembler::tend_() { emit_int32( TEND_OPCODE | rc(1)); }
|
inline void Assembler::tend_() { emit_int32( TEND_OPCODE | rc(1)); }
|
||||||
inline void Assembler::tendall_() { emit_int32( TEND_OPCODE | /*A=1*/ 1u << (31-6) | rc(1)); }
|
inline void Assembler::tendall_() { emit_int32( TEND_OPCODE | /*A=1*/ 1u << (31-6) | rc(1)); }
|
||||||
inline void Assembler::tabort_(Register a) { emit_int32( TABORT_OPCODE | ra(a) | rc(1)); }
|
inline void Assembler::tabort_() { emit_int32( TABORT_OPCODE | rc(1)); }
|
||||||
|
inline void Assembler::tabort_(Register a) { assert(a != R0, "r0 not allowed"); emit_int32( TABORT_OPCODE | ra(a) | rc(1)); }
|
||||||
inline void Assembler::tabortwc_(int t, Register a, Register b) { emit_int32( TABORTWC_OPCODE | to(t) | ra(a) | rb(b) | rc(1)); }
|
inline void Assembler::tabortwc_(int t, Register a, Register b) { emit_int32( TABORTWC_OPCODE | to(t) | ra(a) | rb(b) | rc(1)); }
|
||||||
inline void Assembler::tabortwci_(int t, Register a, int si) { emit_int32( TABORTWCI_OPCODE | to(t) | ra(a) | sh1620(si) | rc(1)); }
|
inline void Assembler::tabortwci_(int t, Register a, int si) { emit_int32( TABORTWCI_OPCODE | to(t) | ra(a) | sh1620(si) | rc(1)); }
|
||||||
inline void Assembler::tabortdc_(int t, Register a, Register b) { emit_int32( TABORTDC_OPCODE | to(t) | ra(a) | rb(b) | rc(1)); }
|
inline void Assembler::tabortdc_(int t, Register a, Register b) { emit_int32( TABORTDC_OPCODE | to(t) | ra(a) | rb(b) | rc(1)); }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright 2012, 2014 SAP AG. All rights reserved.
|
* Copyright 2012, 2015 SAP AG. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -1712,7 +1712,7 @@ void InterpreterMacroAssembler::profile_obj_type(Register obj, Register mdo_addr
|
|||||||
andi_(R0, klass, TypeEntries::type_unknown);
|
andi_(R0, klass, TypeEntries::type_unknown);
|
||||||
// Already unknown. Nothing to do anymore.
|
// Already unknown. Nothing to do anymore.
|
||||||
//bne(CCR0, do_nothing);
|
//bne(CCR0, do_nothing);
|
||||||
crorc(/*CCR0 eq*/2, /*CCR1 eq*/4+2, /*CCR0 eq*/2); // cr0 eq = cr1 eq or cr0 ne
|
crorc(CCR0, Assembler::equal, CCR1, Assembler::equal); // cr0 eq = cr1 eq or cr0 ne
|
||||||
beq(CCR0, do_nothing);
|
beq(CCR0, do_nothing);
|
||||||
|
|
||||||
clrrdi_(R0, tmp, exact_log2(-TypeEntries::type_mask));
|
clrrdi_(R0, tmp, exact_log2(-TypeEntries::type_mask));
|
||||||
@ -1826,9 +1826,9 @@ void InterpreterMacroAssembler::profile_return_type(Register ret, Register tmp1,
|
|||||||
lbz(tmp2, Method::intrinsic_id_offset_in_bytes(), R19_method);
|
lbz(tmp2, Method::intrinsic_id_offset_in_bytes(), R19_method);
|
||||||
cmpwi(CCR0, tmp1, Bytecodes::_invokedynamic);
|
cmpwi(CCR0, tmp1, Bytecodes::_invokedynamic);
|
||||||
cmpwi(CCR1, tmp1, Bytecodes::_invokehandle);
|
cmpwi(CCR1, tmp1, Bytecodes::_invokehandle);
|
||||||
cror(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2);
|
cror(CCR0, Assembler::equal, CCR1, Assembler::equal);
|
||||||
cmpwi(CCR1, tmp2, vmIntrinsics::_compiledLambdaForm);
|
cmpwi(CCR1, tmp2, vmIntrinsics::_compiledLambdaForm);
|
||||||
cror(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2);
|
cror(CCR0, Assembler::equal, CCR1, Assembler::equal);
|
||||||
bne(CCR0, profile_continue);
|
bne(CCR0, profile_continue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright 2012, 2014 SAP AG. All rights reserved.
|
* Copyright 2012, 2015 SAP AG. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -1079,7 +1079,7 @@ class StubGenerator: public StubCodeGenerator {
|
|||||||
__ sldi(tmp2, R5_ARG3, log2_elem_size); // size in bytes
|
__ sldi(tmp2, R5_ARG3, log2_elem_size); // size in bytes
|
||||||
__ cmpld(CCR0, R3_ARG1, R4_ARG2); // Use unsigned comparison!
|
__ cmpld(CCR0, R3_ARG1, R4_ARG2); // Use unsigned comparison!
|
||||||
__ cmpld(CCR1, tmp1, tmp2);
|
__ cmpld(CCR1, tmp1, tmp2);
|
||||||
__ crand(/*CCR0 lt*/0, /*CCR1 lt*/4+0, /*CCR0 lt*/0);
|
__ crand(CCR0, Assembler::less, CCR1, Assembler::less);
|
||||||
__ blt(CCR0, l_overlap); // Src before dst and distance smaller than size.
|
__ blt(CCR0, l_overlap); // Src before dst and distance smaller than size.
|
||||||
|
|
||||||
// need to copy forwards
|
// need to copy forwards
|
||||||
|
@ -264,11 +264,11 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label*
|
|||||||
__ cmpdi(CCR0, Rmdo, 0);
|
__ cmpdi(CCR0, Rmdo, 0);
|
||||||
__ beq(CCR0, no_mdo);
|
__ beq(CCR0, no_mdo);
|
||||||
|
|
||||||
// Increment backedge counter in the MDO.
|
// Increment invocation counter in the MDO.
|
||||||
const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
|
const int mdo_ic_offs = in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
|
||||||
__ lwz(Rscratch2, mdo_bc_offs, Rmdo);
|
__ lwz(Rscratch2, mdo_ic_offs, Rmdo);
|
||||||
__ addi(Rscratch2, Rscratch2, increment);
|
__ addi(Rscratch2, Rscratch2, increment);
|
||||||
__ stw(Rscratch2, mdo_bc_offs, Rmdo);
|
__ stw(Rscratch2, mdo_ic_offs, Rmdo);
|
||||||
__ load_const_optimized(Rscratch1, mask, R0);
|
__ load_const_optimized(Rscratch1, mask, R0);
|
||||||
__ and_(Rscratch1, Rscratch2, Rscratch1);
|
__ and_(Rscratch1, Rscratch2, Rscratch1);
|
||||||
__ bne(CCR0, done);
|
__ bne(CCR0, done);
|
||||||
@ -276,12 +276,12 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Increment counter in MethodCounters*.
|
// Increment counter in MethodCounters*.
|
||||||
const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
|
const int mo_ic_offs = in_bytes(MethodCounters::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
|
||||||
__ bind(no_mdo);
|
__ bind(no_mdo);
|
||||||
__ get_method_counters(R19_method, R3_counters, done);
|
__ get_method_counters(R19_method, R3_counters, done);
|
||||||
__ lwz(Rscratch2, mo_bc_offs, R3_counters);
|
__ lwz(Rscratch2, mo_ic_offs, R3_counters);
|
||||||
__ addi(Rscratch2, Rscratch2, increment);
|
__ addi(Rscratch2, Rscratch2, increment);
|
||||||
__ stw(Rscratch2, mo_bc_offs, R3_counters);
|
__ stw(Rscratch2, mo_ic_offs, R3_counters);
|
||||||
__ load_const_optimized(Rscratch1, mask, R0);
|
__ load_const_optimized(Rscratch1, mask, R0);
|
||||||
__ and_(Rscratch1, Rscratch2, Rscratch1);
|
__ and_(Rscratch1, Rscratch2, Rscratch1);
|
||||||
__ beq(CCR0, *overflow);
|
__ beq(CCR0, *overflow);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright 2013, 2014 SAP AG. All rights reserved.
|
* Copyright 2013, 2015 SAP AG. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -335,11 +335,11 @@ void TemplateTable::ldc(bool wide) {
|
|||||||
|
|
||||||
__ cmpwi(CCR0, Rscratch2, JVM_CONSTANT_UnresolvedClass); // Unresolved class?
|
__ cmpwi(CCR0, Rscratch2, JVM_CONSTANT_UnresolvedClass); // Unresolved class?
|
||||||
__ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_UnresolvedClassInError); // Unresolved class in error state?
|
__ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_UnresolvedClassInError); // Unresolved class in error state?
|
||||||
__ cror(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2);
|
__ cror(CCR0, Assembler::equal, CCR1, Assembler::equal);
|
||||||
|
|
||||||
// Resolved class - need to call vm to get java mirror of the class.
|
// Resolved class - need to call vm to get java mirror of the class.
|
||||||
__ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_Class);
|
__ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_Class);
|
||||||
__ crnor(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); // Neither resolved class nor unresolved case from above?
|
__ crnor(CCR0, Assembler::equal, CCR1, Assembler::equal); // Neither resolved class nor unresolved case from above?
|
||||||
__ beq(CCR0, notClass);
|
__ beq(CCR0, notClass);
|
||||||
|
|
||||||
__ li(R4, wide ? 1 : 0);
|
__ li(R4, wide ? 1 : 0);
|
||||||
@ -2611,7 +2611,7 @@ void TemplateTable::jvmti_post_field_mod(Register Rcache, Register Rscratch, boo
|
|||||||
__ cmpwi(CCR0, Rflags, ltos);
|
__ cmpwi(CCR0, Rflags, ltos);
|
||||||
__ cmpwi(CCR1, Rflags, dtos);
|
__ cmpwi(CCR1, Rflags, dtos);
|
||||||
__ addi(base, R15_esp, Interpreter::expr_offset_in_bytes(1));
|
__ addi(base, R15_esp, Interpreter::expr_offset_in_bytes(1));
|
||||||
__ crnor(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2);
|
__ crnor(CCR0, Assembler::equal, CCR1, Assembler::equal);
|
||||||
__ beq(CCR0, is_one_slot);
|
__ beq(CCR0, is_one_slot);
|
||||||
__ addi(base, R15_esp, Interpreter::expr_offset_in_bytes(2));
|
__ addi(base, R15_esp, Interpreter::expr_offset_in_bytes(2));
|
||||||
__ bind(is_one_slot);
|
__ bind(is_one_slot);
|
||||||
@ -3563,7 +3563,7 @@ void TemplateTable::_new() {
|
|||||||
// Make sure klass does not have has_finalizer, or is abstract, or interface or java/lang/Class.
|
// Make sure klass does not have has_finalizer, or is abstract, or interface or java/lang/Class.
|
||||||
__ andi_(R0, Rinstance_size, Klass::_lh_instance_slow_path_bit); // slow path bit equals 0?
|
__ andi_(R0, Rinstance_size, Klass::_lh_instance_slow_path_bit); // slow path bit equals 0?
|
||||||
|
|
||||||
__ crnand(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); // slow path bit set or not fully initialized?
|
__ crnand(CCR0, Assembler::equal, CCR1, Assembler::equal); // slow path bit set or not fully initialized?
|
||||||
__ beq(CCR0, Lslow_case);
|
__ beq(CCR0, Lslow_case);
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
@ -3184,7 +3184,24 @@ void MacroAssembler::pow_or_exp(bool is_exp, int num_fpu_regs_in_use) {
|
|||||||
jmp(done);
|
jmp(done);
|
||||||
} else {
|
} else {
|
||||||
// Stack: X Y
|
// Stack: X Y
|
||||||
Label x_negative, y_odd;
|
Label x_negative, y_not_2;
|
||||||
|
|
||||||
|
static double two = 2.0;
|
||||||
|
ExternalAddress two_addr((address)&two);
|
||||||
|
|
||||||
|
// constant maybe too far on 64 bit
|
||||||
|
lea(tmp2, two_addr);
|
||||||
|
fld_d(Address(tmp2, 0)); // Stack: 2 X Y
|
||||||
|
fcmp(tmp, 2, true, false); // Stack: X Y
|
||||||
|
jcc(Assembler::parity, y_not_2);
|
||||||
|
jcc(Assembler::notEqual, y_not_2);
|
||||||
|
|
||||||
|
fxch(); fpop(); // Stack: X
|
||||||
|
fmul(0); // Stack: X*X
|
||||||
|
|
||||||
|
jmp(done);
|
||||||
|
|
||||||
|
bind(y_not_2);
|
||||||
|
|
||||||
fldz(); // Stack: 0 X Y
|
fldz(); // Stack: 0 X Y
|
||||||
fcmp(tmp, 1, true, false); // Stack: X Y
|
fcmp(tmp, 1, true, false); // Stack: X Y
|
||||||
|
@ -197,7 +197,38 @@ static pid_t filename_to_pid(const char* filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// check if the given path is considered a secure directory for
|
// Check if the given statbuf is considered a secure directory for
|
||||||
|
// the backing store files. Returns true if the directory is considered
|
||||||
|
// a secure location. Returns false if the statbuf is a symbolic link or
|
||||||
|
// if an error occurred.
|
||||||
|
//
|
||||||
|
static bool is_statbuf_secure(struct stat *statp) {
|
||||||
|
if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) {
|
||||||
|
// The path represents a link or some non-directory file type,
|
||||||
|
// which is not what we expected. Declare it insecure.
|
||||||
|
//
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// We have an existing directory, check if the permissions are safe.
|
||||||
|
//
|
||||||
|
if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) {
|
||||||
|
// The directory is open for writing and could be subjected
|
||||||
|
// to a symlink or a hard link attack. Declare it insecure.
|
||||||
|
//
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// See if the uid of the directory matches the effective uid of the process.
|
||||||
|
//
|
||||||
|
if (statp->st_uid != geteuid()) {
|
||||||
|
// The directory was not created by this user, declare it insecure.
|
||||||
|
//
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check if the given path is considered a secure directory for
|
||||||
// the backing store files. Returns true if the directory exists
|
// the backing store files. Returns true if the directory exists
|
||||||
// and is considered a secure location. Returns false if the path
|
// and is considered a secure location. Returns false if the path
|
||||||
// is a symbolic link or if an error occurred.
|
// is a symbolic link or if an error occurred.
|
||||||
@ -211,27 +242,185 @@ static bool is_directory_secure(const char* path) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the path exists, now check it's mode
|
// The path exists, see if it is secure.
|
||||||
if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) {
|
return is_statbuf_secure(&statbuf);
|
||||||
// the path represents a link or some non-directory file type,
|
}
|
||||||
// which is not what we expected. declare it insecure.
|
|
||||||
//
|
|
||||||
|
// Check if the given directory file descriptor is considered a secure
|
||||||
|
// directory for the backing store files. Returns true if the directory
|
||||||
|
// exists and is considered a secure location. Returns false if the path
|
||||||
|
// is a symbolic link or if an error occurred.
|
||||||
|
//
|
||||||
|
static bool is_dirfd_secure(int dir_fd) {
|
||||||
|
struct stat statbuf;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
RESTARTABLE(::fstat(dir_fd, &statbuf), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// we have an existing directory, check if the permissions are safe.
|
// The path exists, now check its mode.
|
||||||
//
|
return is_statbuf_secure(&statbuf);
|
||||||
if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
|
}
|
||||||
// the directory is open for writing and could be subjected
|
|
||||||
// to a symlnk attack. declare it insecure.
|
|
||||||
//
|
// Check to make sure fd1 and fd2 are referencing the same file system object.
|
||||||
return false;
|
//
|
||||||
|
static bool is_same_fsobject(int fd1, int fd2) {
|
||||||
|
struct stat statbuf1;
|
||||||
|
struct stat statbuf2;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
RESTARTABLE(::fstat(fd1, &statbuf1), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RESTARTABLE(::fstat(fd2, &statbuf2), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((statbuf1.st_ino == statbuf2.st_ino) &&
|
||||||
|
(statbuf1.st_dev == statbuf2.st_dev)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Open the directory of the given path and validate it.
|
||||||
|
// Return a DIR * of the open directory.
|
||||||
|
//
|
||||||
|
static DIR *open_directory_secure(const char* dirname) {
|
||||||
|
// Open the directory using open() so that it can be verified
|
||||||
|
// to be secure by calling is_dirfd_secure(), opendir() and then check
|
||||||
|
// to see if they are the same file system object. This method does not
|
||||||
|
// introduce a window of opportunity for the directory to be attacked that
|
||||||
|
// calling opendir() and is_directory_secure() does.
|
||||||
|
int result;
|
||||||
|
DIR *dirp = NULL;
|
||||||
|
RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
// Directory doesn't exist or is a symlink, so there is nothing to cleanup.
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
if (errno == ELOOP) {
|
||||||
|
warning("directory %s is a symlink and is not secure\n", dirname);
|
||||||
|
} else {
|
||||||
|
warning("could not open directory %s: %s\n", dirname, strerror(errno));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
int fd = result;
|
||||||
|
|
||||||
|
// Determine if the open directory is secure.
|
||||||
|
if (!is_dirfd_secure(fd)) {
|
||||||
|
// The directory is not a secure directory.
|
||||||
|
os::close(fd);
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the directory.
|
||||||
|
dirp = ::opendir(dirname);
|
||||||
|
if (dirp == NULL) {
|
||||||
|
// The directory doesn't exist, close fd and return.
|
||||||
|
os::close(fd);
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to make sure fd and dirp are referencing the same file system object.
|
||||||
|
if (!is_same_fsobject(fd, dirfd(dirp))) {
|
||||||
|
// The directory is not secure.
|
||||||
|
os::close(fd);
|
||||||
|
os::closedir(dirp);
|
||||||
|
dirp = NULL;
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close initial open now that we know directory is secure
|
||||||
|
os::close(fd);
|
||||||
|
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: The code below uses fchdir(), open() and unlink() because
|
||||||
|
// fdopendir(), openat() and unlinkat() are not supported on all
|
||||||
|
// versions. Once the support for fdopendir(), openat() and unlinkat()
|
||||||
|
// is available on all supported versions the code can be changed
|
||||||
|
// to use these functions.
|
||||||
|
|
||||||
|
// Open the directory of the given path, validate it and set the
|
||||||
|
// current working directory to it.
|
||||||
|
// Return a DIR * of the open directory and the saved cwd fd.
|
||||||
|
//
|
||||||
|
static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) {
|
||||||
|
|
||||||
|
// Open the directory.
|
||||||
|
DIR* dirp = open_directory_secure(dirname);
|
||||||
|
if (dirp == NULL) {
|
||||||
|
// Directory doesn't exist or is insecure, so there is nothing to cleanup.
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
int fd = dirfd(dirp);
|
||||||
|
|
||||||
|
// Open a fd to the cwd and save it off.
|
||||||
|
int result;
|
||||||
|
RESTARTABLE(::open(".", O_RDONLY), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
*saved_cwd_fd = -1;
|
||||||
|
} else {
|
||||||
|
*saved_cwd_fd = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the current directory to dirname by using the fd of the directory.
|
||||||
|
result = fchdir(fd);
|
||||||
|
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the directory and restore the current working directory.
|
||||||
|
//
|
||||||
|
static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) {
|
||||||
|
|
||||||
|
int result;
|
||||||
|
// If we have a saved cwd change back to it and close the fd.
|
||||||
|
if (saved_cwd_fd != -1) {
|
||||||
|
result = fchdir(saved_cwd_fd);
|
||||||
|
::close(saved_cwd_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the directory.
|
||||||
|
os::closedir(dirp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the given file descriptor is considered a secure.
|
||||||
|
//
|
||||||
|
static bool is_file_secure(int fd, const char *filename) {
|
||||||
|
|
||||||
|
int result;
|
||||||
|
struct stat statbuf;
|
||||||
|
|
||||||
|
// Determine if the file is secure.
|
||||||
|
RESTARTABLE(::fstat(fd, &statbuf), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
warning("fstat failed on %s: %s\n", filename, strerror(errno));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (statbuf.st_nlink > 1) {
|
||||||
|
// A file with multiple links is not expected.
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
warning("file %s has multiple links\n", filename);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// return the user name for the given user id
|
// return the user name for the given user id
|
||||||
//
|
//
|
||||||
// the caller is expected to free the allocated memory.
|
// the caller is expected to free the allocated memory.
|
||||||
@ -317,9 +506,11 @@ static char* get_user_name_slow(int vmid, TRAPS) {
|
|||||||
|
|
||||||
const char* tmpdirname = os::get_temp_directory();
|
const char* tmpdirname = os::get_temp_directory();
|
||||||
|
|
||||||
|
// open the temp directory
|
||||||
DIR* tmpdirp = os::opendir(tmpdirname);
|
DIR* tmpdirp = os::opendir(tmpdirname);
|
||||||
|
|
||||||
if (tmpdirp == NULL) {
|
if (tmpdirp == NULL) {
|
||||||
|
// Cannot open the directory to get the user name, return.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,25 +535,14 @@ static char* get_user_name_slow(int vmid, TRAPS) {
|
|||||||
strcat(usrdir_name, "/");
|
strcat(usrdir_name, "/");
|
||||||
strcat(usrdir_name, dentry->d_name);
|
strcat(usrdir_name, dentry->d_name);
|
||||||
|
|
||||||
DIR* subdirp = os::opendir(usrdir_name);
|
// open the user directory
|
||||||
|
DIR* subdirp = open_directory_secure(usrdir_name);
|
||||||
|
|
||||||
if (subdirp == NULL) {
|
if (subdirp == NULL) {
|
||||||
FREE_C_HEAP_ARRAY(char, usrdir_name);
|
FREE_C_HEAP_ARRAY(char, usrdir_name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since we don't create the backing store files in directories
|
|
||||||
// pointed to by symbolic links, we also don't follow them when
|
|
||||||
// looking for the files. We check for a symbolic link after the
|
|
||||||
// call to opendir in order to eliminate a small window where the
|
|
||||||
// symlink can be exploited.
|
|
||||||
//
|
|
||||||
if (!is_directory_secure(usrdir_name)) {
|
|
||||||
FREE_C_HEAP_ARRAY(char, usrdir_name);
|
|
||||||
os::closedir(subdirp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dirent* udentry;
|
struct dirent* udentry;
|
||||||
char* udbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(usrdir_name), mtInternal);
|
char* udbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(usrdir_name), mtInternal);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@ -465,26 +645,6 @@ static void remove_file(const char* path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// remove file
|
|
||||||
//
|
|
||||||
// this method removes the file with the given file name in the
|
|
||||||
// named directory.
|
|
||||||
//
|
|
||||||
static void remove_file(const char* dirname, const char* filename) {
|
|
||||||
|
|
||||||
size_t nbytes = strlen(dirname) + strlen(filename) + 2;
|
|
||||||
char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
|
|
||||||
|
|
||||||
strcpy(path, dirname);
|
|
||||||
strcat(path, "/");
|
|
||||||
strcat(path, filename);
|
|
||||||
|
|
||||||
remove_file(path);
|
|
||||||
|
|
||||||
FREE_C_HEAP_ARRAY(char, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// cleanup stale shared memory resources
|
// cleanup stale shared memory resources
|
||||||
//
|
//
|
||||||
// This method attempts to remove all stale shared memory files in
|
// This method attempts to remove all stale shared memory files in
|
||||||
@ -496,17 +656,11 @@ static void remove_file(const char* dirname, const char* filename) {
|
|||||||
//
|
//
|
||||||
static void cleanup_sharedmem_resources(const char* dirname) {
|
static void cleanup_sharedmem_resources(const char* dirname) {
|
||||||
|
|
||||||
// open the user temp directory
|
int saved_cwd_fd;
|
||||||
DIR* dirp = os::opendir(dirname);
|
// open the directory and set the current working directory to it
|
||||||
|
DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
|
||||||
if (dirp == NULL) {
|
if (dirp == NULL) {
|
||||||
// directory doesn't exist, so there is nothing to cleanup
|
// directory doesn't exist or is insecure, so there is nothing to cleanup
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_directory_secure(dirname)) {
|
|
||||||
// the directory is not a secure directory
|
|
||||||
os::closedir(dirp);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,6 +674,7 @@ static void cleanup_sharedmem_resources(const char* dirname) {
|
|||||||
//
|
//
|
||||||
struct dirent* entry;
|
struct dirent* entry;
|
||||||
char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal);
|
char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal);
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) {
|
while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) {
|
||||||
|
|
||||||
@ -530,7 +685,7 @@ static void cleanup_sharedmem_resources(const char* dirname) {
|
|||||||
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
|
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
|
||||||
|
|
||||||
// attempt to remove all unexpected files, except "." and ".."
|
// attempt to remove all unexpected files, except "." and ".."
|
||||||
remove_file(dirname, entry->d_name);
|
unlink(entry->d_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@ -553,11 +708,14 @@ static void cleanup_sharedmem_resources(const char* dirname) {
|
|||||||
if ((pid == os::current_process_id()) ||
|
if ((pid == os::current_process_id()) ||
|
||||||
(kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) {
|
(kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) {
|
||||||
|
|
||||||
remove_file(dirname, entry->d_name);
|
unlink(entry->d_name);
|
||||||
}
|
}
|
||||||
errno = 0;
|
errno = 0;
|
||||||
}
|
}
|
||||||
os::closedir(dirp);
|
|
||||||
|
// close the directory and reset the current working directory
|
||||||
|
close_directory_secure_cwd(dirp, saved_cwd_fd);
|
||||||
|
|
||||||
FREE_C_HEAP_ARRAY(char, dbuf);
|
FREE_C_HEAP_ARRAY(char, dbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,19 +772,54 @@ static int create_sharedmem_resources(const char* dirname, const char* filename,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int result;
|
int saved_cwd_fd;
|
||||||
|
// open the directory and set the current working directory to it
|
||||||
RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result);
|
DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
|
||||||
if (result == OS_ERR) {
|
if (dirp == NULL) {
|
||||||
if (PrintMiscellaneous && Verbose) {
|
// Directory doesn't exist or is insecure, so cannot create shared
|
||||||
warning("could not create file %s: %s\n", filename, strerror(errno));
|
// memory file.
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open the filename in the current directory.
|
||||||
|
// Cannot use O_TRUNC here; truncation of an existing file has to happen
|
||||||
|
// after the is_file_secure() check below.
|
||||||
|
int result;
|
||||||
|
RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
if (errno == ELOOP) {
|
||||||
|
warning("file %s is a symlink and is not secure\n", filename);
|
||||||
|
} else {
|
||||||
|
warning("could not create file %s: %s\n", filename, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// close the directory and reset the current working directory
|
||||||
|
close_directory_secure_cwd(dirp, saved_cwd_fd);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// close the directory and reset the current working directory
|
||||||
|
close_directory_secure_cwd(dirp, saved_cwd_fd);
|
||||||
|
|
||||||
// save the file descriptor
|
// save the file descriptor
|
||||||
int fd = result;
|
int fd = result;
|
||||||
|
|
||||||
|
// check to see if the file is secure
|
||||||
|
if (!is_file_secure(fd, filename)) {
|
||||||
|
::close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// truncate the file to get rid of any existing data
|
||||||
|
RESTARTABLE(::ftruncate(fd, (off_t)0), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
warning("could not truncate shared memory file: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
::close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
// set the file size
|
// set the file size
|
||||||
RESTARTABLE(::ftruncate(fd, (off_t)size), result);
|
RESTARTABLE(::ftruncate(fd, (off_t)size), result);
|
||||||
if (result == OS_ERR) {
|
if (result == OS_ERR) {
|
||||||
@ -684,8 +877,15 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) {
|
|||||||
THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR);
|
THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int fd = result;
|
||||||
|
|
||||||
return result;
|
// check to see if the file is secure
|
||||||
|
if (!is_file_secure(fd, filename)) {
|
||||||
|
::close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a named shared memory region. returns the address of the
|
// create a named shared memory region. returns the address of the
|
||||||
@ -717,13 +917,21 @@ static char* mmap_create_shared(size_t size) {
|
|||||||
char* dirname = get_user_tmp_dir(user_name);
|
char* dirname = get_user_tmp_dir(user_name);
|
||||||
char* filename = get_sharedmem_filename(dirname, vmid);
|
char* filename = get_sharedmem_filename(dirname, vmid);
|
||||||
|
|
||||||
|
// get the short filename
|
||||||
|
char* short_filename = strrchr(filename, '/');
|
||||||
|
if (short_filename == NULL) {
|
||||||
|
short_filename = filename;
|
||||||
|
} else {
|
||||||
|
short_filename++;
|
||||||
|
}
|
||||||
|
|
||||||
// cleanup any stale shared memory files
|
// cleanup any stale shared memory files
|
||||||
cleanup_sharedmem_resources(dirname);
|
cleanup_sharedmem_resources(dirname);
|
||||||
|
|
||||||
assert(((size > 0) && (size % os::vm_page_size() == 0)),
|
assert(((size > 0) && (size % os::vm_page_size() == 0)),
|
||||||
"unexpected PerfMemory region size");
|
"unexpected PerfMemory region size");
|
||||||
|
|
||||||
fd = create_sharedmem_resources(dirname, filename, size);
|
fd = create_sharedmem_resources(dirname, short_filename, size);
|
||||||
|
|
||||||
FREE_C_HEAP_ARRAY(char, user_name);
|
FREE_C_HEAP_ARRAY(char, user_name);
|
||||||
FREE_C_HEAP_ARRAY(char, dirname);
|
FREE_C_HEAP_ARRAY(char, dirname);
|
||||||
@ -838,12 +1046,12 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor
|
|||||||
// constructs for the file and the shared memory mapping.
|
// constructs for the file and the shared memory mapping.
|
||||||
if (mode == PerfMemory::PERF_MODE_RO) {
|
if (mode == PerfMemory::PERF_MODE_RO) {
|
||||||
mmap_prot = PROT_READ;
|
mmap_prot = PROT_READ;
|
||||||
file_flags = O_RDONLY;
|
file_flags = O_RDONLY | O_NOFOLLOW;
|
||||||
}
|
}
|
||||||
else if (mode == PerfMemory::PERF_MODE_RW) {
|
else if (mode == PerfMemory::PERF_MODE_RW) {
|
||||||
#ifdef LATER
|
#ifdef LATER
|
||||||
mmap_prot = PROT_READ | PROT_WRITE;
|
mmap_prot = PROT_READ | PROT_WRITE;
|
||||||
file_flags = O_RDWR;
|
file_flags = O_RDWR | O_NOFOLLOW;
|
||||||
#else
|
#else
|
||||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||||
"Unsupported access mode");
|
"Unsupported access mode");
|
||||||
|
@ -197,7 +197,38 @@ static pid_t filename_to_pid(const char* filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// check if the given path is considered a secure directory for
|
// Check if the given statbuf is considered a secure directory for
|
||||||
|
// the backing store files. Returns true if the directory is considered
|
||||||
|
// a secure location. Returns false if the statbuf is a symbolic link or
|
||||||
|
// if an error occurred.
|
||||||
|
//
|
||||||
|
static bool is_statbuf_secure(struct stat *statp) {
|
||||||
|
if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) {
|
||||||
|
// The path represents a link or some non-directory file type,
|
||||||
|
// which is not what we expected. Declare it insecure.
|
||||||
|
//
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// We have an existing directory, check if the permissions are safe.
|
||||||
|
//
|
||||||
|
if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) {
|
||||||
|
// The directory is open for writing and could be subjected
|
||||||
|
// to a symlink or a hard link attack. Declare it insecure.
|
||||||
|
//
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// See if the uid of the directory matches the effective uid of the process.
|
||||||
|
//
|
||||||
|
if (statp->st_uid != geteuid()) {
|
||||||
|
// The directory was not created by this user, declare it insecure.
|
||||||
|
//
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check if the given path is considered a secure directory for
|
||||||
// the backing store files. Returns true if the directory exists
|
// the backing store files. Returns true if the directory exists
|
||||||
// and is considered a secure location. Returns false if the path
|
// and is considered a secure location. Returns false if the path
|
||||||
// is a symbolic link or if an error occurred.
|
// is a symbolic link or if an error occurred.
|
||||||
@ -211,22 +242,180 @@ static bool is_directory_secure(const char* path) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the path exists, now check it's mode
|
// The path exists, see if it is secure.
|
||||||
if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) {
|
return is_statbuf_secure(&statbuf);
|
||||||
// the path represents a link or some non-directory file type,
|
}
|
||||||
// which is not what we expected. declare it insecure.
|
|
||||||
//
|
|
||||||
|
// Check if the given directory file descriptor is considered a secure
|
||||||
|
// directory for the backing store files. Returns true if the directory
|
||||||
|
// exists and is considered a secure location. Returns false if the path
|
||||||
|
// is a symbolic link or if an error occurred.
|
||||||
|
//
|
||||||
|
static bool is_dirfd_secure(int dir_fd) {
|
||||||
|
struct stat statbuf;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
RESTARTABLE(::fstat(dir_fd, &statbuf), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// we have an existing directory, check if the permissions are safe.
|
// The path exists, now check its mode.
|
||||||
//
|
return is_statbuf_secure(&statbuf);
|
||||||
if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
|
}
|
||||||
// the directory is open for writing and could be subjected
|
|
||||||
// to a symlnk attack. declare it insecure.
|
|
||||||
//
|
// Check to make sure fd1 and fd2 are referencing the same file system object.
|
||||||
return false;
|
//
|
||||||
|
static bool is_same_fsobject(int fd1, int fd2) {
|
||||||
|
struct stat statbuf1;
|
||||||
|
struct stat statbuf2;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
RESTARTABLE(::fstat(fd1, &statbuf1), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RESTARTABLE(::fstat(fd2, &statbuf2), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((statbuf1.st_ino == statbuf2.st_ino) &&
|
||||||
|
(statbuf1.st_dev == statbuf2.st_dev)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Open the directory of the given path and validate it.
|
||||||
|
// Return a DIR * of the open directory.
|
||||||
|
//
|
||||||
|
static DIR *open_directory_secure(const char* dirname) {
|
||||||
|
// Open the directory using open() so that it can be verified
|
||||||
|
// to be secure by calling is_dirfd_secure(), opendir() and then check
|
||||||
|
// to see if they are the same file system object. This method does not
|
||||||
|
// introduce a window of opportunity for the directory to be attacked that
|
||||||
|
// calling opendir() and is_directory_secure() does.
|
||||||
|
int result;
|
||||||
|
DIR *dirp = NULL;
|
||||||
|
RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
if (errno == ELOOP) {
|
||||||
|
warning("directory %s is a symlink and is not secure\n", dirname);
|
||||||
|
} else {
|
||||||
|
warning("could not open directory %s: %s\n", dirname, strerror(errno));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
int fd = result;
|
||||||
|
|
||||||
|
// Determine if the open directory is secure.
|
||||||
|
if (!is_dirfd_secure(fd)) {
|
||||||
|
// The directory is not a secure directory.
|
||||||
|
os::close(fd);
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the directory.
|
||||||
|
dirp = ::opendir(dirname);
|
||||||
|
if (dirp == NULL) {
|
||||||
|
// The directory doesn't exist, close fd and return.
|
||||||
|
os::close(fd);
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to make sure fd and dirp are referencing the same file system object.
|
||||||
|
if (!is_same_fsobject(fd, dirfd(dirp))) {
|
||||||
|
// The directory is not secure.
|
||||||
|
os::close(fd);
|
||||||
|
os::closedir(dirp);
|
||||||
|
dirp = NULL;
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close initial open now that we know directory is secure
|
||||||
|
os::close(fd);
|
||||||
|
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: The code below uses fchdir(), open() and unlink() because
|
||||||
|
// fdopendir(), openat() and unlinkat() are not supported on all
|
||||||
|
// versions. Once the support for fdopendir(), openat() and unlinkat()
|
||||||
|
// is available on all supported versions the code can be changed
|
||||||
|
// to use these functions.
|
||||||
|
|
||||||
|
// Open the directory of the given path, validate it and set the
|
||||||
|
// current working directory to it.
|
||||||
|
// Return a DIR * of the open directory and the saved cwd fd.
|
||||||
|
//
|
||||||
|
static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) {
|
||||||
|
|
||||||
|
// Open the directory.
|
||||||
|
DIR* dirp = open_directory_secure(dirname);
|
||||||
|
if (dirp == NULL) {
|
||||||
|
// Directory doesn't exist or is insecure, so there is nothing to cleanup.
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
int fd = dirfd(dirp);
|
||||||
|
|
||||||
|
// Open a fd to the cwd and save it off.
|
||||||
|
int result;
|
||||||
|
RESTARTABLE(::open(".", O_RDONLY), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
*saved_cwd_fd = -1;
|
||||||
|
} else {
|
||||||
|
*saved_cwd_fd = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the current directory to dirname by using the fd of the directory.
|
||||||
|
result = fchdir(fd);
|
||||||
|
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the directory and restore the current working directory.
|
||||||
|
//
|
||||||
|
static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) {
|
||||||
|
|
||||||
|
int result;
|
||||||
|
// If we have a saved cwd change back to it and close the fd.
|
||||||
|
if (saved_cwd_fd != -1) {
|
||||||
|
result = fchdir(saved_cwd_fd);
|
||||||
|
::close(saved_cwd_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the directory.
|
||||||
|
os::closedir(dirp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the given file descriptor is considered a secure.
|
||||||
|
//
|
||||||
|
static bool is_file_secure(int fd, const char *filename) {
|
||||||
|
|
||||||
|
int result;
|
||||||
|
struct stat statbuf;
|
||||||
|
|
||||||
|
// Determine if the file is secure.
|
||||||
|
RESTARTABLE(::fstat(fd, &statbuf), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
warning("fstat failed on %s: %s\n", filename, strerror(errno));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (statbuf.st_nlink > 1) {
|
||||||
|
// A file with multiple links is not expected.
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
warning("file %s has multiple links\n", filename);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -317,9 +506,11 @@ static char* get_user_name_slow(int vmid, TRAPS) {
|
|||||||
|
|
||||||
const char* tmpdirname = os::get_temp_directory();
|
const char* tmpdirname = os::get_temp_directory();
|
||||||
|
|
||||||
|
// open the temp directory
|
||||||
DIR* tmpdirp = os::opendir(tmpdirname);
|
DIR* tmpdirp = os::opendir(tmpdirname);
|
||||||
|
|
||||||
if (tmpdirp == NULL) {
|
if (tmpdirp == NULL) {
|
||||||
|
// Cannot open the directory to get the user name, return.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,7 +535,8 @@ static char* get_user_name_slow(int vmid, TRAPS) {
|
|||||||
strcat(usrdir_name, "/");
|
strcat(usrdir_name, "/");
|
||||||
strcat(usrdir_name, dentry->d_name);
|
strcat(usrdir_name, dentry->d_name);
|
||||||
|
|
||||||
DIR* subdirp = os::opendir(usrdir_name);
|
// open the user directory
|
||||||
|
DIR* subdirp = open_directory_secure(usrdir_name);
|
||||||
|
|
||||||
if (subdirp == NULL) {
|
if (subdirp == NULL) {
|
||||||
FREE_C_HEAP_ARRAY(char, usrdir_name);
|
FREE_C_HEAP_ARRAY(char, usrdir_name);
|
||||||
@ -465,26 +657,6 @@ static void remove_file(const char* path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// remove file
|
|
||||||
//
|
|
||||||
// this method removes the file with the given file name in the
|
|
||||||
// named directory.
|
|
||||||
//
|
|
||||||
static void remove_file(const char* dirname, const char* filename) {
|
|
||||||
|
|
||||||
size_t nbytes = strlen(dirname) + strlen(filename) + 2;
|
|
||||||
char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
|
|
||||||
|
|
||||||
strcpy(path, dirname);
|
|
||||||
strcat(path, "/");
|
|
||||||
strcat(path, filename);
|
|
||||||
|
|
||||||
remove_file(path);
|
|
||||||
|
|
||||||
FREE_C_HEAP_ARRAY(char, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// cleanup stale shared memory resources
|
// cleanup stale shared memory resources
|
||||||
//
|
//
|
||||||
// This method attempts to remove all stale shared memory files in
|
// This method attempts to remove all stale shared memory files in
|
||||||
@ -496,17 +668,11 @@ static void remove_file(const char* dirname, const char* filename) {
|
|||||||
//
|
//
|
||||||
static void cleanup_sharedmem_resources(const char* dirname) {
|
static void cleanup_sharedmem_resources(const char* dirname) {
|
||||||
|
|
||||||
// open the user temp directory
|
int saved_cwd_fd;
|
||||||
DIR* dirp = os::opendir(dirname);
|
// open the directory
|
||||||
|
DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
|
||||||
if (dirp == NULL) {
|
if (dirp == NULL) {
|
||||||
// directory doesn't exist, so there is nothing to cleanup
|
// directory doesn't exist or is insecure, so there is nothing to cleanup
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_directory_secure(dirname)) {
|
|
||||||
// the directory is not a secure directory
|
|
||||||
os::closedir(dirp);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,6 +686,7 @@ static void cleanup_sharedmem_resources(const char* dirname) {
|
|||||||
//
|
//
|
||||||
struct dirent* entry;
|
struct dirent* entry;
|
||||||
char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal);
|
char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal);
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) {
|
while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) {
|
||||||
|
|
||||||
@ -528,9 +695,8 @@ static void cleanup_sharedmem_resources(const char* dirname) {
|
|||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
|
|
||||||
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
|
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
|
||||||
|
|
||||||
// attempt to remove all unexpected files, except "." and ".."
|
// attempt to remove all unexpected files, except "." and ".."
|
||||||
remove_file(dirname, entry->d_name);
|
unlink(entry->d_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@ -552,12 +718,14 @@ static void cleanup_sharedmem_resources(const char* dirname) {
|
|||||||
//
|
//
|
||||||
if ((pid == os::current_process_id()) ||
|
if ((pid == os::current_process_id()) ||
|
||||||
(kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) {
|
(kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) {
|
||||||
|
unlink(entry->d_name);
|
||||||
remove_file(dirname, entry->d_name);
|
|
||||||
}
|
}
|
||||||
errno = 0;
|
errno = 0;
|
||||||
}
|
}
|
||||||
os::closedir(dirp);
|
|
||||||
|
// close the directory and reset the current working directory
|
||||||
|
close_directory_secure_cwd(dirp, saved_cwd_fd);
|
||||||
|
|
||||||
FREE_C_HEAP_ARRAY(char, dbuf);
|
FREE_C_HEAP_ARRAY(char, dbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,19 +782,54 @@ static int create_sharedmem_resources(const char* dirname, const char* filename,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int result;
|
int saved_cwd_fd;
|
||||||
|
// open the directory and set the current working directory to it
|
||||||
RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result);
|
DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
|
||||||
if (result == OS_ERR) {
|
if (dirp == NULL) {
|
||||||
if (PrintMiscellaneous && Verbose) {
|
// Directory doesn't exist or is insecure, so cannot create shared
|
||||||
warning("could not create file %s: %s\n", filename, strerror(errno));
|
// memory file.
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open the filename in the current directory.
|
||||||
|
// Cannot use O_TRUNC here; truncation of an existing file has to happen
|
||||||
|
// after the is_file_secure() check below.
|
||||||
|
int result;
|
||||||
|
RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
if (errno == ELOOP) {
|
||||||
|
warning("file %s is a symlink and is not secure\n", filename);
|
||||||
|
} else {
|
||||||
|
warning("could not create file %s: %s\n", filename, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// close the directory and reset the current working directory
|
||||||
|
close_directory_secure_cwd(dirp, saved_cwd_fd);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// close the directory and reset the current working directory
|
||||||
|
close_directory_secure_cwd(dirp, saved_cwd_fd);
|
||||||
|
|
||||||
// save the file descriptor
|
// save the file descriptor
|
||||||
int fd = result;
|
int fd = result;
|
||||||
|
|
||||||
|
// check to see if the file is secure
|
||||||
|
if (!is_file_secure(fd, filename)) {
|
||||||
|
::close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// truncate the file to get rid of any existing data
|
||||||
|
RESTARTABLE(::ftruncate(fd, (off_t)0), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
warning("could not truncate shared memory file: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
::close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
// set the file size
|
// set the file size
|
||||||
RESTARTABLE(::ftruncate(fd, (off_t)size), result);
|
RESTARTABLE(::ftruncate(fd, (off_t)size), result);
|
||||||
if (result == OS_ERR) {
|
if (result == OS_ERR) {
|
||||||
@ -684,8 +887,15 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) {
|
|||||||
THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR);
|
THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int fd = result;
|
||||||
|
|
||||||
return result;
|
// check to see if the file is secure
|
||||||
|
if (!is_file_secure(fd, filename)) {
|
||||||
|
::close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a named shared memory region. returns the address of the
|
// create a named shared memory region. returns the address of the
|
||||||
@ -716,6 +926,13 @@ static char* mmap_create_shared(size_t size) {
|
|||||||
|
|
||||||
char* dirname = get_user_tmp_dir(user_name);
|
char* dirname = get_user_tmp_dir(user_name);
|
||||||
char* filename = get_sharedmem_filename(dirname, vmid);
|
char* filename = get_sharedmem_filename(dirname, vmid);
|
||||||
|
// get the short filename
|
||||||
|
char* short_filename = strrchr(filename, '/');
|
||||||
|
if (short_filename == NULL) {
|
||||||
|
short_filename = filename;
|
||||||
|
} else {
|
||||||
|
short_filename++;
|
||||||
|
}
|
||||||
|
|
||||||
// cleanup any stale shared memory files
|
// cleanup any stale shared memory files
|
||||||
cleanup_sharedmem_resources(dirname);
|
cleanup_sharedmem_resources(dirname);
|
||||||
@ -723,7 +940,7 @@ static char* mmap_create_shared(size_t size) {
|
|||||||
assert(((size > 0) && (size % os::vm_page_size() == 0)),
|
assert(((size > 0) && (size % os::vm_page_size() == 0)),
|
||||||
"unexpected PerfMemory region size");
|
"unexpected PerfMemory region size");
|
||||||
|
|
||||||
fd = create_sharedmem_resources(dirname, filename, size);
|
fd = create_sharedmem_resources(dirname, short_filename, size);
|
||||||
|
|
||||||
FREE_C_HEAP_ARRAY(char, user_name);
|
FREE_C_HEAP_ARRAY(char, user_name);
|
||||||
FREE_C_HEAP_ARRAY(char, dirname);
|
FREE_C_HEAP_ARRAY(char, dirname);
|
||||||
@ -838,12 +1055,12 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor
|
|||||||
// constructs for the file and the shared memory mapping.
|
// constructs for the file and the shared memory mapping.
|
||||||
if (mode == PerfMemory::PERF_MODE_RO) {
|
if (mode == PerfMemory::PERF_MODE_RO) {
|
||||||
mmap_prot = PROT_READ;
|
mmap_prot = PROT_READ;
|
||||||
file_flags = O_RDONLY;
|
file_flags = O_RDONLY | O_NOFOLLOW;
|
||||||
}
|
}
|
||||||
else if (mode == PerfMemory::PERF_MODE_RW) {
|
else if (mode == PerfMemory::PERF_MODE_RW) {
|
||||||
#ifdef LATER
|
#ifdef LATER
|
||||||
mmap_prot = PROT_READ | PROT_WRITE;
|
mmap_prot = PROT_READ | PROT_WRITE;
|
||||||
file_flags = O_RDWR;
|
file_flags = O_RDWR | O_NOFOLLOW;
|
||||||
#else
|
#else
|
||||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||||
"Unsupported access mode");
|
"Unsupported access mode");
|
||||||
|
@ -199,7 +199,38 @@ static pid_t filename_to_pid(const char* filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// check if the given path is considered a secure directory for
|
// Check if the given statbuf is considered a secure directory for
|
||||||
|
// the backing store files. Returns true if the directory is considered
|
||||||
|
// a secure location. Returns false if the statbuf is a symbolic link or
|
||||||
|
// if an error occurred.
|
||||||
|
//
|
||||||
|
static bool is_statbuf_secure(struct stat *statp) {
|
||||||
|
if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) {
|
||||||
|
// The path represents a link or some non-directory file type,
|
||||||
|
// which is not what we expected. Declare it insecure.
|
||||||
|
//
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// We have an existing directory, check if the permissions are safe.
|
||||||
|
//
|
||||||
|
if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) {
|
||||||
|
// The directory is open for writing and could be subjected
|
||||||
|
// to a symlink or a hard link attack. Declare it insecure.
|
||||||
|
//
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// See if the uid of the directory matches the effective uid of the process.
|
||||||
|
//
|
||||||
|
if (statp->st_uid != geteuid()) {
|
||||||
|
// The directory was not created by this user, declare it insecure.
|
||||||
|
//
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check if the given path is considered a secure directory for
|
||||||
// the backing store files. Returns true if the directory exists
|
// the backing store files. Returns true if the directory exists
|
||||||
// and is considered a secure location. Returns false if the path
|
// and is considered a secure location. Returns false if the path
|
||||||
// is a symbolic link or if an error occurred.
|
// is a symbolic link or if an error occurred.
|
||||||
@ -213,27 +244,185 @@ static bool is_directory_secure(const char* path) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the path exists, now check it's mode
|
// The path exists, see if it is secure.
|
||||||
if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) {
|
return is_statbuf_secure(&statbuf);
|
||||||
// the path represents a link or some non-directory file type,
|
}
|
||||||
// which is not what we expected. declare it insecure.
|
|
||||||
//
|
|
||||||
|
// Check if the given directory file descriptor is considered a secure
|
||||||
|
// directory for the backing store files. Returns true if the directory
|
||||||
|
// exists and is considered a secure location. Returns false if the path
|
||||||
|
// is a symbolic link or if an error occurred.
|
||||||
|
//
|
||||||
|
static bool is_dirfd_secure(int dir_fd) {
|
||||||
|
struct stat statbuf;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
RESTARTABLE(::fstat(dir_fd, &statbuf), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// we have an existing directory, check if the permissions are safe.
|
// The path exists, now check its mode.
|
||||||
//
|
return is_statbuf_secure(&statbuf);
|
||||||
if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
|
}
|
||||||
// the directory is open for writing and could be subjected
|
|
||||||
// to a symlnk attack. declare it insecure.
|
|
||||||
//
|
// Check to make sure fd1 and fd2 are referencing the same file system object.
|
||||||
return false;
|
//
|
||||||
|
static bool is_same_fsobject(int fd1, int fd2) {
|
||||||
|
struct stat statbuf1;
|
||||||
|
struct stat statbuf2;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
RESTARTABLE(::fstat(fd1, &statbuf1), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RESTARTABLE(::fstat(fd2, &statbuf2), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((statbuf1.st_ino == statbuf2.st_ino) &&
|
||||||
|
(statbuf1.st_dev == statbuf2.st_dev)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Open the directory of the given path and validate it.
|
||||||
|
// Return a DIR * of the open directory.
|
||||||
|
//
|
||||||
|
static DIR *open_directory_secure(const char* dirname) {
|
||||||
|
// Open the directory using open() so that it can be verified
|
||||||
|
// to be secure by calling is_dirfd_secure(), opendir() and then check
|
||||||
|
// to see if they are the same file system object. This method does not
|
||||||
|
// introduce a window of opportunity for the directory to be attacked that
|
||||||
|
// calling opendir() and is_directory_secure() does.
|
||||||
|
int result;
|
||||||
|
DIR *dirp = NULL;
|
||||||
|
RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
// Directory doesn't exist or is a symlink, so there is nothing to cleanup.
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
if (errno == ELOOP) {
|
||||||
|
warning("directory %s is a symlink and is not secure\n", dirname);
|
||||||
|
} else {
|
||||||
|
warning("could not open directory %s: %s\n", dirname, strerror(errno));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
int fd = result;
|
||||||
|
|
||||||
|
// Determine if the open directory is secure.
|
||||||
|
if (!is_dirfd_secure(fd)) {
|
||||||
|
// The directory is not a secure directory.
|
||||||
|
os::close(fd);
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the directory.
|
||||||
|
dirp = ::opendir(dirname);
|
||||||
|
if (dirp == NULL) {
|
||||||
|
// The directory doesn't exist, close fd and return.
|
||||||
|
os::close(fd);
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to make sure fd and dirp are referencing the same file system object.
|
||||||
|
if (!is_same_fsobject(fd, dirp->dd_fd)) {
|
||||||
|
// The directory is not secure.
|
||||||
|
os::close(fd);
|
||||||
|
os::closedir(dirp);
|
||||||
|
dirp = NULL;
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close initial open now that we know directory is secure
|
||||||
|
os::close(fd);
|
||||||
|
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: The code below uses fchdir(), open() and unlink() because
|
||||||
|
// fdopendir(), openat() and unlinkat() are not supported on all
|
||||||
|
// versions. Once the support for fdopendir(), openat() and unlinkat()
|
||||||
|
// is available on all supported versions the code can be changed
|
||||||
|
// to use these functions.
|
||||||
|
|
||||||
|
// Open the directory of the given path, validate it and set the
|
||||||
|
// current working directory to it.
|
||||||
|
// Return a DIR * of the open directory and the saved cwd fd.
|
||||||
|
//
|
||||||
|
static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) {
|
||||||
|
|
||||||
|
// Open the directory.
|
||||||
|
DIR* dirp = open_directory_secure(dirname);
|
||||||
|
if (dirp == NULL) {
|
||||||
|
// Directory doesn't exist or is insecure, so there is nothing to cleanup.
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
int fd = dirp->dd_fd;
|
||||||
|
|
||||||
|
// Open a fd to the cwd and save it off.
|
||||||
|
int result;
|
||||||
|
RESTARTABLE(::open(".", O_RDONLY), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
*saved_cwd_fd = -1;
|
||||||
|
} else {
|
||||||
|
*saved_cwd_fd = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the current directory to dirname by using the fd of the directory.
|
||||||
|
result = fchdir(fd);
|
||||||
|
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the directory and restore the current working directory.
|
||||||
|
//
|
||||||
|
static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) {
|
||||||
|
|
||||||
|
int result;
|
||||||
|
// If we have a saved cwd change back to it and close the fd.
|
||||||
|
if (saved_cwd_fd != -1) {
|
||||||
|
result = fchdir(saved_cwd_fd);
|
||||||
|
::close(saved_cwd_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the directory.
|
||||||
|
os::closedir(dirp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the given file descriptor is considered a secure.
|
||||||
|
//
|
||||||
|
static bool is_file_secure(int fd, const char *filename) {
|
||||||
|
|
||||||
|
int result;
|
||||||
|
struct stat statbuf;
|
||||||
|
|
||||||
|
// Determine if the file is secure.
|
||||||
|
RESTARTABLE(::fstat(fd, &statbuf), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
warning("fstat failed on %s: %s\n", filename, strerror(errno));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (statbuf.st_nlink > 1) {
|
||||||
|
// A file with multiple links is not expected.
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
warning("file %s has multiple links\n", filename);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// return the user name for the given user id
|
// return the user name for the given user id
|
||||||
//
|
//
|
||||||
// the caller is expected to free the allocated memory.
|
// the caller is expected to free the allocated memory.
|
||||||
@ -308,9 +497,11 @@ static char* get_user_name_slow(int vmid, TRAPS) {
|
|||||||
|
|
||||||
const char* tmpdirname = os::get_temp_directory();
|
const char* tmpdirname = os::get_temp_directory();
|
||||||
|
|
||||||
|
// open the temp directory
|
||||||
DIR* tmpdirp = os::opendir(tmpdirname);
|
DIR* tmpdirp = os::opendir(tmpdirname);
|
||||||
|
|
||||||
if (tmpdirp == NULL) {
|
if (tmpdirp == NULL) {
|
||||||
|
// Cannot open the directory to get the user name, return.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +526,8 @@ static char* get_user_name_slow(int vmid, TRAPS) {
|
|||||||
strcat(usrdir_name, "/");
|
strcat(usrdir_name, "/");
|
||||||
strcat(usrdir_name, dentry->d_name);
|
strcat(usrdir_name, dentry->d_name);
|
||||||
|
|
||||||
DIR* subdirp = os::opendir(usrdir_name);
|
// open the user directory
|
||||||
|
DIR* subdirp = open_directory_secure(usrdir_name);
|
||||||
|
|
||||||
if (subdirp == NULL) {
|
if (subdirp == NULL) {
|
||||||
FREE_C_HEAP_ARRAY(char, usrdir_name);
|
FREE_C_HEAP_ARRAY(char, usrdir_name);
|
||||||
@ -504,26 +696,6 @@ static void remove_file(const char* path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// remove file
|
|
||||||
//
|
|
||||||
// this method removes the file with the given file name in the
|
|
||||||
// named directory.
|
|
||||||
//
|
|
||||||
static void remove_file(const char* dirname, const char* filename) {
|
|
||||||
|
|
||||||
size_t nbytes = strlen(dirname) + strlen(filename) + 2;
|
|
||||||
char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
|
|
||||||
|
|
||||||
strcpy(path, dirname);
|
|
||||||
strcat(path, "/");
|
|
||||||
strcat(path, filename);
|
|
||||||
|
|
||||||
remove_file(path);
|
|
||||||
|
|
||||||
FREE_C_HEAP_ARRAY(char, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// cleanup stale shared memory resources
|
// cleanup stale shared memory resources
|
||||||
//
|
//
|
||||||
// This method attempts to remove all stale shared memory files in
|
// This method attempts to remove all stale shared memory files in
|
||||||
@ -535,17 +707,11 @@ static void remove_file(const char* dirname, const char* filename) {
|
|||||||
//
|
//
|
||||||
static void cleanup_sharedmem_resources(const char* dirname) {
|
static void cleanup_sharedmem_resources(const char* dirname) {
|
||||||
|
|
||||||
// open the user temp directory
|
int saved_cwd_fd;
|
||||||
DIR* dirp = os::opendir(dirname);
|
// open the directory
|
||||||
|
DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
|
||||||
if (dirp == NULL) {
|
if (dirp == NULL) {
|
||||||
// directory doesn't exist, so there is nothing to cleanup
|
// directory doesn't exist or is insecure, so there is nothing to cleanup
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_directory_secure(dirname)) {
|
|
||||||
// the directory is not a secure directory
|
|
||||||
os::closedir(dirp);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,6 +725,7 @@ static void cleanup_sharedmem_resources(const char* dirname) {
|
|||||||
//
|
//
|
||||||
struct dirent* entry;
|
struct dirent* entry;
|
||||||
char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal);
|
char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal);
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) {
|
while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) {
|
||||||
|
|
||||||
@ -569,7 +736,7 @@ static void cleanup_sharedmem_resources(const char* dirname) {
|
|||||||
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
|
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
|
||||||
|
|
||||||
// attempt to remove all unexpected files, except "." and ".."
|
// attempt to remove all unexpected files, except "." and ".."
|
||||||
remove_file(dirname, entry->d_name);
|
unlink(entry->d_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@ -592,11 +759,14 @@ static void cleanup_sharedmem_resources(const char* dirname) {
|
|||||||
if ((pid == os::current_process_id()) ||
|
if ((pid == os::current_process_id()) ||
|
||||||
(kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) {
|
(kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) {
|
||||||
|
|
||||||
remove_file(dirname, entry->d_name);
|
unlink(entry->d_name);
|
||||||
}
|
}
|
||||||
errno = 0;
|
errno = 0;
|
||||||
}
|
}
|
||||||
os::closedir(dirp);
|
|
||||||
|
// close the directory and reset the current working directory
|
||||||
|
close_directory_secure_cwd(dirp, saved_cwd_fd);
|
||||||
|
|
||||||
FREE_C_HEAP_ARRAY(char, dbuf);
|
FREE_C_HEAP_ARRAY(char, dbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -653,19 +823,54 @@ static int create_sharedmem_resources(const char* dirname, const char* filename,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int result;
|
int saved_cwd_fd;
|
||||||
|
// open the directory and set the current working directory to it
|
||||||
RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result);
|
DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
|
||||||
if (result == OS_ERR) {
|
if (dirp == NULL) {
|
||||||
if (PrintMiscellaneous && Verbose) {
|
// Directory doesn't exist or is insecure, so cannot create shared
|
||||||
warning("could not create file %s: %s\n", filename, strerror(errno));
|
// memory file.
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open the filename in the current directory.
|
||||||
|
// Cannot use O_TRUNC here; truncation of an existing file has to happen
|
||||||
|
// after the is_file_secure() check below.
|
||||||
|
int result;
|
||||||
|
RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
if (errno == ELOOP) {
|
||||||
|
warning("file %s is a symlink and is not secure\n", filename);
|
||||||
|
} else {
|
||||||
|
warning("could not create file %s: %s\n", filename, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// close the directory and reset the current working directory
|
||||||
|
close_directory_secure_cwd(dirp, saved_cwd_fd);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// close the directory and reset the current working directory
|
||||||
|
close_directory_secure_cwd(dirp, saved_cwd_fd);
|
||||||
|
|
||||||
// save the file descriptor
|
// save the file descriptor
|
||||||
int fd = result;
|
int fd = result;
|
||||||
|
|
||||||
|
// check to see if the file is secure
|
||||||
|
if (!is_file_secure(fd, filename)) {
|
||||||
|
::close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// truncate the file to get rid of any existing data
|
||||||
|
RESTARTABLE(::ftruncate(fd, (off_t)0), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
warning("could not truncate shared memory file: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
::close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
// set the file size
|
// set the file size
|
||||||
RESTARTABLE(::ftruncate(fd, (off_t)size), result);
|
RESTARTABLE(::ftruncate(fd, (off_t)size), result);
|
||||||
if (result == OS_ERR) {
|
if (result == OS_ERR) {
|
||||||
@ -701,8 +906,15 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) {
|
|||||||
THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR);
|
THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int fd = result;
|
||||||
|
|
||||||
return result;
|
// check to see if the file is secure
|
||||||
|
if (!is_file_secure(fd, filename)) {
|
||||||
|
::close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a named shared memory region. returns the address of the
|
// create a named shared memory region. returns the address of the
|
||||||
@ -734,13 +946,21 @@ static char* mmap_create_shared(size_t size) {
|
|||||||
char* dirname = get_user_tmp_dir(user_name);
|
char* dirname = get_user_tmp_dir(user_name);
|
||||||
char* filename = get_sharedmem_filename(dirname, vmid);
|
char* filename = get_sharedmem_filename(dirname, vmid);
|
||||||
|
|
||||||
|
// get the short filename
|
||||||
|
char* short_filename = strrchr(filename, '/');
|
||||||
|
if (short_filename == NULL) {
|
||||||
|
short_filename = filename;
|
||||||
|
} else {
|
||||||
|
short_filename++;
|
||||||
|
}
|
||||||
|
|
||||||
// cleanup any stale shared memory files
|
// cleanup any stale shared memory files
|
||||||
cleanup_sharedmem_resources(dirname);
|
cleanup_sharedmem_resources(dirname);
|
||||||
|
|
||||||
assert(((size > 0) && (size % os::vm_page_size() == 0)),
|
assert(((size > 0) && (size % os::vm_page_size() == 0)),
|
||||||
"unexpected PerfMemory region size");
|
"unexpected PerfMemory region size");
|
||||||
|
|
||||||
fd = create_sharedmem_resources(dirname, filename, size);
|
fd = create_sharedmem_resources(dirname, short_filename, size);
|
||||||
|
|
||||||
FREE_C_HEAP_ARRAY(char, user_name);
|
FREE_C_HEAP_ARRAY(char, user_name);
|
||||||
FREE_C_HEAP_ARRAY(char, dirname);
|
FREE_C_HEAP_ARRAY(char, dirname);
|
||||||
@ -856,12 +1076,12 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor
|
|||||||
// constructs for the file and the shared memory mapping.
|
// constructs for the file and the shared memory mapping.
|
||||||
if (mode == PerfMemory::PERF_MODE_RO) {
|
if (mode == PerfMemory::PERF_MODE_RO) {
|
||||||
mmap_prot = PROT_READ;
|
mmap_prot = PROT_READ;
|
||||||
file_flags = O_RDONLY;
|
file_flags = O_RDONLY | O_NOFOLLOW;
|
||||||
}
|
}
|
||||||
else if (mode == PerfMemory::PERF_MODE_RW) {
|
else if (mode == PerfMemory::PERF_MODE_RW) {
|
||||||
#ifdef LATER
|
#ifdef LATER
|
||||||
mmap_prot = PROT_READ | PROT_WRITE;
|
mmap_prot = PROT_READ | PROT_WRITE;
|
||||||
file_flags = O_RDWR;
|
file_flags = O_RDWR | O_NOFOLLOW;
|
||||||
#else
|
#else
|
||||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||||
"Unsupported access mode");
|
"Unsupported access mode");
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright 2007, 2008, 2011 Red Hat, Inc.
|
* Copyright 2007, 2008, 2011, 2015, Red Hat, Inc.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -237,7 +237,13 @@ inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) {
|
|||||||
// operation. Note that some platforms only support this with the
|
// operation. Note that some platforms only support this with the
|
||||||
// limitation that the only valid value to store is the immediate
|
// limitation that the only valid value to store is the immediate
|
||||||
// constant 1. There is a test for this in JNI_CreateJavaVM().
|
// constant 1. There is a test for this in JNI_CreateJavaVM().
|
||||||
return __sync_lock_test_and_set (dest, exchange_value);
|
jint result = __sync_lock_test_and_set (dest, exchange_value);
|
||||||
|
// All atomic operations are expected to be full memory barriers
|
||||||
|
// (see atomic.hpp). However, __sync_lock_test_and_set is not
|
||||||
|
// a full memory barrier, but an acquire barrier. Hence, this added
|
||||||
|
// barrier.
|
||||||
|
__sync_synchronize();
|
||||||
|
return result;
|
||||||
#endif // M68K
|
#endif // M68K
|
||||||
#endif // ARM
|
#endif // ARM
|
||||||
}
|
}
|
||||||
@ -250,7 +256,9 @@ inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value,
|
|||||||
#ifdef M68K
|
#ifdef M68K
|
||||||
return m68k_lock_test_and_set(dest, exchange_value);
|
return m68k_lock_test_and_set(dest, exchange_value);
|
||||||
#else
|
#else
|
||||||
return __sync_lock_test_and_set (dest, exchange_value);
|
intptr_t result = __sync_lock_test_and_set (dest, exchange_value);
|
||||||
|
__sync_synchronize();
|
||||||
|
return result;
|
||||||
#endif // M68K
|
#endif // M68K
|
||||||
#endif // ARM
|
#endif // ARM
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright 2007, 2008, 2011 Red Hat, Inc.
|
* Copyright 2007, 2008, 2011, 2015, Red Hat, Inc.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -231,7 +231,13 @@ inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) {
|
|||||||
// operation. Note that some platforms only support this with the
|
// operation. Note that some platforms only support this with the
|
||||||
// limitation that the only valid value to store is the immediate
|
// limitation that the only valid value to store is the immediate
|
||||||
// constant 1. There is a test for this in JNI_CreateJavaVM().
|
// constant 1. There is a test for this in JNI_CreateJavaVM().
|
||||||
return __sync_lock_test_and_set (dest, exchange_value);
|
jint result = __sync_lock_test_and_set (dest, exchange_value);
|
||||||
|
// All atomic operations are expected to be full memory barriers
|
||||||
|
// (see atomic.hpp). However, __sync_lock_test_and_set is not
|
||||||
|
// a full memory barrier, but an acquire barrier. Hence, this added
|
||||||
|
// barrier.
|
||||||
|
__sync_synchronize();
|
||||||
|
return result;
|
||||||
#endif // M68K
|
#endif // M68K
|
||||||
#endif // ARM
|
#endif // ARM
|
||||||
}
|
}
|
||||||
@ -244,7 +250,9 @@ inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value,
|
|||||||
#ifdef M68K
|
#ifdef M68K
|
||||||
return m68k_lock_test_and_set(dest, exchange_value);
|
return m68k_lock_test_and_set(dest, exchange_value);
|
||||||
#else
|
#else
|
||||||
return __sync_lock_test_and_set (dest, exchange_value);
|
intptr_t result = __sync_lock_test_and_set (dest, exchange_value);
|
||||||
|
__sync_synchronize();
|
||||||
|
return result;
|
||||||
#endif // M68K
|
#endif // M68K
|
||||||
#endif // ARM
|
#endif // ARM
|
||||||
}
|
}
|
||||||
|
@ -89,8 +89,8 @@ class BCEscapeAnalyzer::StateInfo {
|
|||||||
public:
|
public:
|
||||||
ArgumentMap *_vars;
|
ArgumentMap *_vars;
|
||||||
ArgumentMap *_stack;
|
ArgumentMap *_stack;
|
||||||
short _stack_height;
|
int _stack_height;
|
||||||
short _max_stack;
|
int _max_stack;
|
||||||
bool _initialized;
|
bool _initialized;
|
||||||
ArgumentMap empty_map;
|
ArgumentMap empty_map;
|
||||||
|
|
||||||
|
@ -1905,11 +1905,12 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) {
|
|||||||
InstanceKlass::cast(WK_KLASS(Reference_klass))->set_reference_type(REF_OTHER);
|
InstanceKlass::cast(WK_KLASS(Reference_klass))->set_reference_type(REF_OTHER);
|
||||||
InstanceRefKlass::update_nonstatic_oop_maps(WK_KLASS(Reference_klass));
|
InstanceRefKlass::update_nonstatic_oop_maps(WK_KLASS(Reference_klass));
|
||||||
|
|
||||||
initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(PhantomReference_klass), scan, CHECK);
|
initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Cleaner_klass), scan, CHECK);
|
||||||
InstanceKlass::cast(WK_KLASS(SoftReference_klass))->set_reference_type(REF_SOFT);
|
InstanceKlass::cast(WK_KLASS(SoftReference_klass))->set_reference_type(REF_SOFT);
|
||||||
InstanceKlass::cast(WK_KLASS(WeakReference_klass))->set_reference_type(REF_WEAK);
|
InstanceKlass::cast(WK_KLASS(WeakReference_klass))->set_reference_type(REF_WEAK);
|
||||||
InstanceKlass::cast(WK_KLASS(FinalReference_klass))->set_reference_type(REF_FINAL);
|
InstanceKlass::cast(WK_KLASS(FinalReference_klass))->set_reference_type(REF_FINAL);
|
||||||
InstanceKlass::cast(WK_KLASS(PhantomReference_klass))->set_reference_type(REF_PHANTOM);
|
InstanceKlass::cast(WK_KLASS(PhantomReference_klass))->set_reference_type(REF_PHANTOM);
|
||||||
|
InstanceKlass::cast(WK_KLASS(Cleaner_klass))->set_reference_type(REF_CLEANER);
|
||||||
|
|
||||||
// JSR 292 classes
|
// JSR 292 classes
|
||||||
WKID jsr292_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
|
WKID jsr292_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
|
||||||
|
@ -128,6 +128,7 @@ class Ticks;
|
|||||||
do_klass(WeakReference_klass, java_lang_ref_WeakReference, Pre ) \
|
do_klass(WeakReference_klass, java_lang_ref_WeakReference, Pre ) \
|
||||||
do_klass(FinalReference_klass, java_lang_ref_FinalReference, Pre ) \
|
do_klass(FinalReference_klass, java_lang_ref_FinalReference, Pre ) \
|
||||||
do_klass(PhantomReference_klass, java_lang_ref_PhantomReference, Pre ) \
|
do_klass(PhantomReference_klass, java_lang_ref_PhantomReference, Pre ) \
|
||||||
|
do_klass(Cleaner_klass, sun_misc_Cleaner, Pre ) \
|
||||||
do_klass(Finalizer_klass, java_lang_ref_Finalizer, Pre ) \
|
do_klass(Finalizer_klass, java_lang_ref_Finalizer, Pre ) \
|
||||||
\
|
\
|
||||||
do_klass(Thread_klass, java_lang_Thread, Pre ) \
|
do_klass(Thread_klass, java_lang_Thread, Pre ) \
|
||||||
|
@ -1555,14 +1555,14 @@ void ClassVerifier::verify_method(methodHandle m, TRAPS) {
|
|||||||
case Bytecodes::_invokespecial :
|
case Bytecodes::_invokespecial :
|
||||||
case Bytecodes::_invokestatic :
|
case Bytecodes::_invokestatic :
|
||||||
verify_invoke_instructions(
|
verify_invoke_instructions(
|
||||||
&bcs, code_length, ¤t_frame,
|
&bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max),
|
||||||
&this_uninit, return_type, cp, CHECK_VERIFY(this));
|
&this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this));
|
||||||
no_control_flow = false; break;
|
no_control_flow = false; break;
|
||||||
case Bytecodes::_invokeinterface :
|
case Bytecodes::_invokeinterface :
|
||||||
case Bytecodes::_invokedynamic :
|
case Bytecodes::_invokedynamic :
|
||||||
verify_invoke_instructions(
|
verify_invoke_instructions(
|
||||||
&bcs, code_length, ¤t_frame,
|
&bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max),
|
||||||
&this_uninit, return_type, cp, CHECK_VERIFY(this));
|
&this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this));
|
||||||
no_control_flow = false; break;
|
no_control_flow = false; break;
|
||||||
case Bytecodes::_new :
|
case Bytecodes::_new :
|
||||||
{
|
{
|
||||||
@ -2406,8 +2406,9 @@ bool ClassVerifier::ends_in_athrow(u4 start_bc_offset) {
|
|||||||
|
|
||||||
void ClassVerifier::verify_invoke_init(
|
void ClassVerifier::verify_invoke_init(
|
||||||
RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type,
|
RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type,
|
||||||
StackMapFrame* current_frame, u4 code_length, bool *this_uninit,
|
StackMapFrame* current_frame, u4 code_length, bool in_try_block,
|
||||||
constantPoolHandle cp, TRAPS) {
|
bool *this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table,
|
||||||
|
TRAPS) {
|
||||||
u2 bci = bcs->bci();
|
u2 bci = bcs->bci();
|
||||||
VerificationType type = current_frame->pop_stack(
|
VerificationType type = current_frame->pop_stack(
|
||||||
VerificationType::reference_check(), CHECK_VERIFY(this));
|
VerificationType::reference_check(), CHECK_VERIFY(this));
|
||||||
@ -2423,28 +2424,36 @@ void ClassVerifier::verify_invoke_init(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this call is done from inside of a TRY block. If so, make
|
// If this invokespecial call is done from inside of a TRY block then make
|
||||||
// sure that all catch clause paths end in a throw. Otherwise, this
|
// sure that all catch clause paths end in a throw. Otherwise, this can
|
||||||
// can result in returning an incomplete object.
|
// result in returning an incomplete object.
|
||||||
ExceptionTable exhandlers(_method());
|
if (in_try_block) {
|
||||||
int exlength = exhandlers.length();
|
ExceptionTable exhandlers(_method());
|
||||||
for(int i = 0; i < exlength; i++) {
|
int exlength = exhandlers.length();
|
||||||
u2 start_pc = exhandlers.start_pc(i);
|
for(int i = 0; i < exlength; i++) {
|
||||||
u2 end_pc = exhandlers.end_pc(i);
|
u2 start_pc = exhandlers.start_pc(i);
|
||||||
|
u2 end_pc = exhandlers.end_pc(i);
|
||||||
|
|
||||||
if (bci >= start_pc && bci < end_pc) {
|
if (bci >= start_pc && bci < end_pc) {
|
||||||
if (!ends_in_athrow(exhandlers.handler_pc(i))) {
|
if (!ends_in_athrow(exhandlers.handler_pc(i))) {
|
||||||
verify_error(ErrorContext::bad_code(bci),
|
verify_error(ErrorContext::bad_code(bci),
|
||||||
"Bad <init> method call from after the start of a try block");
|
"Bad <init> method call from after the start of a try block");
|
||||||
return;
|
return;
|
||||||
} else if (VerboseVerification) {
|
} else if (VerboseVerification) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
tty->print_cr(
|
tty->print_cr(
|
||||||
"Survived call to ends_in_athrow(): %s",
|
"Survived call to ends_in_athrow(): %s",
|
||||||
current_class()->name()->as_C_string());
|
current_class()->name()->as_C_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Check the exception handler target stackmaps with the locals from the
|
||||||
|
// incoming stackmap (before initialize_object() changes them to outgoing
|
||||||
|
// state).
|
||||||
|
verify_exception_handler_targets(bci, true, current_frame,
|
||||||
|
stackmap_table, CHECK_VERIFY(this));
|
||||||
|
} // in_try_block
|
||||||
|
|
||||||
current_frame->initialize_object(type, current_type());
|
current_frame->initialize_object(type, current_type());
|
||||||
*this_uninit = true;
|
*this_uninit = true;
|
||||||
@ -2498,6 +2507,13 @@ void ClassVerifier::verify_invoke_init(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Check the exception handler target stackmaps with the locals from the
|
||||||
|
// incoming stackmap (before initialize_object() changes them to outgoing
|
||||||
|
// state).
|
||||||
|
if (in_try_block) {
|
||||||
|
verify_exception_handler_targets(bci, *this_uninit, current_frame,
|
||||||
|
stackmap_table, CHECK_VERIFY(this));
|
||||||
|
}
|
||||||
current_frame->initialize_object(type, new_class_type);
|
current_frame->initialize_object(type, new_class_type);
|
||||||
} else {
|
} else {
|
||||||
verify_error(ErrorContext::bad_type(bci, current_frame->stack_top_ctx()),
|
verify_error(ErrorContext::bad_type(bci, current_frame->stack_top_ctx()),
|
||||||
@ -2526,8 +2542,8 @@ bool ClassVerifier::is_same_or_direct_interface(
|
|||||||
|
|
||||||
void ClassVerifier::verify_invoke_instructions(
|
void ClassVerifier::verify_invoke_instructions(
|
||||||
RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
|
RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
|
||||||
bool *this_uninit, VerificationType return_type,
|
bool in_try_block, bool *this_uninit, VerificationType return_type,
|
||||||
constantPoolHandle cp, TRAPS) {
|
constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS) {
|
||||||
// Make sure the constant pool item is the right type
|
// Make sure the constant pool item is the right type
|
||||||
u2 index = bcs->get_index_u2();
|
u2 index = bcs->get_index_u2();
|
||||||
Bytecodes::Code opcode = bcs->raw_code();
|
Bytecodes::Code opcode = bcs->raw_code();
|
||||||
@ -2693,7 +2709,8 @@ void ClassVerifier::verify_invoke_instructions(
|
|||||||
opcode != Bytecodes::_invokedynamic) {
|
opcode != Bytecodes::_invokedynamic) {
|
||||||
if (method_name == vmSymbols::object_initializer_name()) { // <init> method
|
if (method_name == vmSymbols::object_initializer_name()) { // <init> method
|
||||||
verify_invoke_init(bcs, index, ref_class_type, current_frame,
|
verify_invoke_init(bcs, index, ref_class_type, current_frame,
|
||||||
code_length, this_uninit, cp, CHECK_VERIFY(this));
|
code_length, in_try_block, this_uninit, cp, stackmap_table,
|
||||||
|
CHECK_VERIFY(this));
|
||||||
} else { // other methods
|
} else { // other methods
|
||||||
// Ensures that target class is assignable to method class.
|
// Ensures that target class is assignable to method class.
|
||||||
if (opcode == Bytecodes::_invokespecial) {
|
if (opcode == Bytecodes::_invokespecial) {
|
||||||
|
@ -301,8 +301,9 @@ class ClassVerifier : public StackObj {
|
|||||||
|
|
||||||
void verify_invoke_init(
|
void verify_invoke_init(
|
||||||
RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type,
|
RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type,
|
||||||
StackMapFrame* current_frame, u4 code_length, bool* this_uninit,
|
StackMapFrame* current_frame, u4 code_length, bool in_try_block,
|
||||||
constantPoolHandle cp, TRAPS);
|
bool* this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table,
|
||||||
|
TRAPS);
|
||||||
|
|
||||||
// Used by ends_in_athrow() to push all handlers that contain bci onto
|
// Used by ends_in_athrow() to push all handlers that contain bci onto
|
||||||
// the handler_stack, if the handler is not already on the stack.
|
// the handler_stack, if the handler is not already on the stack.
|
||||||
@ -316,8 +317,8 @@ class ClassVerifier : public StackObj {
|
|||||||
|
|
||||||
void verify_invoke_instructions(
|
void verify_invoke_instructions(
|
||||||
RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
|
RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
|
||||||
bool* this_uninit, VerificationType return_type,
|
bool in_try_block, bool* this_uninit, VerificationType return_type,
|
||||||
constantPoolHandle cp, TRAPS);
|
constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS);
|
||||||
|
|
||||||
VerificationType get_newarray_type(u2 index, u2 bci, TRAPS);
|
VerificationType get_newarray_type(u2 index, u2 bci, TRAPS);
|
||||||
void verify_anewarray(u2 bci, u2 index, constantPoolHandle cp,
|
void verify_anewarray(u2 bci, u2 index, constantPoolHandle cp,
|
||||||
|
@ -79,6 +79,7 @@
|
|||||||
template(java_lang_ref_WeakReference, "java/lang/ref/WeakReference") \
|
template(java_lang_ref_WeakReference, "java/lang/ref/WeakReference") \
|
||||||
template(java_lang_ref_FinalReference, "java/lang/ref/FinalReference") \
|
template(java_lang_ref_FinalReference, "java/lang/ref/FinalReference") \
|
||||||
template(java_lang_ref_PhantomReference, "java/lang/ref/PhantomReference") \
|
template(java_lang_ref_PhantomReference, "java/lang/ref/PhantomReference") \
|
||||||
|
template(sun_misc_Cleaner, "sun/misc/Cleaner") \
|
||||||
template(java_lang_ref_Finalizer, "java/lang/ref/Finalizer") \
|
template(java_lang_ref_Finalizer, "java/lang/ref/Finalizer") \
|
||||||
template(java_lang_reflect_AccessibleObject, "java/lang/reflect/AccessibleObject") \
|
template(java_lang_reflect_AccessibleObject, "java/lang/reflect/AccessibleObject") \
|
||||||
template(java_lang_reflect_Method, "java/lang/reflect/Method") \
|
template(java_lang_reflect_Method, "java/lang/reflect/Method") \
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -560,7 +560,7 @@ void Dependencies::print_dependency(DepType dept, GrowableArray<DepArgument>* ar
|
|||||||
put_star = !Dependencies::is_concrete_klass((Klass*)arg.metadata_value());
|
put_star = !Dependencies::is_concrete_klass((Klass*)arg.metadata_value());
|
||||||
} else if (arg.is_method()) {
|
} else if (arg.is_method()) {
|
||||||
what = "method ";
|
what = "method ";
|
||||||
put_star = !Dependencies::is_concrete_method((Method*)arg.metadata_value());
|
put_star = !Dependencies::is_concrete_method((Method*)arg.metadata_value(), NULL);
|
||||||
} else if (arg.is_klass()) {
|
} else if (arg.is_klass()) {
|
||||||
what = "class ";
|
what = "class ";
|
||||||
} else {
|
} else {
|
||||||
@ -878,8 +878,8 @@ class ClassHierarchyWalker {
|
|||||||
// Static methods don't override non-static so punt
|
// Static methods don't override non-static so punt
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ( !Dependencies::is_concrete_method(lm)
|
if ( !Dependencies::is_concrete_method(lm, k)
|
||||||
&& !Dependencies::is_concrete_method(m)
|
&& !Dependencies::is_concrete_method(m, ctxk)
|
||||||
&& lm->method_holder()->is_subtype_of(m->method_holder()))
|
&& lm->method_holder()->is_subtype_of(m->method_holder()))
|
||||||
// Method m is overridden by lm, but both are non-concrete.
|
// Method m is overridden by lm, but both are non-concrete.
|
||||||
return true;
|
return true;
|
||||||
@ -915,8 +915,17 @@ class ClassHierarchyWalker {
|
|||||||
} else if (!k->oop_is_instance()) {
|
} else if (!k->oop_is_instance()) {
|
||||||
return false; // no methods to find in an array type
|
return false; // no methods to find in an array type
|
||||||
} else {
|
} else {
|
||||||
Method* m = InstanceKlass::cast(k)->find_method(_name, _signature);
|
// Search class hierarchy first.
|
||||||
if (m == NULL || !Dependencies::is_concrete_method(m)) return false;
|
Method* m = InstanceKlass::cast(k)->find_instance_method(_name, _signature);
|
||||||
|
if (!Dependencies::is_concrete_method(m, k)) {
|
||||||
|
// Check interface defaults also, if any exist.
|
||||||
|
Array<Method*>* default_methods = InstanceKlass::cast(k)->default_methods();
|
||||||
|
if (default_methods == NULL)
|
||||||
|
return false;
|
||||||
|
m = InstanceKlass::cast(k)->find_method(default_methods, _name, _signature);
|
||||||
|
if (!Dependencies::is_concrete_method(m, NULL))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
_found_methods[_num_participants] = m;
|
_found_methods[_num_participants] = m;
|
||||||
// Note: If add_participant(k) is called,
|
// Note: If add_participant(k) is called,
|
||||||
// the method m will already be memoized for it.
|
// the method m will already be memoized for it.
|
||||||
@ -1209,15 +1218,17 @@ bool Dependencies::is_concrete_klass(Klass* k) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Dependencies::is_concrete_method(Method* m) {
|
bool Dependencies::is_concrete_method(Method* m, Klass * k) {
|
||||||
// Statics are irrelevant to virtual call sites.
|
// NULL is not a concrete method,
|
||||||
if (m->is_static()) return false;
|
// statics are irrelevant to virtual call sites,
|
||||||
|
// abstract methods are not concrete,
|
||||||
// We could also return false if m does not yet appear to be
|
// overpass (error) methods are not concrete if k is abstract
|
||||||
// executed, if the VM version supports this distinction also.
|
//
|
||||||
// Default methods are considered "concrete" as well.
|
// note "true" is conservative answer --
|
||||||
return !m->is_abstract() &&
|
// overpass clause is false if k == NULL, implies return true if
|
||||||
!m->is_overpass(); // error functions aren't concrete
|
// answer depends on overpass clause.
|
||||||
|
return ! ( m == NULL || m -> is_static() || m -> is_abstract() ||
|
||||||
|
m->is_overpass() && k != NULL && k -> is_abstract() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1242,16 +1253,6 @@ bool Dependencies::is_concrete_klass(ciInstanceKlass* k) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Dependencies::is_concrete_method(ciMethod* m) {
|
|
||||||
// Statics are irrelevant to virtual call sites.
|
|
||||||
if (m->is_static()) return false;
|
|
||||||
|
|
||||||
// We could also return false if m does not yet appear to be
|
|
||||||
// executed, if the VM version supports this distinction also.
|
|
||||||
return !m->is_abstract();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Dependencies::has_finalizable_subclass(ciInstanceKlass* k) {
|
bool Dependencies::has_finalizable_subclass(ciInstanceKlass* k) {
|
||||||
return k->has_finalizable_subclass();
|
return k->has_finalizable_subclass();
|
||||||
}
|
}
|
||||||
@ -1469,7 +1470,7 @@ Method* Dependencies::find_unique_concrete_method(Klass* ctxk, Method* m) {
|
|||||||
Klass* wit = wf.find_witness_definer(ctxk);
|
Klass* wit = wf.find_witness_definer(ctxk);
|
||||||
if (wit != NULL) return NULL; // Too many witnesses.
|
if (wit != NULL) return NULL; // Too many witnesses.
|
||||||
Method* fm = wf.found_method(0); // Will be NULL if num_parts == 0.
|
Method* fm = wf.found_method(0); // Will be NULL if num_parts == 0.
|
||||||
if (Dependencies::is_concrete_method(m)) {
|
if (Dependencies::is_concrete_method(m, ctxk)) {
|
||||||
if (fm == NULL) {
|
if (fm == NULL) {
|
||||||
// It turns out that m was always the only implementation.
|
// It turns out that m was always the only implementation.
|
||||||
fm = m;
|
fm = m;
|
||||||
@ -1499,61 +1500,6 @@ Klass* Dependencies::check_exclusive_concrete_methods(Klass* ctxk,
|
|||||||
return wf.find_witness_definer(ctxk, changes);
|
return wf.find_witness_definer(ctxk, changes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the set of all non-abstract methods under ctxk that match m[0].
|
|
||||||
// (The method m[0] must be defined or inherited in ctxk.)
|
|
||||||
// Include m itself in the set, unless it is abstract.
|
|
||||||
// Fill the given array m[0..(mlen-1)] with this set, and return the length.
|
|
||||||
// (The length may be zero if no concrete methods are found anywhere.)
|
|
||||||
// If there are too many concrete methods to fit in marray, return -1.
|
|
||||||
int Dependencies::find_exclusive_concrete_methods(Klass* ctxk,
|
|
||||||
int mlen,
|
|
||||||
Method* marray[]) {
|
|
||||||
Method* m0 = marray[0];
|
|
||||||
ClassHierarchyWalker wf(m0);
|
|
||||||
assert(wf.check_method_context(ctxk, m0), "proper context");
|
|
||||||
wf.record_witnesses(mlen);
|
|
||||||
bool participants_hide_witnesses = true;
|
|
||||||
Klass* wit = wf.find_witness_definer(ctxk);
|
|
||||||
if (wit != NULL) return -1; // Too many witnesses.
|
|
||||||
int num = wf.num_participants();
|
|
||||||
assert(num <= mlen, "oob");
|
|
||||||
// Keep track of whether m is also part of the result set.
|
|
||||||
int mfill = 0;
|
|
||||||
assert(marray[mfill] == m0, "sanity");
|
|
||||||
if (Dependencies::is_concrete_method(m0))
|
|
||||||
mfill++; // keep m0 as marray[0], the first result
|
|
||||||
for (int i = 0; i < num; i++) {
|
|
||||||
Method* fm = wf.found_method(i);
|
|
||||||
if (fm == m0) continue; // Already put this guy in the list.
|
|
||||||
if (mfill == mlen) {
|
|
||||||
return -1; // Oops. Too many methods after all!
|
|
||||||
}
|
|
||||||
marray[mfill++] = fm;
|
|
||||||
}
|
|
||||||
#ifndef PRODUCT
|
|
||||||
// Make sure the dependency mechanism will pass this discovery:
|
|
||||||
if (VerifyDependencies) {
|
|
||||||
// Turn off dependency tracing while actually testing deps.
|
|
||||||
FlagSetting fs(TraceDependencies, false);
|
|
||||||
switch (mfill) {
|
|
||||||
case 1:
|
|
||||||
guarantee(NULL == (void *)check_unique_concrete_method(ctxk, marray[0]),
|
|
||||||
"verify dep.");
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
guarantee(NULL == (void *)
|
|
||||||
check_exclusive_concrete_methods(ctxk, marray[0], marray[1]),
|
|
||||||
"verify dep.");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ShouldNotReachHere(); // mlen > 2 yet supported
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif //PRODUCT
|
|
||||||
return mfill;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Klass* Dependencies::check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepChange* changes) {
|
Klass* Dependencies::check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepChange* changes) {
|
||||||
Klass* search_at = ctxk;
|
Klass* search_at = ctxk;
|
||||||
if (changes != NULL)
|
if (changes != NULL)
|
||||||
@ -1561,7 +1507,6 @@ Klass* Dependencies::check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepCh
|
|||||||
return find_finalizable_subclass(search_at);
|
return find_finalizable_subclass(search_at);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Klass* Dependencies::check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes) {
|
Klass* Dependencies::check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes) {
|
||||||
assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "sanity");
|
assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "sanity");
|
||||||
assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "sanity");
|
assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "sanity");
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -288,7 +288,7 @@ class Dependencies: public ResourceObj {
|
|||||||
// In that case, there would be a middle ground between concrete
|
// In that case, there would be a middle ground between concrete
|
||||||
// and abstract (as defined by the Java language and VM).
|
// and abstract (as defined by the Java language and VM).
|
||||||
static bool is_concrete_klass(Klass* k); // k is instantiable
|
static bool is_concrete_klass(Klass* k); // k is instantiable
|
||||||
static bool is_concrete_method(Method* m); // m is invocable
|
static bool is_concrete_method(Method* m, Klass* k); // m is invocable
|
||||||
static Klass* find_finalizable_subclass(Klass* k);
|
static Klass* find_finalizable_subclass(Klass* k);
|
||||||
|
|
||||||
// These versions of the concreteness queries work through the CI.
|
// These versions of the concreteness queries work through the CI.
|
||||||
@ -302,7 +302,6 @@ class Dependencies: public ResourceObj {
|
|||||||
// not go back into the VM to get their value; they must cache the
|
// not go back into the VM to get their value; they must cache the
|
||||||
// bit in the CI, either eagerly or lazily.)
|
// bit in the CI, either eagerly or lazily.)
|
||||||
static bool is_concrete_klass(ciInstanceKlass* k); // k appears instantiable
|
static bool is_concrete_klass(ciInstanceKlass* k); // k appears instantiable
|
||||||
static bool is_concrete_method(ciMethod* m); // m appears invocable
|
|
||||||
static bool has_finalizable_subclass(ciInstanceKlass* k);
|
static bool has_finalizable_subclass(ciInstanceKlass* k);
|
||||||
|
|
||||||
// As a general rule, it is OK to compile under the assumption that
|
// As a general rule, it is OK to compile under the assumption that
|
||||||
@ -349,7 +348,6 @@ class Dependencies: public ResourceObj {
|
|||||||
static Klass* find_unique_concrete_subtype(Klass* ctxk);
|
static Klass* find_unique_concrete_subtype(Klass* ctxk);
|
||||||
static Method* find_unique_concrete_method(Klass* ctxk, Method* m);
|
static Method* find_unique_concrete_method(Klass* ctxk, Method* m);
|
||||||
static int find_exclusive_concrete_subtypes(Klass* ctxk, int klen, Klass* k[]);
|
static int find_exclusive_concrete_subtypes(Klass* ctxk, int klen, Klass* k[]);
|
||||||
static int find_exclusive_concrete_methods(Klass* ctxk, int mlen, Method* m[]);
|
|
||||||
|
|
||||||
// Create the encoding which will be stored in an nmethod.
|
// Create the encoding which will be stored in an nmethod.
|
||||||
void encode_content_bytes();
|
void encode_content_bytes();
|
||||||
|
@ -252,7 +252,7 @@ CompileTask* CompileTask::allocate() {
|
|||||||
} else {
|
} else {
|
||||||
task = new CompileTask();
|
task = new CompileTask();
|
||||||
DEBUG_ONLY(_num_allocated_tasks++;)
|
DEBUG_ONLY(_num_allocated_tasks++;)
|
||||||
assert (_num_allocated_tasks < 10000, "Leaking compilation tasks?");
|
assert (WhiteBoxAPI || _num_allocated_tasks < 10000, "Leaking compilation tasks?");
|
||||||
task->set_next(NULL);
|
task->set_next(NULL);
|
||||||
task->set_is_free(true);
|
task->set_is_free(true);
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,6 @@ class MethodMatcher : public CHeapObj<mtCompiler> {
|
|||||||
tty->print(".");
|
tty->print(".");
|
||||||
print_symbol(method_name(), _method_mode);
|
print_symbol(method_name(), _method_mode);
|
||||||
if (signature() != NULL) {
|
if (signature() != NULL) {
|
||||||
tty->print(" ");
|
|
||||||
signature()->print_symbol_on(tty);
|
signature()->print_symbol_on(tty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -467,43 +466,85 @@ static OracleCommand parse_command_name(const char * line, int* bytes_read) {
|
|||||||
return UnknownCommand;
|
return UnknownCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void usage() {
|
static void usage() {
|
||||||
tty->print_cr(" CompileCommand and the CompilerOracle allows simple control over");
|
|
||||||
tty->print_cr(" what's allowed to be compiled. The standard supported directives");
|
|
||||||
tty->print_cr(" are exclude and compileonly. The exclude directive stops a method");
|
|
||||||
tty->print_cr(" from being compiled and compileonly excludes all methods except for");
|
|
||||||
tty->print_cr(" the ones mentioned by compileonly directives. The basic form of");
|
|
||||||
tty->print_cr(" all commands is a command name followed by the name of the method");
|
|
||||||
tty->print_cr(" in one of two forms: the standard class file format as in");
|
|
||||||
tty->print_cr(" class/name.methodName or the PrintCompilation format");
|
|
||||||
tty->print_cr(" class.name::methodName. The method name can optionally be followed");
|
|
||||||
tty->print_cr(" by a space then the signature of the method in the class file");
|
|
||||||
tty->print_cr(" format. Otherwise the directive applies to all methods with the");
|
|
||||||
tty->print_cr(" same name and class regardless of signature. Leading and trailing");
|
|
||||||
tty->print_cr(" *'s in the class and/or method name allows a small amount of");
|
|
||||||
tty->print_cr(" wildcarding. ");
|
|
||||||
tty->cr();
|
tty->cr();
|
||||||
tty->print_cr(" Examples:");
|
tty->print_cr("The CompileCommand option enables the user of the JVM to control specific");
|
||||||
|
tty->print_cr("behavior of the dynamic compilers. Many commands require a pattern that defines");
|
||||||
|
tty->print_cr("the set of methods the command shall be applied to. The CompileCommand");
|
||||||
|
tty->print_cr("option provides the following commands:");
|
||||||
tty->cr();
|
tty->cr();
|
||||||
tty->print_cr(" exclude java/lang/StringBuffer.append");
|
tty->print_cr(" break,<pattern> - debug breakpoint in compiler and in generated code");
|
||||||
tty->print_cr(" compileonly java/lang/StringBuffer.toString ()Ljava/lang/String;");
|
tty->print_cr(" print,<pattern> - print assembly");
|
||||||
tty->print_cr(" exclude java/lang/String*.*");
|
tty->print_cr(" exclude,<pattern> - don't compile or inline");
|
||||||
tty->print_cr(" exclude *.toString");
|
tty->print_cr(" inline,<pattern> - always inline");
|
||||||
}
|
tty->print_cr(" dontinline,<pattern> - don't inline");
|
||||||
|
tty->print_cr(" compileonly,<pattern> - compile only");
|
||||||
|
tty->print_cr(" log,<pattern> - log compilation");
|
||||||
|
tty->print_cr(" option,<pattern>,<option type>,<option name>,<value>");
|
||||||
|
tty->print_cr(" - set value of custom option");
|
||||||
|
tty->print_cr(" option,<pattern>,<bool option name>");
|
||||||
|
tty->print_cr(" - shorthand for setting boolean flag");
|
||||||
|
tty->print_cr(" quiet - silence the compile command output");
|
||||||
|
tty->print_cr(" help - print this text");
|
||||||
|
tty->cr();
|
||||||
|
tty->print_cr("The preferred format for the method matching pattern is:");
|
||||||
|
tty->print_cr(" package/Class.method()");
|
||||||
|
tty->cr();
|
||||||
|
tty->print_cr("For backward compatibility this form is also allowed:");
|
||||||
|
tty->print_cr(" package.Class::method()");
|
||||||
|
tty->cr();
|
||||||
|
tty->print_cr("The signature can be separated by an optional whitespace or comma:");
|
||||||
|
tty->print_cr(" package/Class.method ()");
|
||||||
|
tty->cr();
|
||||||
|
tty->print_cr("The class and method identifier can be used together with leading or");
|
||||||
|
tty->print_cr("trailing *'s for a small amount of wildcarding:");
|
||||||
|
tty->print_cr(" *ackage/Clas*.*etho*()");
|
||||||
|
tty->cr();
|
||||||
|
tty->print_cr("It is possible to use more than one CompileCommand on the command line:");
|
||||||
|
tty->print_cr(" -XX:CompileCommand=exclude,java/*.* -XX:CompileCommand=log,java*.*");
|
||||||
|
tty->cr();
|
||||||
|
tty->print_cr("The CompileCommands can be loaded from a file with the flag");
|
||||||
|
tty->print_cr("-XX:CompileCommandFile=<file> or be added to the file '.hotspot_compiler'");
|
||||||
|
tty->print_cr("Use the same format in the file as the argument to the CompileCommand flag.");
|
||||||
|
tty->print_cr("Add one command on each line.");
|
||||||
|
tty->print_cr(" exclude java/*.*");
|
||||||
|
tty->print_cr(" option java/*.* ReplayInline");
|
||||||
|
tty->cr();
|
||||||
|
tty->print_cr("The following commands have conflicting behavior: 'exclude', 'inline', 'dontinline',");
|
||||||
|
tty->print_cr("and 'compileonly'. There is no priority of commands. Applying (a subset of) these");
|
||||||
|
tty->print_cr("commands to the same method results in undefined behavior.");
|
||||||
|
tty->cr();
|
||||||
|
};
|
||||||
|
|
||||||
|
// The JVM specification defines the allowed characters.
|
||||||
|
// Tokens that are disallowed by the JVM specification can have
|
||||||
|
// a meaning to the parser so we need to include them here.
|
||||||
|
// The parser does not enforce all rules of the JVMS - a successful parse
|
||||||
|
// does not mean that it is an allowed name. Illegal names will
|
||||||
|
// be ignored since they never can match a class or method.
|
||||||
|
//
|
||||||
|
// '\0' and 0xf0-0xff are disallowed in constant string values
|
||||||
|
// 0x20 ' ', 0x09 '\t' and, 0x2c ',' are used in the matching
|
||||||
|
// 0x5b '[' and 0x5d ']' can not be used because of the matcher
|
||||||
|
// 0x28 '(' and 0x29 ')' are used for the signature
|
||||||
|
// 0x2e '.' is always replaced before the matching
|
||||||
|
// 0x2f '/' is only used in the class name as package separator
|
||||||
|
|
||||||
// The characters allowed in a class or method name. All characters > 0x7f
|
#define RANGEBASE "\x1\x2\x3\x4\x5\x6\x7\x8\xa\xb\xc\xd\xe\xf" \
|
||||||
// are allowed in order to handle obfuscated class files (e.g. Volano)
|
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
|
||||||
#define RANGEBASE "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$_<>" \
|
"\x21\x22\x23\x24\x25\x26\x27\x2a\x2b\x2c\x2d" \
|
||||||
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" \
|
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \
|
||||||
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" \
|
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \
|
||||||
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" \
|
"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5c\x5e\x5f" \
|
||||||
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" \
|
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \
|
||||||
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" \
|
"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" \
|
||||||
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" \
|
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" \
|
||||||
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" \
|
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" \
|
||||||
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
|
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" \
|
||||||
|
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" \
|
||||||
|
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" \
|
||||||
|
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" \
|
||||||
|
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"
|
||||||
|
|
||||||
#define RANGE0 "[*" RANGEBASE "]"
|
#define RANGE0 "[*" RANGEBASE "]"
|
||||||
#define RANGESLASH "[*" RANGEBASE "/]"
|
#define RANGESLASH "[*" RANGEBASE "/]"
|
||||||
@ -681,8 +722,9 @@ void CompilerOracle::parse_from_line(char* line) {
|
|||||||
|
|
||||||
if (command == UnknownCommand) {
|
if (command == UnknownCommand) {
|
||||||
ttyLocker ttyl;
|
ttyLocker ttyl;
|
||||||
tty->print_cr("CompilerOracle: unrecognized line");
|
tty->print_cr("CompileCommand: unrecognized command");
|
||||||
tty->print_cr(" \"%s\"", original_line);
|
tty->print_cr(" \"%s\"", original_line);
|
||||||
|
CompilerOracle::print_tip();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,9 +754,17 @@ void CompilerOracle::parse_from_line(char* line) {
|
|||||||
Symbol* signature = NULL;
|
Symbol* signature = NULL;
|
||||||
|
|
||||||
line += bytes_read;
|
line += bytes_read;
|
||||||
|
|
||||||
|
// Skip any leading spaces before signature
|
||||||
|
int whitespace_read = 0;
|
||||||
|
sscanf(line, "%*[ \t]%n", &whitespace_read);
|
||||||
|
if (whitespace_read > 0) {
|
||||||
|
line += whitespace_read;
|
||||||
|
}
|
||||||
|
|
||||||
// there might be a signature following the method.
|
// there might be a signature following the method.
|
||||||
// signatures always begin with ( so match that by hand
|
// signatures always begin with ( so match that by hand
|
||||||
if (1 == sscanf(line, "%*[ \t](%254[[);/" RANGEBASE "]%n", sig + 1, &bytes_read)) {
|
if (1 == sscanf(line, "(%254[[);/" RANGEBASE "]%n", sig + 1, &bytes_read)) {
|
||||||
sig[0] = '(';
|
sig[0] = '(';
|
||||||
line += bytes_read;
|
line += bytes_read;
|
||||||
signature = SymbolTable::new_symbol(sig, CHECK);
|
signature = SymbolTable::new_symbol(sig, CHECK);
|
||||||
@ -740,7 +790,7 @@ void CompilerOracle::parse_from_line(char* line) {
|
|||||||
if (match != NULL && !_quiet) {
|
if (match != NULL && !_quiet) {
|
||||||
// Print out the last match added
|
// Print out the last match added
|
||||||
ttyLocker ttyl;
|
ttyLocker ttyl;
|
||||||
tty->print("CompilerOracle: %s ", command_names[command]);
|
tty->print("CompileCommand: %s ", command_names[command]);
|
||||||
match->print();
|
match->print();
|
||||||
}
|
}
|
||||||
line += bytes_read;
|
line += bytes_read;
|
||||||
@ -775,26 +825,36 @@ void CompilerOracle::parse_from_line(char* line) {
|
|||||||
ttyLocker ttyl;
|
ttyLocker ttyl;
|
||||||
if (error_msg != NULL) {
|
if (error_msg != NULL) {
|
||||||
// an error has happened
|
// an error has happened
|
||||||
tty->print_cr("CompilerOracle: unrecognized line");
|
tty->print_cr("CompileCommand: An error occured during parsing");
|
||||||
tty->print_cr(" \"%s\"", original_line);
|
tty->print_cr(" \"%s\"", original_line);
|
||||||
if (error_msg != NULL) {
|
if (error_msg != NULL) {
|
||||||
tty->print_cr("%s", error_msg);
|
tty->print_cr("%s", error_msg);
|
||||||
}
|
}
|
||||||
|
CompilerOracle::print_tip();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// check for remaining characters
|
// check for remaining characters
|
||||||
bytes_read = 0;
|
bytes_read = 0;
|
||||||
sscanf(line, "%*[ \t]%n", &bytes_read);
|
sscanf(line, "%*[ \t]%n", &bytes_read);
|
||||||
if (line[bytes_read] != '\0') {
|
if (line[bytes_read] != '\0') {
|
||||||
tty->print_cr("CompilerOracle: unrecognized line");
|
tty->print_cr("CompileCommand: Bad pattern");
|
||||||
tty->print_cr(" \"%s\"", original_line);
|
tty->print_cr(" \"%s\"", original_line);
|
||||||
tty->print_cr(" Unrecognized text %s after command ", line);
|
tty->print_cr(" Unrecognized text %s after command ", line);
|
||||||
|
CompilerOracle::print_tip();
|
||||||
} else if (match != NULL && !_quiet) {
|
} else if (match != NULL && !_quiet) {
|
||||||
tty->print("CompilerOracle: %s ", command_names[command]);
|
tty->print("CompileCommand: %s ", command_names[command]);
|
||||||
match->print();
|
match->print();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompilerOracle::print_tip() {
|
||||||
|
tty->cr();
|
||||||
|
tty->print_cr("Usage: '-XX:CompileCommand=command,\"package/Class.method()\"'");
|
||||||
|
tty->print_cr("Use: '-XX:CompileCommand=help' for more information.");
|
||||||
|
tty->cr();
|
||||||
|
}
|
||||||
|
|
||||||
static const char* default_cc_file = ".hotspot_compiler";
|
static const char* default_cc_file = ".hotspot_compiler";
|
||||||
|
|
||||||
static const char* cc_file() {
|
static const char* cc_file() {
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
class CompilerOracle : AllStatic {
|
class CompilerOracle : AllStatic {
|
||||||
private:
|
private:
|
||||||
static bool _quiet;
|
static bool _quiet;
|
||||||
|
static void print_tip();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -645,7 +645,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
|||||||
// Support for parallelizing survivor space rescan
|
// Support for parallelizing survivor space rescan
|
||||||
if ((CMSParallelRemarkEnabled && CMSParallelSurvivorRemarkEnabled) || CMSParallelInitialMarkEnabled) {
|
if ((CMSParallelRemarkEnabled && CMSParallelSurvivorRemarkEnabled) || CMSParallelInitialMarkEnabled) {
|
||||||
const size_t max_plab_samples =
|
const size_t max_plab_samples =
|
||||||
((DefNewGeneration*)_young_gen)->max_survivor_size()/MinTLABSize;
|
((DefNewGeneration*)_young_gen)->max_survivor_size() / plab_sample_minimum_size();
|
||||||
|
|
||||||
_survivor_plab_array = NEW_C_HEAP_ARRAY(ChunkArray, ParallelGCThreads, mtGC);
|
_survivor_plab_array = NEW_C_HEAP_ARRAY(ChunkArray, ParallelGCThreads, mtGC);
|
||||||
_survivor_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, 2*max_plab_samples, mtGC);
|
_survivor_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, 2*max_plab_samples, mtGC);
|
||||||
@ -703,6 +703,12 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
|||||||
_inter_sweep_timer.start(); // start of time
|
_inter_sweep_timer.start(); // start of time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CMSCollector::plab_sample_minimum_size() {
|
||||||
|
// The default value of MinTLABSize is 2k, but there is
|
||||||
|
// no way to get the default value if the flag has been overridden.
|
||||||
|
return MAX2(ThreadLocalAllocBuffer::min_size() * HeapWordSize, 2 * K);
|
||||||
|
}
|
||||||
|
|
||||||
const char* ConcurrentMarkSweepGeneration::name() const {
|
const char* ConcurrentMarkSweepGeneration::name() const {
|
||||||
return "concurrent mark-sweep generation";
|
return "concurrent mark-sweep generation";
|
||||||
}
|
}
|
||||||
|
@ -737,6 +737,10 @@ class CMSCollector: public CHeapObj<mtGC> {
|
|||||||
size_t* _cursor;
|
size_t* _cursor;
|
||||||
ChunkArray* _survivor_plab_array;
|
ChunkArray* _survivor_plab_array;
|
||||||
|
|
||||||
|
// A bounded minimum size of PLABs, should not return too small values since
|
||||||
|
// this will affect the size of the data structures used for parallel young gen rescan
|
||||||
|
size_t plab_sample_minimum_size();
|
||||||
|
|
||||||
// Support for marking stack overflow handling
|
// Support for marking stack overflow handling
|
||||||
bool take_from_overflow_list(size_t num, CMSMarkStack* to_stack);
|
bool take_from_overflow_list(size_t num, CMSMarkStack* to_stack);
|
||||||
bool par_take_from_overflow_list(size_t num,
|
bool par_take_from_overflow_list(size_t num,
|
||||||
|
@ -1910,7 +1910,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void work(uint worker_id) {
|
void work(uint worker_id) {
|
||||||
double start = os::elapsedTime();
|
|
||||||
FreeRegionList local_cleanup_list("Local Cleanup List");
|
FreeRegionList local_cleanup_list("Local Cleanup List");
|
||||||
HRRSCleanupTask hrrs_cleanup_task;
|
HRRSCleanupTask hrrs_cleanup_task;
|
||||||
G1NoteEndOfConcMarkClosure g1_note_end(_g1h, &local_cleanup_list,
|
G1NoteEndOfConcMarkClosure g1_note_end(_g1h, &local_cleanup_list,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -47,6 +47,13 @@ public:
|
|||||||
// active field set to true.
|
// active field set to true.
|
||||||
PtrQueue(qset_, perm, true /* active */) { }
|
PtrQueue(qset_, perm, true /* active */) { }
|
||||||
|
|
||||||
|
// Flush before destroying; queue may be used to capture pending work while
|
||||||
|
// doing something else, with auto-flush on completion.
|
||||||
|
~DirtyCardQueue() { if (!is_permanent()) flush(); }
|
||||||
|
|
||||||
|
// Process queue entries and release resources.
|
||||||
|
void flush() { flush_impl(); }
|
||||||
|
|
||||||
// Apply the closure to all elements, and reset the index to make the
|
// Apply the closure to all elements, and reset the index to make the
|
||||||
// buffer empty. If a closure application returns "false", return
|
// buffer empty. If a closure application returns "false", return
|
||||||
// "false" immediately, halting the iteration. If "consume" is true,
|
// "false" immediately, halting the iteration. If "consume" is true,
|
||||||
|
@ -1229,7 +1229,6 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
|
|||||||
TraceCollectorStats tcs(g1mm()->full_collection_counters());
|
TraceCollectorStats tcs(g1mm()->full_collection_counters());
|
||||||
TraceMemoryManagerStats tms(true /* fullGC */, gc_cause());
|
TraceMemoryManagerStats tms(true /* fullGC */, gc_cause());
|
||||||
|
|
||||||
double start = os::elapsedTime();
|
|
||||||
g1_policy()->record_full_collection_start();
|
g1_policy()->record_full_collection_start();
|
||||||
|
|
||||||
// Note: When we have a more flexible GC logging framework that
|
// Note: When we have a more flexible GC logging framework that
|
||||||
@ -1436,7 +1435,6 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
|
|||||||
|
|
||||||
_allocator->init_mutator_alloc_region();
|
_allocator->init_mutator_alloc_region();
|
||||||
|
|
||||||
double end = os::elapsedTime();
|
|
||||||
g1_policy()->record_full_collection_end();
|
g1_policy()->record_full_collection_end();
|
||||||
|
|
||||||
if (G1Log::fine()) {
|
if (G1Log::fine()) {
|
||||||
|
@ -56,7 +56,6 @@ class HRRSCleanupTask;
|
|||||||
class GenerationSpec;
|
class GenerationSpec;
|
||||||
class OopsInHeapRegionClosure;
|
class OopsInHeapRegionClosure;
|
||||||
class G1KlassScanClosure;
|
class G1KlassScanClosure;
|
||||||
class G1ScanHeapEvacClosure;
|
|
||||||
class ObjectClosure;
|
class ObjectClosure;
|
||||||
class SpaceClosure;
|
class SpaceClosure;
|
||||||
class CompactibleSpaceClosure;
|
class CompactibleSpaceClosure;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -153,14 +153,6 @@ G1CollectorPolicy::G1CollectorPolicy() :
|
|||||||
_inc_cset_predicted_elapsed_time_ms(0.0),
|
_inc_cset_predicted_elapsed_time_ms(0.0),
|
||||||
_inc_cset_predicted_elapsed_time_ms_diffs(0.0),
|
_inc_cset_predicted_elapsed_time_ms_diffs(0.0),
|
||||||
|
|
||||||
#ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away
|
|
||||||
#pragma warning( disable:4355 ) // 'this' : used in base member initializer list
|
|
||||||
#endif // _MSC_VER
|
|
||||||
|
|
||||||
_short_lived_surv_rate_group(new SurvRateGroup(this, "Short Lived",
|
|
||||||
G1YoungSurvRateNumRegionsSummary)),
|
|
||||||
_survivor_surv_rate_group(new SurvRateGroup(this, "Survivor",
|
|
||||||
G1YoungSurvRateNumRegionsSummary)),
|
|
||||||
// add here any more surv rate groups
|
// add here any more surv rate groups
|
||||||
_recorded_survivor_regions(0),
|
_recorded_survivor_regions(0),
|
||||||
_recorded_survivor_head(NULL),
|
_recorded_survivor_head(NULL),
|
||||||
@ -169,6 +161,22 @@ G1CollectorPolicy::G1CollectorPolicy() :
|
|||||||
|
|
||||||
_gc_overhead_perc(0.0) {
|
_gc_overhead_perc(0.0) {
|
||||||
|
|
||||||
|
uintx confidence_perc = G1ConfidencePercent;
|
||||||
|
// Put an artificial ceiling on this so that it's not set to a silly value.
|
||||||
|
if (confidence_perc > 100) {
|
||||||
|
confidence_perc = 100;
|
||||||
|
warning("G1ConfidencePercent is set to a value that is too large, "
|
||||||
|
"it's been updated to %u", confidence_perc);
|
||||||
|
}
|
||||||
|
// '_sigma' must be initialized before the SurvRateGroups below because they
|
||||||
|
// indirecty access '_sigma' trough the 'this' pointer in their constructor.
|
||||||
|
_sigma = (double) confidence_perc / 100.0;
|
||||||
|
|
||||||
|
_short_lived_surv_rate_group =
|
||||||
|
new SurvRateGroup(this, "Short Lived", G1YoungSurvRateNumRegionsSummary);
|
||||||
|
_survivor_surv_rate_group =
|
||||||
|
new SurvRateGroup(this, "Survivor", G1YoungSurvRateNumRegionsSummary);
|
||||||
|
|
||||||
// Set up the region size and associated fields. Given that the
|
// Set up the region size and associated fields. Given that the
|
||||||
// policy is created before the heap, we have to set this up here,
|
// policy is created before the heap, we have to set this up here,
|
||||||
// so it's done as soon as possible.
|
// so it's done as soon as possible.
|
||||||
@ -283,15 +291,6 @@ G1CollectorPolicy::G1CollectorPolicy() :
|
|||||||
double time_slice = (double) GCPauseIntervalMillis / 1000.0;
|
double time_slice = (double) GCPauseIntervalMillis / 1000.0;
|
||||||
_mmu_tracker = new G1MMUTrackerQueue(time_slice, max_gc_time);
|
_mmu_tracker = new G1MMUTrackerQueue(time_slice, max_gc_time);
|
||||||
|
|
||||||
uintx confidence_perc = G1ConfidencePercent;
|
|
||||||
// Put an artificial ceiling on this so that it's not set to a silly value.
|
|
||||||
if (confidence_perc > 100) {
|
|
||||||
confidence_perc = 100;
|
|
||||||
warning("G1ConfidencePercent is set to a value that is too large, "
|
|
||||||
"it's been updated to %u", confidence_perc);
|
|
||||||
}
|
|
||||||
_sigma = (double) confidence_perc / 100.0;
|
|
||||||
|
|
||||||
// start conservatively (around 50ms is about right)
|
// start conservatively (around 50ms is about right)
|
||||||
_concurrent_mark_remark_times_ms->add(0.05);
|
_concurrent_mark_remark_times_ms->add(0.05);
|
||||||
_concurrent_mark_cleanup_times_ms->add(0.20);
|
_concurrent_mark_cleanup_times_ms->add(0.20);
|
||||||
|
@ -46,9 +46,6 @@ class ReferenceProcessor;
|
|||||||
class G1PrepareCompactClosure;
|
class G1PrepareCompactClosure;
|
||||||
|
|
||||||
class G1MarkSweep : AllStatic {
|
class G1MarkSweep : AllStatic {
|
||||||
friend class VM_G1MarkSweep;
|
|
||||||
friend class Scavenge;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static void invoke_at_safepoint(ReferenceProcessor* rp,
|
static void invoke_at_safepoint(ReferenceProcessor* rp,
|
||||||
|
@ -45,7 +45,8 @@
|
|||||||
#include "utilities/bitMap.inline.hpp"
|
#include "utilities/bitMap.inline.hpp"
|
||||||
|
|
||||||
G1PageBasedVirtualSpace::G1PageBasedVirtualSpace() : _low_boundary(NULL),
|
G1PageBasedVirtualSpace::G1PageBasedVirtualSpace() : _low_boundary(NULL),
|
||||||
_high_boundary(NULL), _committed(), _page_size(0), _special(false), _executable(false) {
|
_high_boundary(NULL), _committed(), _page_size(0), _special(false),
|
||||||
|
_dirty(), _executable(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool G1PageBasedVirtualSpace::initialize_with_granularity(ReservedSpace rs, size_t page_size) {
|
bool G1PageBasedVirtualSpace::initialize_with_granularity(ReservedSpace rs, size_t page_size) {
|
||||||
@ -66,6 +67,9 @@ bool G1PageBasedVirtualSpace::initialize_with_granularity(ReservedSpace rs, size
|
|||||||
assert(_committed.size() == 0, "virtual space initialized more than once");
|
assert(_committed.size() == 0, "virtual space initialized more than once");
|
||||||
uintx size_in_bits = rs.size() / page_size;
|
uintx size_in_bits = rs.size() / page_size;
|
||||||
_committed.resize(size_in_bits, /* in_resource_area */ false);
|
_committed.resize(size_in_bits, /* in_resource_area */ false);
|
||||||
|
if (_special) {
|
||||||
|
_dirty.resize(size_in_bits, /* in_resource_area */ false);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -84,6 +88,7 @@ void G1PageBasedVirtualSpace::release() {
|
|||||||
_executable = false;
|
_executable = false;
|
||||||
_page_size = 0;
|
_page_size = 0;
|
||||||
_committed.resize(0, false);
|
_committed.resize(0, false);
|
||||||
|
_dirty.resize(0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t G1PageBasedVirtualSpace::committed_size() const {
|
size_t G1PageBasedVirtualSpace::committed_size() const {
|
||||||
@ -120,34 +125,43 @@ size_t G1PageBasedVirtualSpace::byte_size_for_pages(size_t num) {
|
|||||||
return num * _page_size;
|
return num * _page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemRegion G1PageBasedVirtualSpace::commit(uintptr_t start, size_t size_in_pages) {
|
bool G1PageBasedVirtualSpace::commit(uintptr_t start, size_t size_in_pages) {
|
||||||
// We need to make sure to commit all pages covered by the given area.
|
// We need to make sure to commit all pages covered by the given area.
|
||||||
guarantee(is_area_uncommitted(start, size_in_pages), "Specified area is not uncommitted");
|
guarantee(is_area_uncommitted(start, size_in_pages), "Specified area is not uncommitted");
|
||||||
|
|
||||||
if (!_special) {
|
bool zero_filled = true;
|
||||||
|
uintptr_t end = start + size_in_pages;
|
||||||
|
|
||||||
|
if (_special) {
|
||||||
|
// Check for dirty pages and update zero_filled if any found.
|
||||||
|
if (_dirty.get_next_one_offset(start,end) < end) {
|
||||||
|
zero_filled = false;
|
||||||
|
_dirty.clear_range(start, end);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
os::commit_memory_or_exit(page_start(start), byte_size_for_pages(size_in_pages), _executable,
|
os::commit_memory_or_exit(page_start(start), byte_size_for_pages(size_in_pages), _executable,
|
||||||
err_msg("Failed to commit pages from "SIZE_FORMAT" of length "SIZE_FORMAT, start, size_in_pages));
|
err_msg("Failed to commit pages from "SIZE_FORMAT" of length "SIZE_FORMAT, start, size_in_pages));
|
||||||
}
|
}
|
||||||
_committed.set_range(start, start + size_in_pages);
|
_committed.set_range(start, end);
|
||||||
|
|
||||||
MemRegion result((HeapWord*)page_start(start), byte_size_for_pages(size_in_pages) / HeapWordSize);
|
|
||||||
if (AlwaysPreTouch) {
|
if (AlwaysPreTouch) {
|
||||||
os::pretouch_memory((char*)result.start(), (char*)result.end());
|
os::pretouch_memory(page_start(start), page_start(end));
|
||||||
}
|
}
|
||||||
return result;
|
return zero_filled;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemRegion G1PageBasedVirtualSpace::uncommit(uintptr_t start, size_t size_in_pages) {
|
void G1PageBasedVirtualSpace::uncommit(uintptr_t start, size_t size_in_pages) {
|
||||||
guarantee(is_area_committed(start, size_in_pages), "checking");
|
guarantee(is_area_committed(start, size_in_pages), "checking");
|
||||||
|
|
||||||
if (!_special) {
|
if (_special) {
|
||||||
|
// Mark that memory is dirty. If committed again the memory might
|
||||||
|
// need to be cleared explicitly.
|
||||||
|
_dirty.set_range(start, start + size_in_pages);
|
||||||
|
} else {
|
||||||
os::uncommit_memory(page_start(start), byte_size_for_pages(size_in_pages));
|
os::uncommit_memory(page_start(start), byte_size_for_pages(size_in_pages));
|
||||||
}
|
}
|
||||||
|
|
||||||
_committed.clear_range(start, start + size_in_pages);
|
_committed.clear_range(start, start + size_in_pages);
|
||||||
|
|
||||||
MemRegion result((HeapWord*)page_start(start), byte_size_for_pages(size_in_pages) / HeapWordSize);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool G1PageBasedVirtualSpace::contains(const void* p) const {
|
bool G1PageBasedVirtualSpace::contains(const void* p) const {
|
||||||
@ -157,7 +171,7 @@ bool G1PageBasedVirtualSpace::contains(const void* p) const {
|
|||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void G1PageBasedVirtualSpace::print_on(outputStream* out) {
|
void G1PageBasedVirtualSpace::print_on(outputStream* out) {
|
||||||
out->print ("Virtual space:");
|
out->print ("Virtual space:");
|
||||||
if (special()) out->print(" (pinned in memory)");
|
if (_special) out->print(" (pinned in memory)");
|
||||||
out->cr();
|
out->cr();
|
||||||
out->print_cr(" - committed: " SIZE_FORMAT, committed_size());
|
out->print_cr(" - committed: " SIZE_FORMAT, committed_size());
|
||||||
out->print_cr(" - reserved: " SIZE_FORMAT, reserved_size());
|
out->print_cr(" - reserved: " SIZE_FORMAT, reserved_size());
|
||||||
|
@ -49,6 +49,12 @@ class G1PageBasedVirtualSpace VALUE_OBJ_CLASS_SPEC {
|
|||||||
// Bitmap used for verification of commit/uncommit operations.
|
// Bitmap used for verification of commit/uncommit operations.
|
||||||
BitMap _committed;
|
BitMap _committed;
|
||||||
|
|
||||||
|
// Bitmap used to keep track of which pages are dirty or not for _special
|
||||||
|
// spaces. This is needed because for those spaces the underlying memory
|
||||||
|
// will only be zero filled the first time it is committed. Calls to commit
|
||||||
|
// will use this bitmap and return whether or not the memory is zero filled.
|
||||||
|
BitMap _dirty;
|
||||||
|
|
||||||
// Indicates that the entire space has been committed and pinned in memory,
|
// Indicates that the entire space has been committed and pinned in memory,
|
||||||
// os::commit_memory() or os::uncommit_memory() have no function.
|
// os::commit_memory() or os::uncommit_memory() have no function.
|
||||||
bool _special;
|
bool _special;
|
||||||
@ -71,12 +77,11 @@ class G1PageBasedVirtualSpace VALUE_OBJ_CLASS_SPEC {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
// Commit the given area of pages starting at start being size_in_pages large.
|
// Commit the given area of pages starting at start being size_in_pages large.
|
||||||
MemRegion commit(uintptr_t start, size_t size_in_pages);
|
// Returns true if the given area is zero filled upon completion.
|
||||||
|
bool commit(uintptr_t start, size_t size_in_pages);
|
||||||
|
|
||||||
// Uncommit the given area of pages starting at start being size_in_pages large.
|
// Uncommit the given area of pages starting at start being size_in_pages large.
|
||||||
MemRegion uncommit(uintptr_t start, size_t size_in_pages);
|
void uncommit(uintptr_t start, size_t size_in_pages);
|
||||||
|
|
||||||
bool special() const { return _special; }
|
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
G1PageBasedVirtualSpace();
|
G1PageBasedVirtualSpace();
|
||||||
|
@ -67,9 +67,9 @@ class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void commit_regions(uintptr_t start_idx, size_t num_regions) {
|
virtual void commit_regions(uintptr_t start_idx, size_t num_regions) {
|
||||||
_storage.commit(start_idx * _pages_per_region, num_regions * _pages_per_region);
|
bool zero_filled = _storage.commit(start_idx * _pages_per_region, num_regions * _pages_per_region);
|
||||||
_commit_map.set_range(start_idx, start_idx + num_regions);
|
_commit_map.set_range(start_idx, start_idx + num_regions);
|
||||||
fire_on_commit(start_idx, num_regions, true);
|
fire_on_commit(start_idx, num_regions, zero_filled);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) {
|
virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) {
|
||||||
@ -117,8 +117,7 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper {
|
|||||||
uint old_refcount = _refcounts.get_by_index(idx);
|
uint old_refcount = _refcounts.get_by_index(idx);
|
||||||
bool zero_filled = false;
|
bool zero_filled = false;
|
||||||
if (old_refcount == 0) {
|
if (old_refcount == 0) {
|
||||||
_storage.commit(idx, 1);
|
zero_filled = _storage.commit(idx, 1);
|
||||||
zero_filled = true;
|
|
||||||
}
|
}
|
||||||
_refcounts.set_by_index(idx, old_refcount + 1);
|
_refcounts.set_by_index(idx, old_refcount + 1);
|
||||||
_commit_map.set_bit(i);
|
_commit_map.set_bit(i);
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
// collection set.
|
// collection set.
|
||||||
|
|
||||||
class G1CollectedHeap;
|
class G1CollectedHeap;
|
||||||
class CardTableModRefBarrierSet;
|
|
||||||
class ConcurrentG1Refine;
|
class ConcurrentG1Refine;
|
||||||
class G1ParPushHeapRSClosure;
|
class G1ParPushHeapRSClosure;
|
||||||
|
|
||||||
|
@ -31,11 +31,15 @@
|
|||||||
#include "runtime/thread.inline.hpp"
|
#include "runtime/thread.inline.hpp"
|
||||||
|
|
||||||
PtrQueue::PtrQueue(PtrQueueSet* qset, bool perm, bool active) :
|
PtrQueue::PtrQueue(PtrQueueSet* qset, bool perm, bool active) :
|
||||||
_qset(qset), _buf(NULL), _index(0), _active(active),
|
_qset(qset), _buf(NULL), _index(0), _sz(0), _active(active),
|
||||||
_perm(perm), _lock(NULL)
|
_perm(perm), _lock(NULL)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void PtrQueue::flush() {
|
PtrQueue::~PtrQueue() {
|
||||||
|
assert(_perm || (_buf == NULL), "queue must be flushed before delete");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PtrQueue::flush_impl() {
|
||||||
if (!_perm && _buf != NULL) {
|
if (!_perm && _buf != NULL) {
|
||||||
if (_index == _sz) {
|
if (_index == _sz) {
|
||||||
// No work to do.
|
// No work to do.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -65,15 +65,18 @@ protected:
|
|||||||
Mutex* _lock;
|
Mutex* _lock;
|
||||||
|
|
||||||
PtrQueueSet* qset() { return _qset; }
|
PtrQueueSet* qset() { return _qset; }
|
||||||
|
bool is_permanent() const { return _perm; }
|
||||||
|
|
||||||
|
// Process queue entries and release resources, if not permanent.
|
||||||
|
void flush_impl();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Initialize this queue to contain a null buffer, and be part of the
|
// Initialize this queue to contain a null buffer, and be part of the
|
||||||
// given PtrQueueSet.
|
// given PtrQueueSet.
|
||||||
PtrQueue(PtrQueueSet* qset, bool perm = false, bool active = false);
|
PtrQueue(PtrQueueSet* qset, bool perm = false, bool active = false);
|
||||||
// Release any contained resources.
|
|
||||||
virtual void flush();
|
// Requires queue flushed or permanent.
|
||||||
// Calls flush() when destroyed.
|
~PtrQueue();
|
||||||
~PtrQueue() { flush(); }
|
|
||||||
|
|
||||||
// Associate a lock with a ptr queue.
|
// Associate a lock with a ptr queue.
|
||||||
void set_lock(Mutex* lock) { _lock = lock; }
|
void set_lock(Mutex* lock) { _lock = lock; }
|
||||||
|
@ -39,7 +39,7 @@ void ObjPtrQueue::flush() {
|
|||||||
// first before we flush it, otherwise we might end up with an
|
// first before we flush it, otherwise we might end up with an
|
||||||
// enqueued buffer with refs into the CSet which breaks our invariants.
|
// enqueued buffer with refs into the CSet which breaks our invariants.
|
||||||
filter();
|
filter();
|
||||||
PtrQueue::flush();
|
flush_impl();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method removes entries from an SATB buffer that will not be
|
// This method removes entries from an SATB buffer that will not be
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -60,9 +60,8 @@ public:
|
|||||||
// field to true. This is done in JavaThread::initialize_queues().
|
// field to true. This is done in JavaThread::initialize_queues().
|
||||||
PtrQueue(qset, perm, false /* active */) { }
|
PtrQueue(qset, perm, false /* active */) { }
|
||||||
|
|
||||||
// Overrides PtrQueue::flush() so that it can filter the buffer
|
// Process queue entries and free resources.
|
||||||
// before it is flushed.
|
void flush();
|
||||||
virtual void flush();
|
|
||||||
|
|
||||||
// Overrides PtrQueue::should_enqueue_buffer(). See the method's
|
// Overrides PtrQueue::should_enqueue_buffer(). See the method's
|
||||||
// definition for more information.
|
// definition for more information.
|
||||||
|
@ -63,7 +63,8 @@ public:
|
|||||||
virtual ~ParGCAllocBuffer() {}
|
virtual ~ParGCAllocBuffer() {}
|
||||||
|
|
||||||
static const size_t min_size() {
|
static const size_t min_size() {
|
||||||
return ThreadLocalAllocBuffer::min_size();
|
// Make sure that we return something that is larger than AlignmentReserve
|
||||||
|
return align_object_size(MAX2(MinTLABSize / HeapWordSize, (uintx)oopDesc::header_size())) + AlignmentReserve;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const size_t max_size() {
|
static const size_t max_size() {
|
||||||
|
@ -320,7 +320,7 @@ int LinkResolver::vtable_index_of_interface_method(KlassHandle klass,
|
|||||||
// First check in default method array
|
// First check in default method array
|
||||||
if (!resolved_method->is_abstract() &&
|
if (!resolved_method->is_abstract() &&
|
||||||
(InstanceKlass::cast(klass())->default_methods() != NULL)) {
|
(InstanceKlass::cast(klass())->default_methods() != NULL)) {
|
||||||
int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), name, signature, false);
|
int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), name, signature, false, false);
|
||||||
if (index >= 0 ) {
|
if (index >= 0 ) {
|
||||||
vtable_index = InstanceKlass::cast(klass())->default_vtable_indices()->at(index);
|
vtable_index = InstanceKlass::cast(klass())->default_vtable_indices()->at(index);
|
||||||
}
|
}
|
||||||
|
@ -279,10 +279,12 @@ size_t CodeHeap::alignment_offset() const {
|
|||||||
return sizeof(HeapBlock) & (_segment_size - 1);
|
return sizeof(HeapBlock) & (_segment_size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finds the next free heapblock. If the current one is free, that it returned
|
// Returns the current block if available and used.
|
||||||
void* CodeHeap::next_free(HeapBlock* b) const {
|
// If not, it returns the subsequent block (if available), NULL otherwise.
|
||||||
// Since free blocks are merged, there is max. on free block
|
// Free blocks are merged, therefore there is at most one free block
|
||||||
// between two used ones
|
// between two used ones. As a result, the subsequent block (if available) is
|
||||||
|
// guaranteed to be used.
|
||||||
|
void* CodeHeap::next_used(HeapBlock* b) const {
|
||||||
if (b != NULL && b->free()) b = next_block(b);
|
if (b != NULL && b->free()) b = next_block(b);
|
||||||
assert(b == NULL || !b->free(), "must be in use or at end of heap");
|
assert(b == NULL || !b->free(), "must be in use or at end of heap");
|
||||||
return (b == NULL) ? NULL : b->allocated_space();
|
return (b == NULL) ? NULL : b->allocated_space();
|
||||||
|
@ -123,7 +123,7 @@ class CodeHeap : public CHeapObj<mtCode> {
|
|||||||
FreeBlock* search_freelist(size_t length);
|
FreeBlock* search_freelist(size_t length);
|
||||||
|
|
||||||
// Iteration helpers
|
// Iteration helpers
|
||||||
void* next_free(HeapBlock* b) const;
|
void* next_used(HeapBlock* b) const;
|
||||||
HeapBlock* first_block() const;
|
HeapBlock* first_block() const;
|
||||||
HeapBlock* next_block(HeapBlock* b) const;
|
HeapBlock* next_block(HeapBlock* b) const;
|
||||||
HeapBlock* block_start(void* p) const;
|
HeapBlock* block_start(void* p) const;
|
||||||
@ -158,9 +158,9 @@ class CodeHeap : public CHeapObj<mtCode> {
|
|||||||
int freelist_length() const { return _freelist_length; } // number of elements in the freelist
|
int freelist_length() const { return _freelist_length; } // number of elements in the freelist
|
||||||
|
|
||||||
// returns the first block or NULL
|
// returns the first block or NULL
|
||||||
void* first() const { return next_free(first_block()); }
|
void* first() const { return next_used(first_block()); }
|
||||||
// returns the next block given a block p or NULL
|
// returns the next block given a block p or NULL
|
||||||
void* next(void* p) const { return next_free(next_block(block_start(p))); }
|
void* next(void* p) const { return next_used(next_block(block_start(p))); }
|
||||||
|
|
||||||
// Statistics
|
// Statistics
|
||||||
size_t capacity() const;
|
size_t capacity() const;
|
||||||
|
@ -3170,7 +3170,9 @@ void Metaspace::global_initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// the min_misc_data_size and min_misc_code_size estimates are based on
|
// the min_misc_data_size and min_misc_code_size estimates are based on
|
||||||
// MetaspaceShared::generate_vtable_methods()
|
// MetaspaceShared::generate_vtable_methods().
|
||||||
|
// The minimum size only accounts for the vtable methods. Any size less than the
|
||||||
|
// minimum required size would cause vm crash when allocating the vtable methods.
|
||||||
uint min_misc_data_size = align_size_up(
|
uint min_misc_data_size = align_size_up(
|
||||||
MetaspaceShared::num_virtuals * MetaspaceShared::vtbl_list_size * sizeof(void*), max_alignment);
|
MetaspaceShared::num_virtuals * MetaspaceShared::vtbl_list_size * sizeof(void*), max_alignment);
|
||||||
|
|
||||||
@ -3336,6 +3338,10 @@ void Metaspace::initialize(Mutex* lock, MetaspaceType type) {
|
|||||||
Metachunk* new_chunk = get_initialization_chunk(NonClassType,
|
Metachunk* new_chunk = get_initialization_chunk(NonClassType,
|
||||||
word_size,
|
word_size,
|
||||||
vsm()->medium_chunk_bunch());
|
vsm()->medium_chunk_bunch());
|
||||||
|
// For dumping shared archive, report error if allocation has failed.
|
||||||
|
if (DumpSharedSpaces && new_chunk == NULL) {
|
||||||
|
report_insufficient_metaspace(MetaspaceAux::committed_bytes() + word_size * BytesPerWord);
|
||||||
|
}
|
||||||
assert(!DumpSharedSpaces || new_chunk != NULL, "should have enough space for both chunks");
|
assert(!DumpSharedSpaces || new_chunk != NULL, "should have enough space for both chunks");
|
||||||
if (new_chunk != NULL) {
|
if (new_chunk != NULL) {
|
||||||
// Add to this manager's list of chunks in use and current_chunk().
|
// Add to this manager's list of chunks in use and current_chunk().
|
||||||
@ -3349,6 +3355,11 @@ void Metaspace::initialize(Mutex* lock, MetaspaceType type) {
|
|||||||
class_vsm()->medium_chunk_bunch());
|
class_vsm()->medium_chunk_bunch());
|
||||||
if (class_chunk != NULL) {
|
if (class_chunk != NULL) {
|
||||||
class_vsm()->add_chunk(class_chunk, true);
|
class_vsm()->add_chunk(class_chunk, true);
|
||||||
|
} else {
|
||||||
|
// For dumping shared archive, report error if allocation has failed.
|
||||||
|
if (DumpSharedSpaces) {
|
||||||
|
report_insufficient_metaspace(MetaspaceAux::committed_bytes() + class_word_size * BytesPerWord);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3829,11 +3840,13 @@ class TestVirtualSpaceNodeTest {
|
|||||||
assert(cm.sum_free_chunks() == 2*MediumChunk, "sizes should add up");
|
assert(cm.sum_free_chunks() == 2*MediumChunk, "sizes should add up");
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // 4 pages of VSN is committed, some is used by chunks
|
const size_t page_chunks = 4 * (size_t)os::vm_page_size() / BytesPerWord;
|
||||||
|
// This doesn't work for systems with vm_page_size >= 16K.
|
||||||
|
if (page_chunks < MediumChunk) {
|
||||||
|
// 4 pages of VSN is committed, some is used by chunks
|
||||||
ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk);
|
ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk);
|
||||||
VirtualSpaceNode vsn(vsn_test_size_bytes);
|
VirtualSpaceNode vsn(vsn_test_size_bytes);
|
||||||
const size_t page_chunks = 4 * (size_t)os::vm_page_size() / BytesPerWord;
|
|
||||||
assert(page_chunks < MediumChunk, "Test expects medium chunks to be at least 4*page_size");
|
|
||||||
vsn.initialize();
|
vsn.initialize();
|
||||||
vsn.expand_by(page_chunks, page_chunks);
|
vsn.expand_by(page_chunks, page_chunks);
|
||||||
vsn.get_chunk_vs(SmallChunk);
|
vsn.get_chunk_vs(SmallChunk);
|
||||||
|
@ -118,6 +118,7 @@ ReferenceProcessor::ReferenceProcessor(MemRegion span,
|
|||||||
_discoveredWeakRefs = &_discoveredSoftRefs[_max_num_q];
|
_discoveredWeakRefs = &_discoveredSoftRefs[_max_num_q];
|
||||||
_discoveredFinalRefs = &_discoveredWeakRefs[_max_num_q];
|
_discoveredFinalRefs = &_discoveredWeakRefs[_max_num_q];
|
||||||
_discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_q];
|
_discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_q];
|
||||||
|
_discoveredCleanerRefs = &_discoveredPhantomRefs[_max_num_q];
|
||||||
|
|
||||||
// Initialize all entries to NULL
|
// Initialize all entries to NULL
|
||||||
for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
|
for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
|
||||||
@ -246,6 +247,13 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references(
|
|||||||
phantom_count =
|
phantom_count =
|
||||||
process_discovered_reflist(_discoveredPhantomRefs, NULL, false,
|
process_discovered_reflist(_discoveredPhantomRefs, NULL, false,
|
||||||
is_alive, keep_alive, complete_gc, task_executor);
|
is_alive, keep_alive, complete_gc, task_executor);
|
||||||
|
|
||||||
|
// Process cleaners, but include them in phantom statistics. We expect
|
||||||
|
// Cleaner references to be temporary, and don't want to deal with
|
||||||
|
// possible incompatibilities arising from making it more visible.
|
||||||
|
phantom_count +=
|
||||||
|
process_discovered_reflist(_discoveredCleanerRefs, NULL, false,
|
||||||
|
is_alive, keep_alive, complete_gc, task_executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weak global JNI references. It would make more sense (semantically) to
|
// Weak global JNI references. It would make more sense (semantically) to
|
||||||
@ -885,6 +893,7 @@ void ReferenceProcessor::balance_all_queues() {
|
|||||||
balance_queues(_discoveredWeakRefs);
|
balance_queues(_discoveredWeakRefs);
|
||||||
balance_queues(_discoveredFinalRefs);
|
balance_queues(_discoveredFinalRefs);
|
||||||
balance_queues(_discoveredPhantomRefs);
|
balance_queues(_discoveredPhantomRefs);
|
||||||
|
balance_queues(_discoveredCleanerRefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
@ -998,6 +1007,9 @@ inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt)
|
|||||||
case REF_PHANTOM:
|
case REF_PHANTOM:
|
||||||
list = &_discoveredPhantomRefs[id];
|
list = &_discoveredPhantomRefs[id];
|
||||||
break;
|
break;
|
||||||
|
case REF_CLEANER:
|
||||||
|
list = &_discoveredCleanerRefs[id];
|
||||||
|
break;
|
||||||
case REF_NONE:
|
case REF_NONE:
|
||||||
// we should not reach here if we are an InstanceRefKlass
|
// we should not reach here if we are an InstanceRefKlass
|
||||||
default:
|
default:
|
||||||
@ -1263,6 +1275,17 @@ void ReferenceProcessor::preclean_discovered_references(
|
|||||||
preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive,
|
preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive,
|
||||||
keep_alive, complete_gc, yield);
|
keep_alive, complete_gc, yield);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cleaner references. Included in timing for phantom references. We
|
||||||
|
// expect Cleaner references to be temporary, and don't want to deal with
|
||||||
|
// possible incompatibilities arising from making it more visible.
|
||||||
|
for (uint i = 0; i < _max_num_q; i++) {
|
||||||
|
if (yield->should_return()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
preclean_discovered_reflist(_discoveredCleanerRefs[i], is_alive,
|
||||||
|
keep_alive, complete_gc, yield);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1331,6 +1354,7 @@ const char* ReferenceProcessor::list_name(uint i) {
|
|||||||
case 1: return "WeakRef";
|
case 1: return "WeakRef";
|
||||||
case 2: return "FinalRef";
|
case 2: return "FinalRef";
|
||||||
case 3: return "PhantomRef";
|
case 3: return "PhantomRef";
|
||||||
|
case 4: return "CleanerRef";
|
||||||
}
|
}
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -264,9 +264,10 @@ class ReferenceProcessor : public CHeapObj<mtGC> {
|
|||||||
DiscoveredList* _discoveredWeakRefs;
|
DiscoveredList* _discoveredWeakRefs;
|
||||||
DiscoveredList* _discoveredFinalRefs;
|
DiscoveredList* _discoveredFinalRefs;
|
||||||
DiscoveredList* _discoveredPhantomRefs;
|
DiscoveredList* _discoveredPhantomRefs;
|
||||||
|
DiscoveredList* _discoveredCleanerRefs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static int number_of_subclasses_of_ref() { return (REF_PHANTOM - REF_OTHER); }
|
static int number_of_subclasses_of_ref() { return (REF_CLEANER - REF_OTHER); }
|
||||||
|
|
||||||
uint num_q() { return _num_q; }
|
uint num_q() { return _num_q; }
|
||||||
uint max_num_q() { return _max_num_q; }
|
uint max_num_q() { return _max_num_q; }
|
||||||
|
@ -35,7 +35,8 @@ enum ReferenceType {
|
|||||||
REF_SOFT, // Subclass of java/lang/ref/SoftReference
|
REF_SOFT, // Subclass of java/lang/ref/SoftReference
|
||||||
REF_WEAK, // Subclass of java/lang/ref/WeakReference
|
REF_WEAK, // Subclass of java/lang/ref/WeakReference
|
||||||
REF_FINAL, // Subclass of java/lang/ref/FinalReference
|
REF_FINAL, // Subclass of java/lang/ref/FinalReference
|
||||||
REF_PHANTOM // Subclass of java/lang/ref/PhantomReference
|
REF_PHANTOM, // Subclass of java/lang/ref/PhantomReference
|
||||||
|
REF_CLEANER // Subclass of sun/misc/Cleaner
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_MEMORY_REFRERENCETYPE_HPP
|
#endif // SHARE_VM_MEMORY_REFRERENCETYPE_HPP
|
||||||
|
@ -235,22 +235,19 @@ void ThreadLocalAllocBuffer::startup_initialization() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t ThreadLocalAllocBuffer::initial_desired_size() {
|
size_t ThreadLocalAllocBuffer::initial_desired_size() {
|
||||||
size_t init_sz;
|
size_t init_sz = 0;
|
||||||
|
|
||||||
if (TLABSize > 0) {
|
if (TLABSize > 0) {
|
||||||
init_sz = MIN2(TLABSize / HeapWordSize, max_size());
|
init_sz = TLABSize / HeapWordSize;
|
||||||
} else if (global_stats() == NULL) {
|
} else if (global_stats() != NULL) {
|
||||||
// Startup issue - main thread initialized before heap initialized.
|
|
||||||
init_sz = min_size();
|
|
||||||
} else {
|
|
||||||
// Initial size is a function of the average number of allocating threads.
|
// Initial size is a function of the average number of allocating threads.
|
||||||
unsigned nof_threads = global_stats()->allocating_threads_avg();
|
unsigned nof_threads = global_stats()->allocating_threads_avg();
|
||||||
|
|
||||||
init_sz = (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize) /
|
init_sz = (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize) /
|
||||||
(nof_threads * target_refills());
|
(nof_threads * target_refills());
|
||||||
init_sz = align_object_size(init_sz);
|
init_sz = align_object_size(init_sz);
|
||||||
init_sz = MIN2(MAX2(init_sz, min_size()), max_size());
|
|
||||||
}
|
}
|
||||||
|
init_sz = MIN2(MAX2(init_sz, min_size()), max_size());
|
||||||
return init_sz;
|
return init_sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ public:
|
|||||||
// do nothing. tlabs must be inited by initialize() calls
|
// do nothing. tlabs must be inited by initialize() calls
|
||||||
}
|
}
|
||||||
|
|
||||||
static const size_t min_size() { return align_object_size(MinTLABSize / HeapWordSize); }
|
static const size_t min_size() { return align_object_size(MinTLABSize / HeapWordSize) + alignment_reserve(); }
|
||||||
static const size_t max_size() { assert(_max_size != 0, "max_size not set up"); return _max_size; }
|
static const size_t max_size() { assert(_max_size != 0, "max_size not set up"); return _max_size; }
|
||||||
static void set_max_size(size_t max_size) { _max_size = max_size; }
|
static void set_max_size(size_t max_size) { _max_size = max_size; }
|
||||||
|
|
||||||
|
@ -1420,32 +1420,41 @@ Method* InstanceKlass::find_method(Symbol* name, Symbol* signature) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Method* InstanceKlass::find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const {
|
Method* InstanceKlass::find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const {
|
||||||
return InstanceKlass::find_method_impl(methods(), name, signature, skipping_overpass);
|
return InstanceKlass::find_method_impl(methods(), name, signature, skipping_overpass, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// find_instance_method looks up the name/signature in the local methods array
|
// find_instance_method looks up the name/signature in the local methods array
|
||||||
// and skips over static methods
|
// and skips over static methods
|
||||||
Method* InstanceKlass::find_instance_method(
|
Method* InstanceKlass::find_instance_method(
|
||||||
Array<Method*>* methods, Symbol* name, Symbol* signature) {
|
Array<Method*>* methods, Symbol* name, Symbol* signature) {
|
||||||
Method* meth = InstanceKlass::find_method(methods, name, signature);
|
Method* meth = InstanceKlass::find_method_impl(methods, name, signature, false, true);
|
||||||
if (meth != NULL && meth->is_static()) {
|
|
||||||
meth = NULL;
|
|
||||||
}
|
|
||||||
return meth;
|
return meth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find_instance_method looks up the name/signature in the local methods array
|
||||||
|
// and skips over static methods
|
||||||
|
Method* InstanceKlass::find_instance_method(Symbol* name, Symbol* signature) {
|
||||||
|
return InstanceKlass::find_instance_method(methods(), name, signature);
|
||||||
|
}
|
||||||
|
|
||||||
// find_method looks up the name/signature in the local methods array
|
// find_method looks up the name/signature in the local methods array
|
||||||
Method* InstanceKlass::find_method(
|
Method* InstanceKlass::find_method(
|
||||||
Array<Method*>* methods, Symbol* name, Symbol* signature) {
|
Array<Method*>* methods, Symbol* name, Symbol* signature) {
|
||||||
return InstanceKlass::find_method_impl(methods, name, signature, false);
|
return InstanceKlass::find_method_impl(methods, name, signature, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Method* InstanceKlass::find_method_impl(
|
Method* InstanceKlass::find_method_impl(
|
||||||
Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass) {
|
Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static) {
|
||||||
int hit = find_method_index(methods, name, signature, skipping_overpass);
|
int hit = find_method_index(methods, name, signature, skipping_overpass, skipping_static);
|
||||||
return hit >= 0 ? methods->at(hit): NULL;
|
return hit >= 0 ? methods->at(hit): NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InstanceKlass::method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static) {
|
||||||
|
return (m->signature() == signature) &&
|
||||||
|
(!skipping_overpass || !m->is_overpass()) &&
|
||||||
|
(!skipping_static || !m->is_static());
|
||||||
|
}
|
||||||
|
|
||||||
// Used directly for default_methods to find the index into the
|
// Used directly for default_methods to find the index into the
|
||||||
// default_vtable_indices, and indirectly by find_method
|
// default_vtable_indices, and indirectly by find_method
|
||||||
// find_method_index looks in the local methods array to return the index
|
// find_method_index looks in the local methods array to return the index
|
||||||
@ -1454,13 +1463,14 @@ Method* InstanceKlass::find_method_impl(
|
|||||||
// is important during method resolution to prefer a static method, for example,
|
// is important during method resolution to prefer a static method, for example,
|
||||||
// over an overpass method.
|
// over an overpass method.
|
||||||
int InstanceKlass::find_method_index(
|
int InstanceKlass::find_method_index(
|
||||||
Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass) {
|
Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static) {
|
||||||
int hit = binary_search(methods, name);
|
int hit = binary_search(methods, name);
|
||||||
if (hit != -1) {
|
if (hit != -1) {
|
||||||
Method* m = methods->at(hit);
|
Method* m = methods->at(hit);
|
||||||
|
|
||||||
// Do linear search to find matching signature. First, quick check
|
// Do linear search to find matching signature. First, quick check
|
||||||
// for common case, ignoring overpasses if requested.
|
// for common case, ignoring overpasses if requested.
|
||||||
if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return hit;
|
if (method_matches(m, signature, skipping_overpass, skipping_static)) return hit;
|
||||||
|
|
||||||
// search downwards through overloaded methods
|
// search downwards through overloaded methods
|
||||||
int i;
|
int i;
|
||||||
@ -1468,18 +1478,18 @@ int InstanceKlass::find_method_index(
|
|||||||
Method* m = methods->at(i);
|
Method* m = methods->at(i);
|
||||||
assert(m->is_method(), "must be method");
|
assert(m->is_method(), "must be method");
|
||||||
if (m->name() != name) break;
|
if (m->name() != name) break;
|
||||||
if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return i;
|
if (method_matches(m, signature, skipping_overpass, skipping_static)) return i;
|
||||||
}
|
}
|
||||||
// search upwards
|
// search upwards
|
||||||
for (i = hit + 1; i < methods->length(); ++i) {
|
for (i = hit + 1; i < methods->length(); ++i) {
|
||||||
Method* m = methods->at(i);
|
Method* m = methods->at(i);
|
||||||
assert(m->is_method(), "must be method");
|
assert(m->is_method(), "must be method");
|
||||||
if (m->name() != name) break;
|
if (m->name() != name) break;
|
||||||
if ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass())) return i;
|
if (method_matches(m, signature, skipping_overpass, skipping_static)) return i;
|
||||||
}
|
}
|
||||||
// not found
|
// not found
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
int index = skipping_overpass ? -1 : linear_search(methods, name, signature);
|
int index = skipping_overpass || skipping_static ? -1 : linear_search(methods, name, signature);
|
||||||
assert(index == -1, err_msg("binary search should have found entry %d", index));
|
assert(index == -1, err_msg("binary search should have found entry %d", index));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -490,10 +490,16 @@ class InstanceKlass: public Klass {
|
|||||||
// find a local method (returns NULL if not found)
|
// find a local method (returns NULL if not found)
|
||||||
Method* find_method(Symbol* name, Symbol* signature) const;
|
Method* find_method(Symbol* name, Symbol* signature) const;
|
||||||
static Method* find_method(Array<Method*>* methods, Symbol* name, Symbol* signature);
|
static Method* find_method(Array<Method*>* methods, Symbol* name, Symbol* signature);
|
||||||
|
|
||||||
|
// find a local method, but skip static methods
|
||||||
|
Method* find_instance_method(Symbol* name, Symbol* signature);
|
||||||
static Method* find_instance_method(Array<Method*>* methods, Symbol* name, Symbol* signature);
|
static Method* find_instance_method(Array<Method*>* methods, Symbol* name, Symbol* signature);
|
||||||
|
|
||||||
|
// true if method matches signature and conforms to skipping_X conditions.
|
||||||
|
static bool method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static);
|
||||||
|
|
||||||
// find a local method index in default_methods (returns -1 if not found)
|
// find a local method index in default_methods (returns -1 if not found)
|
||||||
static int find_method_index(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass);
|
static int find_method_index(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static);
|
||||||
|
|
||||||
// lookup operation (returns NULL if not found)
|
// lookup operation (returns NULL if not found)
|
||||||
Method* uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const;
|
Method* uncached_lookup_method(Symbol* name, Symbol* signature, MethodLookupMode mode) const;
|
||||||
@ -1053,7 +1059,7 @@ private:
|
|||||||
|
|
||||||
// find a local method (returns NULL if not found)
|
// find a local method (returns NULL if not found)
|
||||||
Method* find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const;
|
Method* find_method_impl(Symbol* name, Symbol* signature, bool skipping_overpass) const;
|
||||||
static Method* find_method_impl(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass);
|
static Method* find_method_impl(Array<Method*>* methods, Symbol* name, Symbol* signature, bool skipping_overpass, bool skipping_static);
|
||||||
|
|
||||||
// Free CHeap allocated fields.
|
// Free CHeap allocated fields.
|
||||||
void release_C_heap_structures();
|
void release_C_heap_structures();
|
||||||
|
@ -361,22 +361,36 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class IfTrueNode : public CProjNode {
|
class IfProjNode : public CProjNode {
|
||||||
public:
|
public:
|
||||||
IfTrueNode( IfNode *ifnode ) : CProjNode(ifnode,1) {
|
IfProjNode(IfNode *ifnode, uint idx) : CProjNode(ifnode,idx) {}
|
||||||
|
virtual Node *Identity(PhaseTransform *phase);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Type of If input when this branch is always taken
|
||||||
|
virtual bool always_taken(const TypeTuple* t) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IfTrueNode : public IfProjNode {
|
||||||
|
public:
|
||||||
|
IfTrueNode( IfNode *ifnode ) : IfProjNode(ifnode,1) {
|
||||||
init_class_id(Class_IfTrue);
|
init_class_id(Class_IfTrue);
|
||||||
}
|
}
|
||||||
virtual int Opcode() const;
|
virtual int Opcode() const;
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
|
protected:
|
||||||
|
virtual bool always_taken(const TypeTuple* t) const { return t == TypeTuple::IFTRUE; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class IfFalseNode : public CProjNode {
|
class IfFalseNode : public IfProjNode {
|
||||||
public:
|
public:
|
||||||
IfFalseNode( IfNode *ifnode ) : CProjNode(ifnode,0) {
|
IfFalseNode( IfNode *ifnode ) : IfProjNode(ifnode,0) {
|
||||||
init_class_id(Class_IfFalse);
|
init_class_id(Class_IfFalse);
|
||||||
}
|
}
|
||||||
virtual int Opcode() const;
|
virtual int Opcode() const;
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
|
protected:
|
||||||
|
virtual bool always_taken(const TypeTuple* t) const { return t == TypeTuple::IFFALSE; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1122,12 +1122,21 @@ void IfNode::dominated_by( Node *prev_dom, PhaseIterGVN *igvn ) {
|
|||||||
|
|
||||||
//------------------------------Identity---------------------------------------
|
//------------------------------Identity---------------------------------------
|
||||||
// If the test is constant & we match, then we are the input Control
|
// If the test is constant & we match, then we are the input Control
|
||||||
Node *IfTrueNode::Identity( PhaseTransform *phase ) {
|
Node *IfProjNode::Identity(PhaseTransform *phase) {
|
||||||
// Can only optimize if cannot go the other way
|
// Can only optimize if cannot go the other way
|
||||||
const TypeTuple *t = phase->type(in(0))->is_tuple();
|
const TypeTuple *t = phase->type(in(0))->is_tuple();
|
||||||
return ( t == TypeTuple::IFNEITHER || t == TypeTuple::IFTRUE )
|
if (t == TypeTuple::IFNEITHER ||
|
||||||
? in(0)->in(0) // IfNode control
|
// kill dead branch first otherwise the IfNode's control will
|
||||||
: this; // no progress
|
// have 2 control uses (the IfNode that doesn't go away because
|
||||||
|
// it still has uses and this branch of the
|
||||||
|
// If). Node::has_special_unique_user() will cause this node to
|
||||||
|
// be reprocessed once the dead branch is killed.
|
||||||
|
(always_taken(t) && in(0)->outcnt() == 1)) {
|
||||||
|
// IfNode control
|
||||||
|
return in(0)->in(0);
|
||||||
|
}
|
||||||
|
// no progress
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------dump_spec--------------------------------------
|
//------------------------------dump_spec--------------------------------------
|
||||||
@ -1195,13 +1204,3 @@ static IfNode* idealize_test(PhaseGVN* phase, IfNode* iff) {
|
|||||||
// Progress
|
// Progress
|
||||||
return iff;
|
return iff;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------Identity---------------------------------------
|
|
||||||
// If the test is constant & we match, then we are the input Control
|
|
||||||
Node *IfFalseNode::Identity( PhaseTransform *phase ) {
|
|
||||||
// Can only optimize if cannot go the other way
|
|
||||||
const TypeTuple *t = phase->type(in(0))->is_tuple();
|
|
||||||
return ( t == TypeTuple::IFNEITHER || t == TypeTuple::IFFALSE )
|
|
||||||
? in(0)->in(0) // IfNode control
|
|
||||||
: this; // no progress
|
|
||||||
}
|
|
||||||
|
@ -1080,18 +1080,21 @@ bool Node::has_special_unique_user() const {
|
|||||||
assert(outcnt() == 1, "match only for unique out");
|
assert(outcnt() == 1, "match only for unique out");
|
||||||
Node* n = unique_out();
|
Node* n = unique_out();
|
||||||
int op = Opcode();
|
int op = Opcode();
|
||||||
if( this->is_Store() ) {
|
if (this->is_Store()) {
|
||||||
// Condition for back-to-back stores folding.
|
// Condition for back-to-back stores folding.
|
||||||
return n->Opcode() == op && n->in(MemNode::Memory) == this;
|
return n->Opcode() == op && n->in(MemNode::Memory) == this;
|
||||||
} else if (this->is_Load()) {
|
} else if (this->is_Load()) {
|
||||||
// Condition for removing an unused LoadNode from the MemBarAcquire precedence input
|
// Condition for removing an unused LoadNode from the MemBarAcquire precedence input
|
||||||
return n->Opcode() == Op_MemBarAcquire;
|
return n->Opcode() == Op_MemBarAcquire;
|
||||||
} else if( op == Op_AddL ) {
|
} else if (op == Op_AddL) {
|
||||||
// Condition for convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y))
|
// Condition for convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y))
|
||||||
return n->Opcode() == Op_ConvL2I && n->in(1) == this;
|
return n->Opcode() == Op_ConvL2I && n->in(1) == this;
|
||||||
} else if( op == Op_SubI || op == Op_SubL ) {
|
} else if (op == Op_SubI || op == Op_SubL) {
|
||||||
// Condition for subI(x,subI(y,z)) ==> subI(addI(x,z),y)
|
// Condition for subI(x,subI(y,z)) ==> subI(addI(x,z),y)
|
||||||
return n->Opcode() == op && n->in(2) == this;
|
return n->Opcode() == op && n->in(2) == this;
|
||||||
|
} else if (is_If() && (n->is_IfFalse() || n->is_IfTrue())) {
|
||||||
|
// See IfProjNode::Identity()
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -2951,10 +2951,6 @@ class CommandLineFlags {
|
|||||||
develop(intx, MallocCatchPtr, -1, \
|
develop(intx, MallocCatchPtr, -1, \
|
||||||
"Hit breakpoint when mallocing/freeing this pointer") \
|
"Hit breakpoint when mallocing/freeing this pointer") \
|
||||||
\
|
\
|
||||||
notproduct(intx, AssertRepeat, 1, \
|
|
||||||
"number of times to evaluate expression in assert " \
|
|
||||||
"(to estimate overhead); only works with -DUSE_REPEATED_ASSERTS") \
|
|
||||||
\
|
|
||||||
notproduct(ccstrlist, SuppressErrorAt, "", \
|
notproduct(ccstrlist, SuppressErrorAt, "", \
|
||||||
"List of assertions (file:line) to muzzle") \
|
"List of assertions (file:line) to muzzle") \
|
||||||
\
|
\
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -547,20 +547,16 @@ static void verify_memory(void* ptr) {
|
|||||||
// This function supports testing of the malloc out of memory
|
// This function supports testing of the malloc out of memory
|
||||||
// condition without really running the system out of memory.
|
// condition without really running the system out of memory.
|
||||||
//
|
//
|
||||||
static u_char* testMalloc(size_t alloc_size) {
|
static bool has_reached_max_malloc_test_peak(size_t alloc_size) {
|
||||||
assert(MallocMaxTestWords > 0, "sanity check");
|
if (MallocMaxTestWords > 0) {
|
||||||
|
jint words = (jint)(alloc_size / BytesPerWord);
|
||||||
|
|
||||||
if ((cur_malloc_words + (alloc_size / BytesPerWord)) > MallocMaxTestWords) {
|
if ((cur_malloc_words + words) > MallocMaxTestWords) {
|
||||||
return NULL;
|
return true;
|
||||||
|
}
|
||||||
|
Atomic::add(words, (volatile jint *)&cur_malloc_words);
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
u_char* ptr = (u_char*)::malloc(alloc_size);
|
|
||||||
|
|
||||||
if (ptr != NULL) {
|
|
||||||
Atomic::add(((jint) (alloc_size / BytesPerWord)),
|
|
||||||
(volatile jint *) &cur_malloc_words);
|
|
||||||
}
|
|
||||||
return ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* os::malloc(size_t size, MEMFLAGS flags) {
|
void* os::malloc(size_t size, MEMFLAGS flags) {
|
||||||
@ -608,13 +604,14 @@ void* os::malloc(size_t size, MEMFLAGS memflags, const NativeCallStack& stack) {
|
|||||||
|
|
||||||
NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap());
|
NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap());
|
||||||
|
|
||||||
u_char* ptr;
|
// For the test flag -XX:MallocMaxTestWords
|
||||||
if (MallocMaxTestWords > 0) {
|
if (has_reached_max_malloc_test_peak(size)) {
|
||||||
ptr = testMalloc(alloc_size);
|
return NULL;
|
||||||
} else {
|
|
||||||
ptr = (u_char*)::malloc(alloc_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u_char* ptr;
|
||||||
|
ptr = (u_char*)::malloc(alloc_size);
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
if (ptr == NULL) {
|
if (ptr == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -642,6 +639,11 @@ void* os::realloc(void *memblock, size_t size, MEMFLAGS flags) {
|
|||||||
|
|
||||||
void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCallStack& stack) {
|
void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCallStack& stack) {
|
||||||
|
|
||||||
|
// For the test flag -XX:MallocMaxTestWords
|
||||||
|
if (has_reached_max_malloc_test_peak(size)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef ASSERT
|
#ifndef ASSERT
|
||||||
NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1));
|
NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1));
|
||||||
NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size));
|
NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size));
|
||||||
|
@ -661,6 +661,7 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
|
|||||||
static_field(SystemDictionary, WK_KLASS(WeakReference_klass), Klass*) \
|
static_field(SystemDictionary, WK_KLASS(WeakReference_klass), Klass*) \
|
||||||
static_field(SystemDictionary, WK_KLASS(FinalReference_klass), Klass*) \
|
static_field(SystemDictionary, WK_KLASS(FinalReference_klass), Klass*) \
|
||||||
static_field(SystemDictionary, WK_KLASS(PhantomReference_klass), Klass*) \
|
static_field(SystemDictionary, WK_KLASS(PhantomReference_klass), Klass*) \
|
||||||
|
static_field(SystemDictionary, WK_KLASS(Cleaner_klass), Klass*) \
|
||||||
static_field(SystemDictionary, WK_KLASS(Finalizer_klass), Klass*) \
|
static_field(SystemDictionary, WK_KLASS(Finalizer_klass), Klass*) \
|
||||||
static_field(SystemDictionary, WK_KLASS(Thread_klass), Klass*) \
|
static_field(SystemDictionary, WK_KLASS(Thread_klass), Klass*) \
|
||||||
static_field(SystemDictionary, WK_KLASS(ThreadGroup_klass), Klass*) \
|
static_field(SystemDictionary, WK_KLASS(ThreadGroup_klass), Klass*) \
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright 2008, 2009, 2010 Red Hat, Inc.
|
* Copyright 2008, 2009, 2010 Red Hat, Inc.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
@ -87,30 +87,7 @@
|
|||||||
#undef assert
|
#undef assert
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// from hotspot/src/share/vm/utilities/debug.hpp
|
#define assert(p, msg) vmassert(p, msg)
|
||||||
#ifdef ASSERT
|
|
||||||
#ifndef USE_REPEATED_ASSERTS
|
|
||||||
#define assert(p, msg) \
|
|
||||||
do { \
|
|
||||||
if (!(p)) { \
|
|
||||||
report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", msg); \
|
|
||||||
BREAKPOINT; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
#else // #ifndef USE_REPEATED_ASSERTS
|
|
||||||
#define assert(p, msg)
|
|
||||||
do { \
|
|
||||||
for (int __i = 0; __i < AssertRepeat; __i++) { \
|
|
||||||
if (!(p)) { \
|
|
||||||
report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", msg); \
|
|
||||||
BREAKPOINT; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
#endif // #ifndef USE_REPEATED_ASSERTS
|
|
||||||
#else
|
|
||||||
#define assert(p, msg)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#undef DEBUG
|
#undef DEBUG
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -273,6 +273,14 @@ void report_out_of_shared_space(SharedSpaceType shared_space) {
|
|||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void report_insufficient_metaspace(size_t required_size) {
|
||||||
|
warning("\nThe MaxMetaspaceSize of " UINTX_FORMAT " bytes is not large enough.\n"
|
||||||
|
"Either don't specify the -XX:MaxMetaspaceSize=<size>\n"
|
||||||
|
"or increase the size to at least " SIZE_FORMAT ".\n",
|
||||||
|
MaxMetaspaceSize, required_size);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
void report_java_out_of_memory(const char* message) {
|
void report_java_out_of_memory(const char* message) {
|
||||||
static jint out_of_memory_reported = 0;
|
static jint out_of_memory_reported = 0;
|
||||||
|
|
||||||
@ -326,9 +334,9 @@ void test_error_handler() {
|
|||||||
|
|
||||||
// Keep this in sync with test/runtime/6888954/vmerrors.sh.
|
// Keep this in sync with test/runtime/6888954/vmerrors.sh.
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 1: assert(str == NULL, "expected null");
|
case 1: vmassert(str == NULL, "expected null");
|
||||||
case 2: assert(num == 1023 && *str == 'X',
|
case 2: vmassert(num == 1023 && *str == 'X',
|
||||||
err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
|
err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
|
||||||
case 3: guarantee(str == NULL, "expected null");
|
case 3: guarantee(str == NULL, "expected null");
|
||||||
case 4: guarantee(num == 1023 && *str == 'X',
|
case 4: guarantee(num == 1023 && *str == 'X',
|
||||||
err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
|
err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str));
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -105,58 +105,42 @@ void FormatBuffer<bufsz>::append(const char* format, ...) {
|
|||||||
va_end(argp);
|
va_end(argp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to format messages for assert(), guarantee(), fatal(), etc.
|
// Used to format messages for vmassert(), guarantee(), fatal(), etc.
|
||||||
typedef FormatBuffer<> err_msg;
|
typedef FormatBuffer<> err_msg;
|
||||||
typedef FormatBufferResource err_msg_res;
|
typedef FormatBufferResource err_msg_res;
|
||||||
|
|
||||||
// assertions
|
// assertions
|
||||||
#ifdef ASSERT
|
#ifndef ASSERT
|
||||||
#ifndef USE_REPEATED_ASSERTS
|
#define vmassert(p, msg)
|
||||||
#define assert(p, msg) \
|
#else
|
||||||
|
// Note: message says "assert" rather than "vmassert" for backward
|
||||||
|
// compatibility with tools that parse/match the message text.
|
||||||
|
#define vmassert(p, msg) \
|
||||||
do { \
|
do { \
|
||||||
if (!(p)) { \
|
if (!(p)) { \
|
||||||
report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", msg); \
|
report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", msg); \
|
||||||
BREAKPOINT; \
|
BREAKPOINT; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else // #ifndef USE_REPEATED_ASSERTS
|
#endif
|
||||||
#define assert(p, msg)
|
|
||||||
do { \
|
|
||||||
for (int __i = 0; __i < AssertRepeat; __i++) { \
|
|
||||||
if (!(p)) { \
|
|
||||||
report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", msg); \
|
|
||||||
BREAKPOINT; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
#endif // #ifndef USE_REPEATED_ASSERTS
|
|
||||||
|
|
||||||
// This version of assert is for use with checking return status from
|
// For backward compatibility.
|
||||||
|
#define assert(p, msg) vmassert(p, msg)
|
||||||
|
|
||||||
|
// This version of vmassert is for use with checking return status from
|
||||||
// library calls that return actual error values eg. EINVAL,
|
// library calls that return actual error values eg. EINVAL,
|
||||||
// ENOMEM etc, rather than returning -1 and setting errno.
|
// ENOMEM etc, rather than returning -1 and setting errno.
|
||||||
// When the status is not what is expected it is very useful to know
|
// When the status is not what is expected it is very useful to know
|
||||||
// what status was actually returned, so we pass the status variable as
|
// what status was actually returned, so we pass the status variable as
|
||||||
// an extra arg and use strerror to convert it to a meaningful string
|
// an extra arg and use strerror to convert it to a meaningful string
|
||||||
// like "Invalid argument", "out of memory" etc
|
// like "Invalid argument", "out of memory" etc
|
||||||
#define assert_status(p, status, msg) \
|
#define vmassert_status(p, status, msg) \
|
||||||
do { \
|
vmassert(p, err_msg("error %s(%d), %s", strerror(status), status, msg))
|
||||||
if (!(p)) { \
|
|
||||||
report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", \
|
|
||||||
err_msg("error %s(%d) %s", strerror(status), \
|
|
||||||
status, msg)); \
|
|
||||||
BREAKPOINT; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
// Do not assert this condition if there's already another error reported.
|
// For backward compatibility.
|
||||||
#define assert_if_no_error(cond,msg) assert((cond) || is_error_reported(), msg)
|
#define assert_status(p, status, msg) vmassert_status(p, status, msg)
|
||||||
#else // #ifdef ASSERT
|
|
||||||
#define assert(p,msg)
|
|
||||||
#define assert_status(p,status,msg)
|
|
||||||
#define assert_if_no_error(cond,msg)
|
|
||||||
#endif // #ifdef ASSERT
|
|
||||||
|
|
||||||
// guarantee is like assert except it's always executed -- use it for
|
// guarantee is like vmassert except it's always executed -- use it for
|
||||||
// cheap tests that catch errors that would otherwise be hard to find.
|
// cheap tests that catch errors that would otherwise be hard to find.
|
||||||
// guarantee is also used for Verify options.
|
// guarantee is also used for Verify options.
|
||||||
#define guarantee(p, msg) \
|
#define guarantee(p, msg) \
|
||||||
@ -225,21 +209,22 @@ void report_untested(const char* file, int line, const char* message);
|
|||||||
|
|
||||||
void warning(const char* format, ...) ATTRIBUTE_PRINTF(1, 2);
|
void warning(const char* format, ...) ATTRIBUTE_PRINTF(1, 2);
|
||||||
|
|
||||||
#ifdef ASSERT
|
// Compile-time asserts. Cond must be a compile-time constant expression that
|
||||||
// Compile-time asserts.
|
// is convertible to bool. STATIC_ASSERT() can be used anywhere a declaration
|
||||||
template <bool> struct StaticAssert;
|
// may appear.
|
||||||
template <> struct StaticAssert<true> {};
|
//
|
||||||
|
// Implementation Note: STATIC_ASSERT_FAILURE<true> provides a value member
|
||||||
|
// rather than type member that could be used directly in the typedef, because
|
||||||
|
// a type member would require conditional use of "typename", depending on
|
||||||
|
// whether Cond is dependent or not. The use of a value member leads to the
|
||||||
|
// use of an array type.
|
||||||
|
|
||||||
// Only StaticAssert<true> is defined, so if cond evaluates to false we get
|
template<bool x> struct STATIC_ASSERT_FAILURE;
|
||||||
// a compile time exception when trying to use StaticAssert<false>.
|
template<> struct STATIC_ASSERT_FAILURE<true> { enum { value = 1 }; };
|
||||||
#define STATIC_ASSERT(cond) \
|
|
||||||
do { \
|
#define STATIC_ASSERT(Cond) \
|
||||||
StaticAssert<(cond)> DUMMY_STATIC_ASSERT; \
|
typedef char STATIC_ASSERT_FAILURE_ ## __LINE__ [ \
|
||||||
(void)DUMMY_STATIC_ASSERT; /* ignore */ \
|
STATIC_ASSERT_FAILURE< (Cond) >::value ]
|
||||||
} while (false)
|
|
||||||
#else
|
|
||||||
#define STATIC_ASSERT(cond)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// out of shared space reporting
|
// out of shared space reporting
|
||||||
enum SharedSpaceType {
|
enum SharedSpaceType {
|
||||||
@ -251,6 +236,8 @@ enum SharedSpaceType {
|
|||||||
|
|
||||||
void report_out_of_shared_space(SharedSpaceType space_type);
|
void report_out_of_shared_space(SharedSpaceType space_type);
|
||||||
|
|
||||||
|
void report_insufficient_metaspace(size_t required_size);
|
||||||
|
|
||||||
// out of memory reporting
|
// out of memory reporting
|
||||||
void report_java_out_of_memory(const char* message);
|
void report_java_out_of_memory(const char* message);
|
||||||
|
|
||||||
@ -258,7 +245,7 @@ void report_java_out_of_memory(const char* message);
|
|||||||
bool is_error_reported();
|
bool is_error_reported();
|
||||||
void set_error_reported();
|
void set_error_reported();
|
||||||
|
|
||||||
/* Test assert(), fatal(), guarantee(), etc. */
|
/* Test vmassert(), fatal(), guarantee(), etc. */
|
||||||
NOT_PRODUCT(void test_error_handler();)
|
NOT_PRODUCT(void test_error_handler();)
|
||||||
|
|
||||||
void pd_ps(frame f);
|
void pd_ps(frame f);
|
||||||
|
@ -41,6 +41,8 @@ class defaultStream : public xmlTextStream {
|
|||||||
|
|
||||||
void init();
|
void init();
|
||||||
void init_log();
|
void init_log();
|
||||||
|
fileStream* open_file(const char* log_name);
|
||||||
|
void start_log();
|
||||||
void finish_log();
|
void finish_log();
|
||||||
void finish_log_on_error(char *buf, int buflen);
|
void finish_log_on_error(char *buf, int buflen);
|
||||||
public:
|
public:
|
||||||
|
@ -367,7 +367,6 @@ extern Mutex* tty_lock;
|
|||||||
|
|
||||||
#define EXTRACHARLEN 32
|
#define EXTRACHARLEN 32
|
||||||
#define CURRENTAPPX ".current"
|
#define CURRENTAPPX ".current"
|
||||||
#define FILENAMEBUFLEN 1024
|
|
||||||
// convert YYYY-MM-DD HH:MM:SS to YYYY-MM-DD_HH-MM-SS
|
// convert YYYY-MM-DD HH:MM:SS to YYYY-MM-DD_HH-MM-SS
|
||||||
char* get_datetime_string(char *buf, size_t len) {
|
char* get_datetime_string(char *buf, size_t len) {
|
||||||
os::local_time_string(buf, len);
|
os::local_time_string(buf, len);
|
||||||
@ -401,7 +400,6 @@ static const char* make_log_name_internal(const char* log_name, const char* forc
|
|||||||
buffer_length = strlen(log_name) + 1;
|
buffer_length = strlen(log_name) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const char* star = strchr(basename, '*');
|
|
||||||
const char* pts = strstr(basename, "%p");
|
const char* pts = strstr(basename, "%p");
|
||||||
int pid_pos = (pts == NULL) ? -1 : (pts - nametail);
|
int pid_pos = (pts == NULL) ? -1 : (pts - nametail);
|
||||||
|
|
||||||
@ -416,6 +414,11 @@ static const char* make_log_name_internal(const char* log_name, const char* forc
|
|||||||
buffer_length += strlen(tms);
|
buffer_length += strlen(tms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// File name is too long.
|
||||||
|
if (buffer_length > JVM_MAXPATHLEN) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Create big enough buffer.
|
// Create big enough buffer.
|
||||||
char *buf = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal);
|
char *buf = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal);
|
||||||
|
|
||||||
@ -489,46 +492,88 @@ static const char* make_log_name(const char* log_name, const char* force_directo
|
|||||||
void test_loggc_filename() {
|
void test_loggc_filename() {
|
||||||
int pid;
|
int pid;
|
||||||
char tms[32];
|
char tms[32];
|
||||||
char i_result[FILENAMEBUFLEN];
|
char i_result[JVM_MAXPATHLEN];
|
||||||
const char* o_result;
|
const char* o_result;
|
||||||
get_datetime_string(tms, sizeof(tms));
|
get_datetime_string(tms, sizeof(tms));
|
||||||
pid = os::current_process_id();
|
pid = os::current_process_id();
|
||||||
|
|
||||||
// test.log
|
// test.log
|
||||||
jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test.log", tms);
|
jio_snprintf(i_result, JVM_MAXPATHLEN, "test.log", tms);
|
||||||
o_result = make_log_name_internal("test.log", NULL, pid, tms);
|
o_result = make_log_name_internal("test.log", NULL, pid, tms);
|
||||||
assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test.log\", NULL)");
|
assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test.log\", NULL)");
|
||||||
FREE_C_HEAP_ARRAY(char, o_result);
|
FREE_C_HEAP_ARRAY(char, o_result);
|
||||||
|
|
||||||
// test-%t-%p.log
|
// test-%t-%p.log
|
||||||
jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%s-pid%u.log", tms, pid);
|
jio_snprintf(i_result, JVM_MAXPATHLEN, "test-%s-pid%u.log", tms, pid);
|
||||||
o_result = make_log_name_internal("test-%t-%p.log", NULL, pid, tms);
|
o_result = make_log_name_internal("test-%t-%p.log", NULL, pid, tms);
|
||||||
assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t-%%p.log\", NULL)");
|
assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t-%%p.log\", NULL)");
|
||||||
FREE_C_HEAP_ARRAY(char, o_result);
|
FREE_C_HEAP_ARRAY(char, o_result);
|
||||||
|
|
||||||
// test-%t%p.log
|
// test-%t%p.log
|
||||||
jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%spid%u.log", tms, pid);
|
jio_snprintf(i_result, JVM_MAXPATHLEN, "test-%spid%u.log", tms, pid);
|
||||||
o_result = make_log_name_internal("test-%t%p.log", NULL, pid, tms);
|
o_result = make_log_name_internal("test-%t%p.log", NULL, pid, tms);
|
||||||
assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t%%p.log\", NULL)");
|
assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t%%p.log\", NULL)");
|
||||||
FREE_C_HEAP_ARRAY(char, o_result);
|
FREE_C_HEAP_ARRAY(char, o_result);
|
||||||
|
|
||||||
// %p%t.log
|
// %p%t.log
|
||||||
jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u%s.log", pid, tms);
|
jio_snprintf(i_result, JVM_MAXPATHLEN, "pid%u%s.log", pid, tms);
|
||||||
o_result = make_log_name_internal("%p%t.log", NULL, pid, tms);
|
o_result = make_log_name_internal("%p%t.log", NULL, pid, tms);
|
||||||
assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p%%t.log\", NULL)");
|
assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p%%t.log\", NULL)");
|
||||||
FREE_C_HEAP_ARRAY(char, o_result);
|
FREE_C_HEAP_ARRAY(char, o_result);
|
||||||
|
|
||||||
// %p-test.log
|
// %p-test.log
|
||||||
jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u-test.log", pid);
|
jio_snprintf(i_result, JVM_MAXPATHLEN, "pid%u-test.log", pid);
|
||||||
o_result = make_log_name_internal("%p-test.log", NULL, pid, tms);
|
o_result = make_log_name_internal("%p-test.log", NULL, pid, tms);
|
||||||
assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p-test.log\", NULL)");
|
assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p-test.log\", NULL)");
|
||||||
FREE_C_HEAP_ARRAY(char, o_result);
|
FREE_C_HEAP_ARRAY(char, o_result);
|
||||||
|
|
||||||
// %t.log
|
// %t.log
|
||||||
jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "%s.log", tms);
|
jio_snprintf(i_result, JVM_MAXPATHLEN, "%s.log", tms);
|
||||||
o_result = make_log_name_internal("%t.log", NULL, pid, tms);
|
o_result = make_log_name_internal("%t.log", NULL, pid, tms);
|
||||||
assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%t.log\", NULL)");
|
assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%t.log\", NULL)");
|
||||||
FREE_C_HEAP_ARRAY(char, o_result);
|
FREE_C_HEAP_ARRAY(char, o_result);
|
||||||
|
|
||||||
|
{
|
||||||
|
// longest filename
|
||||||
|
char longest_name[JVM_MAXPATHLEN];
|
||||||
|
memset(longest_name, 'a', sizeof(longest_name));
|
||||||
|
longest_name[JVM_MAXPATHLEN - 1] = '\0';
|
||||||
|
o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms);
|
||||||
|
assert(strcmp(longest_name, o_result) == 0, err_msg("longest name does not match. expected '%s' but got '%s'", longest_name, o_result));
|
||||||
|
FREE_C_HEAP_ARRAY(char, o_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// too long file name
|
||||||
|
char too_long_name[JVM_MAXPATHLEN + 100];
|
||||||
|
int too_long_length = sizeof(too_long_name);
|
||||||
|
memset(too_long_name, 'a', too_long_length);
|
||||||
|
too_long_name[too_long_length - 1] = '\0';
|
||||||
|
o_result = make_log_name_internal((const char*)&too_long_name, NULL, pid, tms);
|
||||||
|
assert(o_result == NULL, err_msg("Too long file name should return NULL, but got '%s'", o_result));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// too long with timestamp
|
||||||
|
char longest_name[JVM_MAXPATHLEN];
|
||||||
|
memset(longest_name, 'a', JVM_MAXPATHLEN);
|
||||||
|
longest_name[JVM_MAXPATHLEN - 3] = '%';
|
||||||
|
longest_name[JVM_MAXPATHLEN - 2] = 't';
|
||||||
|
longest_name[JVM_MAXPATHLEN - 1] = '\0';
|
||||||
|
o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms);
|
||||||
|
assert(o_result == NULL, err_msg("Too long file name after timestamp expansion should return NULL, but got '%s'", o_result));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// too long with pid
|
||||||
|
char longest_name[JVM_MAXPATHLEN];
|
||||||
|
memset(longest_name, 'a', JVM_MAXPATHLEN);
|
||||||
|
longest_name[JVM_MAXPATHLEN - 3] = '%';
|
||||||
|
longest_name[JVM_MAXPATHLEN - 2] = 'p';
|
||||||
|
longest_name[JVM_MAXPATHLEN - 1] = '\0';
|
||||||
|
o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms);
|
||||||
|
assert(o_result == NULL, err_msg("Too long file name after pid expansion should return NULL, but got '%s'", o_result));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif // PRODUCT
|
#endif // PRODUCT
|
||||||
|
|
||||||
@ -637,9 +682,16 @@ gcLogFileStream::gcLogFileStream(const char* file_name) {
|
|||||||
_bytes_written = 0L;
|
_bytes_written = 0L;
|
||||||
_file_name = make_log_name(file_name, NULL);
|
_file_name = make_log_name(file_name, NULL);
|
||||||
|
|
||||||
|
if (_file_name == NULL) {
|
||||||
|
warning("Cannot open file %s: file name is too long.\n", file_name);
|
||||||
|
_need_close = false;
|
||||||
|
UseGCLogFileRotation = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// gc log file rotation
|
// gc log file rotation
|
||||||
if (UseGCLogFileRotation && NumberOfGCLogFiles > 1) {
|
if (UseGCLogFileRotation && NumberOfGCLogFiles > 1) {
|
||||||
char tempbuf[FILENAMEBUFLEN];
|
char tempbuf[JVM_MAXPATHLEN];
|
||||||
jio_snprintf(tempbuf, sizeof(tempbuf), "%s.%d" CURRENTAPPX, _file_name, _cur_file_num);
|
jio_snprintf(tempbuf, sizeof(tempbuf), "%s.%d" CURRENTAPPX, _file_name, _cur_file_num);
|
||||||
_file = fopen(tempbuf, "w");
|
_file = fopen(tempbuf, "w");
|
||||||
} else {
|
} else {
|
||||||
@ -671,10 +723,10 @@ void gcLogFileStream::write(const char* s, size_t len) {
|
|||||||
// concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log
|
// concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log
|
||||||
// must be synchronized.
|
// must be synchronized.
|
||||||
void gcLogFileStream::rotate_log(bool force, outputStream* out) {
|
void gcLogFileStream::rotate_log(bool force, outputStream* out) {
|
||||||
char time_msg[FILENAMEBUFLEN];
|
char time_msg[O_BUFLEN];
|
||||||
char time_str[EXTRACHARLEN];
|
char time_str[EXTRACHARLEN];
|
||||||
char current_file_name[FILENAMEBUFLEN];
|
char current_file_name[JVM_MAXPATHLEN];
|
||||||
char renamed_file_name[FILENAMEBUFLEN];
|
char renamed_file_name[JVM_MAXPATHLEN];
|
||||||
|
|
||||||
if (!should_rotate(force)) {
|
if (!should_rotate(force)) {
|
||||||
return;
|
return;
|
||||||
@ -713,12 +765,15 @@ void gcLogFileStream::rotate_log(bool force, outputStream* out) {
|
|||||||
// have a form of extended_filename.<i>.current where i is the current rotation
|
// have a form of extended_filename.<i>.current where i is the current rotation
|
||||||
// file number. After it reaches max file size, the file will be saved and renamed
|
// file number. After it reaches max file size, the file will be saved and renamed
|
||||||
// with .current removed from its tail.
|
// with .current removed from its tail.
|
||||||
size_t filename_len = strlen(_file_name);
|
|
||||||
if (_file != NULL) {
|
if (_file != NULL) {
|
||||||
jio_snprintf(renamed_file_name, filename_len + EXTRACHARLEN, "%s.%d",
|
jio_snprintf(renamed_file_name, JVM_MAXPATHLEN, "%s.%d",
|
||||||
_file_name, _cur_file_num);
|
|
||||||
jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
|
|
||||||
_file_name, _cur_file_num);
|
_file_name, _cur_file_num);
|
||||||
|
int result = jio_snprintf(current_file_name, JVM_MAXPATHLEN,
|
||||||
|
"%s.%d" CURRENTAPPX, _file_name, _cur_file_num);
|
||||||
|
if (result >= JVM_MAXPATHLEN) {
|
||||||
|
warning("Cannot create new log file name: %s: file name is too long.\n", current_file_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const char* msg = force ? "GC log rotation request has been received."
|
const char* msg = force ? "GC log rotation request has been received."
|
||||||
: "GC log file has reached the maximum size.";
|
: "GC log file has reached the maximum size.";
|
||||||
@ -757,19 +812,23 @@ void gcLogFileStream::rotate_log(bool force, outputStream* out) {
|
|||||||
|
|
||||||
_cur_file_num++;
|
_cur_file_num++;
|
||||||
if (_cur_file_num > NumberOfGCLogFiles - 1) _cur_file_num = 0;
|
if (_cur_file_num > NumberOfGCLogFiles - 1) _cur_file_num = 0;
|
||||||
jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
|
int result = jio_snprintf(current_file_name, JVM_MAXPATHLEN, "%s.%d" CURRENTAPPX,
|
||||||
_file_name, _cur_file_num);
|
_file_name, _cur_file_num);
|
||||||
|
if (result >= JVM_MAXPATHLEN) {
|
||||||
|
warning("Cannot create new log file name: %s: file name is too long.\n", current_file_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_file = fopen(current_file_name, "w");
|
_file = fopen(current_file_name, "w");
|
||||||
|
|
||||||
if (_file != NULL) {
|
if (_file != NULL) {
|
||||||
_bytes_written = 0L;
|
_bytes_written = 0L;
|
||||||
_need_close = true;
|
_need_close = true;
|
||||||
// reuse current_file_name for time_msg
|
// reuse current_file_name for time_msg
|
||||||
jio_snprintf(current_file_name, filename_len + EXTRACHARLEN,
|
jio_snprintf(current_file_name, JVM_MAXPATHLEN,
|
||||||
"%s.%d", _file_name, _cur_file_num);
|
"%s.%d", _file_name, _cur_file_num);
|
||||||
jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file created %s\n",
|
jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file created %s\n",
|
||||||
os::local_time_string((char *)time_str, sizeof(time_str)),
|
os::local_time_string((char *)time_str, sizeof(time_str)), current_file_name);
|
||||||
current_file_name);
|
|
||||||
write(time_msg, strlen(time_msg));
|
write(time_msg, strlen(time_msg));
|
||||||
|
|
||||||
if (out != NULL) {
|
if (out != NULL) {
|
||||||
@ -817,32 +876,64 @@ bool defaultStream::has_log_file() {
|
|||||||
return _log_file != NULL;
|
return _log_file != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileStream* defaultStream::open_file(const char* log_name) {
|
||||||
|
const char* try_name = make_log_name(log_name, NULL);
|
||||||
|
if (try_name == NULL) {
|
||||||
|
warning("Cannot open file %s: file name is too long.\n", log_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name);
|
||||||
|
FREE_C_HEAP_ARRAY(char, try_name);
|
||||||
|
if (file->is_open()) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try again to open the file in the temp directory.
|
||||||
|
delete file;
|
||||||
|
char warnbuf[O_BUFLEN*2];
|
||||||
|
jio_snprintf(warnbuf, sizeof(warnbuf), "Warning: Cannot open log file: %s\n", log_name);
|
||||||
|
// Note: This feature is for maintainer use only. No need for L10N.
|
||||||
|
jio_print(warnbuf);
|
||||||
|
try_name = make_log_name(log_name, os::get_temp_directory());
|
||||||
|
if (try_name == NULL) {
|
||||||
|
warning("Cannot open file %s: file name is too long for directory %s.\n", log_name, os::get_temp_directory());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jio_snprintf(warnbuf, sizeof(warnbuf),
|
||||||
|
"Warning: Forcing option -XX:LogFile=%s\n", try_name);
|
||||||
|
jio_print(warnbuf);
|
||||||
|
|
||||||
|
file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name);
|
||||||
|
FREE_C_HEAP_ARRAY(char, try_name);
|
||||||
|
if (file->is_open()) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete file;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void defaultStream::init_log() {
|
void defaultStream::init_log() {
|
||||||
// %%% Need a MutexLocker?
|
// %%% Need a MutexLocker?
|
||||||
const char* log_name = LogFile != NULL ? LogFile : "hotspot_%p.log";
|
const char* log_name = LogFile != NULL ? LogFile : "hotspot_%p.log";
|
||||||
const char* try_name = make_log_name(log_name, NULL);
|
fileStream* file = open_file(log_name);
|
||||||
fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name);
|
|
||||||
if (!file->is_open()) {
|
|
||||||
// Try again to open the file.
|
|
||||||
char warnbuf[O_BUFLEN*2];
|
|
||||||
jio_snprintf(warnbuf, sizeof(warnbuf),
|
|
||||||
"Warning: Cannot open log file: %s\n", try_name);
|
|
||||||
// Note: This feature is for maintainer use only. No need for L10N.
|
|
||||||
jio_print(warnbuf);
|
|
||||||
FREE_C_HEAP_ARRAY(char, try_name);
|
|
||||||
try_name = make_log_name(log_name, os::get_temp_directory());
|
|
||||||
jio_snprintf(warnbuf, sizeof(warnbuf),
|
|
||||||
"Warning: Forcing option -XX:LogFile=%s\n", try_name);
|
|
||||||
jio_print(warnbuf);
|
|
||||||
delete file;
|
|
||||||
file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name);
|
|
||||||
}
|
|
||||||
FREE_C_HEAP_ARRAY(char, try_name);
|
|
||||||
|
|
||||||
if (file->is_open()) {
|
if (file != NULL) {
|
||||||
_log_file = file;
|
_log_file = file;
|
||||||
xmlStream* xs = new(ResourceObj::C_HEAP, mtInternal) xmlStream(file);
|
_outer_xmlStream = new(ResourceObj::C_HEAP, mtInternal) xmlStream(file);
|
||||||
_outer_xmlStream = xs;
|
start_log();
|
||||||
|
} else {
|
||||||
|
// and leave xtty as NULL
|
||||||
|
LogVMOutput = false;
|
||||||
|
DisplayVMOutput = true;
|
||||||
|
LogCompilation = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void defaultStream::start_log() {
|
||||||
|
xmlStream*xs = _outer_xmlStream;
|
||||||
if (this == tty) xtty = xs;
|
if (this == tty) xtty = xs;
|
||||||
// Write XML header.
|
// Write XML header.
|
||||||
xs->print_cr("<?xml version='1.0' encoding='UTF-8'?>");
|
xs->print_cr("<?xml version='1.0' encoding='UTF-8'?>");
|
||||||
@ -897,13 +988,6 @@ void defaultStream::init_log() {
|
|||||||
xs->head("tty");
|
xs->head("tty");
|
||||||
// All further non-markup text gets copied to the tty:
|
// All further non-markup text gets copied to the tty:
|
||||||
xs->_text = this; // requires friend declaration!
|
xs->_text = this; // requires friend declaration!
|
||||||
} else {
|
|
||||||
delete(file);
|
|
||||||
// and leave xtty as NULL
|
|
||||||
LogVMOutput = false;
|
|
||||||
DisplayVMOutput = true;
|
|
||||||
LogCompilation = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// finish_log() is called during normal VM shutdown. finish_log_on_error() is
|
// finish_log() is called during normal VM shutdown. finish_log_on_error() is
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
#include "compiler/compileBroker.hpp"
|
#include "compiler/compileBroker.hpp"
|
||||||
@ -807,7 +808,8 @@ fdStream VMError::log; // error log used by VMError::report_and_die()
|
|||||||
static int expand_and_open(const char* pattern, char* buf, size_t buflen, size_t pos) {
|
static int expand_and_open(const char* pattern, char* buf, size_t buflen, size_t pos) {
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
if (Arguments::copy_expand_pid(pattern, strlen(pattern), &buf[pos], buflen - pos)) {
|
if (Arguments::copy_expand_pid(pattern, strlen(pattern), &buf[pos], buflen - pos)) {
|
||||||
fd = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0666);
|
// the O_EXCL flag will cause the open to fail if the file exists
|
||||||
|
fd = open(buf, O_RDWR | O_CREAT | O_EXCL, 0666);
|
||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -33,6 +33,10 @@
|
|||||||
#include "runtime/vmThread.hpp"
|
#include "runtime/vmThread.hpp"
|
||||||
#include "utilities/xmlstream.hpp"
|
#include "utilities/xmlstream.hpp"
|
||||||
|
|
||||||
|
// Do not assert this condition if there's already another error reported.
|
||||||
|
#define assert_if_no_error(cond, msg) \
|
||||||
|
vmassert((cond) || is_error_reported(), msg)
|
||||||
|
|
||||||
void xmlStream::initialize(outputStream* out) {
|
void xmlStream::initialize(outputStream* out) {
|
||||||
_out = out;
|
_out = out;
|
||||||
_last_flush = 0;
|
_last_flush = 0;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -69,7 +69,6 @@ needs_jdk = \
|
|||||||
gc/metaspace/TestPerfCountersAndMemoryPools.java \
|
gc/metaspace/TestPerfCountersAndMemoryPools.java \
|
||||||
runtime/6819213/TestBootNativeLibraryPath.java \
|
runtime/6819213/TestBootNativeLibraryPath.java \
|
||||||
runtime/7158988/FieldMonitor.java \
|
runtime/7158988/FieldMonitor.java \
|
||||||
runtime/7194254/Test7194254.java \
|
|
||||||
runtime/Metaspace/FragmentMetaspace.java \
|
runtime/Metaspace/FragmentMetaspace.java \
|
||||||
runtime/NMT/BaselineWithParameter.java \
|
runtime/NMT/BaselineWithParameter.java \
|
||||||
runtime/NMT/JcmdBaselineDetail.java \
|
runtime/NMT/JcmdBaselineDetail.java \
|
||||||
@ -94,6 +93,7 @@ needs_jdk = \
|
|||||||
runtime/NMT/VirtualAllocTestType.java \
|
runtime/NMT/VirtualAllocTestType.java \
|
||||||
runtime/RedefineObject/TestRedefineObject.java \
|
runtime/RedefineObject/TestRedefineObject.java \
|
||||||
runtime/Thread/TestThreadDumpMonitorContention.java \
|
runtime/Thread/TestThreadDumpMonitorContention.java \
|
||||||
|
runtime/Thread/ThreadPriorities.java \
|
||||||
runtime/XCheckJniJsig/XCheckJSig.java \
|
runtime/XCheckJniJsig/XCheckJSig.java \
|
||||||
serviceability/attach/AttachWithStalePidFile.java \
|
serviceability/attach/AttachWithStalePidFile.java \
|
||||||
serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java \
|
serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java \
|
||||||
@ -232,7 +232,8 @@ needs_g1gc = \
|
|||||||
gc/g1/ \
|
gc/g1/ \
|
||||||
gc/metaspace/G1AddMetaspaceDependency.java \
|
gc/metaspace/G1AddMetaspaceDependency.java \
|
||||||
gc/metaspace/TestMetaspacePerfCounters.java \
|
gc/metaspace/TestMetaspacePerfCounters.java \
|
||||||
gc/startup_warnings/TestG1.java
|
gc/startup_warnings/TestG1.java \
|
||||||
|
gc/whitebox/TestConcMarkCycleWB.java
|
||||||
|
|
||||||
# All tests that explicitly set the serial GC
|
# All tests that explicitly set the serial GC
|
||||||
#
|
#
|
||||||
@ -357,7 +358,8 @@ hotspot_compiler_2 = \
|
|||||||
compiler/inlining/ \
|
compiler/inlining/ \
|
||||||
compiler/integerArithmetic/ \
|
compiler/integerArithmetic/ \
|
||||||
compiler/interpreter/ \
|
compiler/interpreter/ \
|
||||||
-compiler/codegen/7184394
|
-compiler/codegen/7184394 \
|
||||||
|
-compiler/codecache/stress
|
||||||
|
|
||||||
hotspot_compiler_3 = \
|
hotspot_compiler_3 = \
|
||||||
compiler/intrinsics/ \
|
compiler/intrinsics/ \
|
||||||
|
@ -37,6 +37,7 @@ import sun.hotspot.code.BlobType;
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* @test PoolsIndependenceTest
|
* @test PoolsIndependenceTest
|
||||||
|
* @ignore 8068385
|
||||||
* @library /testlibrary /../../test/lib
|
* @library /testlibrary /../../test/lib
|
||||||
* @build PoolsIndependenceTest
|
* @build PoolsIndependenceTest
|
||||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.oracle.java.testlibrary.TimeLimitedRunner;
|
||||||
|
import com.oracle.java.testlibrary.Utils;
|
||||||
|
|
||||||
|
public class CodeCacheStressRunner {
|
||||||
|
private final Runnable action;
|
||||||
|
public CodeCacheStressRunner(Runnable action) {
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void runTest() {
|
||||||
|
Helper.startInfiniteLoopThread(action);
|
||||||
|
try {
|
||||||
|
// adjust timeout and substract vm init and exit time
|
||||||
|
long timeout = Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT);
|
||||||
|
timeout *= 0.9;
|
||||||
|
new TimeLimitedRunner(timeout, 2.0d, this::test).call();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new Error("Exception occurred during test execution", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean test() {
|
||||||
|
Helper.TestCase obj = Helper.TestCase.get();
|
||||||
|
Helper.callMethod(obj.getCallable(), obj.expectedValue());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
141
hotspot/test/compiler/codecache/stress/Helper.java
Normal file
141
hotspot/test/compiler/codecache/stress/Helper.java
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.oracle.java.testlibrary.Asserts;
|
||||||
|
import com.oracle.java.testlibrary.ByteCodeLoader;
|
||||||
|
import com.oracle.java.testlibrary.InfiniteLoop;
|
||||||
|
import com.oracle.java.testlibrary.Utils;
|
||||||
|
import sun.hotspot.WhiteBox;
|
||||||
|
|
||||||
|
public final class Helper {
|
||||||
|
public static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
|
||||||
|
public static final Random RNG = Utils.getRandomInstance();
|
||||||
|
|
||||||
|
private static final long THRESHOLD = WHITE_BOX.getIntxVMFlag("CompileThreshold");
|
||||||
|
private static final String TEST_CASE_IMPL_CLASS_NAME = "Helper$TestCaseImpl";
|
||||||
|
private static byte[] CLASS_DATA;
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
CLASS_DATA = loadClassData(TEST_CASE_IMPL_CLASS_NAME);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new Error("TESTBUG: cannot load class byte code", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Helper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startInfiniteLoopThread(Runnable action) {
|
||||||
|
startInfiniteLoopThread(action, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startInfiniteLoopThread(Runnable action, long millis) {
|
||||||
|
Thread t = new Thread(new InfiniteLoop(action, millis));
|
||||||
|
t.setDaemon(true);
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int callMethod(Callable<Integer> callable, int expected) {
|
||||||
|
int result = 0;
|
||||||
|
for (int i = 0; i < THRESHOLD; ++i) {
|
||||||
|
try {
|
||||||
|
result = callable.call();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new AssertionError(
|
||||||
|
"Exception occurred during test method execution", e);
|
||||||
|
}
|
||||||
|
Asserts.assertEQ(result, expected, "Method returns unexpected value");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] loadClassData(String name) throws IOException {
|
||||||
|
try (BufferedInputStream in = new BufferedInputStream(
|
||||||
|
ClassLoader.getSystemResourceAsStream(name.replace(".", "/")
|
||||||
|
+ ".class"))) {
|
||||||
|
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int read;
|
||||||
|
while ((read = in.read(buffer)) != -1) {
|
||||||
|
result.write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
return result.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TestCase {
|
||||||
|
|
||||||
|
public static TestCase get() {
|
||||||
|
try {
|
||||||
|
Class clazz = ByteCodeLoader.load(
|
||||||
|
TEST_CASE_IMPL_CLASS_NAME, CLASS_DATA);
|
||||||
|
return (TestCase) clazz.newInstance();
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new Error(String.format(
|
||||||
|
"TESTBUG: error while creating %s instance from reloaded class",
|
||||||
|
TEST_CASE_IMPL_CLASS_NAME), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Callable<Integer> getCallable();
|
||||||
|
int method();
|
||||||
|
int expectedValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TestCaseImpl implements TestCase {
|
||||||
|
private static final int RETURN_VALUE = 42;
|
||||||
|
private static final int RECURSION_DEPTH = 10;
|
||||||
|
private volatile int i;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Callable<Integer> getCallable() {
|
||||||
|
return () -> {
|
||||||
|
i = 0;
|
||||||
|
return method();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int method() {
|
||||||
|
++i;
|
||||||
|
int result = RETURN_VALUE;
|
||||||
|
if (i < RECURSION_DEPTH) {
|
||||||
|
return result + method();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int expectedValue() {
|
||||||
|
return RETURN_VALUE * RECURSION_DEPTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import com.oracle.java.testlibrary.Platform;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test OverloadCompileQueueTest
|
||||||
|
* @library /testlibrary /../../test/lib
|
||||||
|
* @build OverloadCompileQueueTest
|
||||||
|
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
|
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||||
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -XX:CompileCommand=dontinline,Helper$TestCase::method
|
||||||
|
* -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache OverloadCompileQueueTest
|
||||||
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -XX:CompileCommand=dontinline,Helper$TestCase::method
|
||||||
|
* -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache OverloadCompileQueueTest
|
||||||
|
* @summary stressing code cache by overloading compile queues
|
||||||
|
*/
|
||||||
|
public class OverloadCompileQueueTest implements Runnable {
|
||||||
|
private static final int MAX_SLEEP = 10000;
|
||||||
|
private static final String METHOD_TO_ENQUEUE = "method";
|
||||||
|
private static final int LEVEL_SIMPLE = 1;
|
||||||
|
private static final int LEVEL_FULL_OPTIMIZATION = 4;
|
||||||
|
private static final boolean INTERPRETED
|
||||||
|
= System.getProperty("java.vm.info").startsWith("interpreted ");
|
||||||
|
private static final boolean TIERED_COMPILATION
|
||||||
|
= Helper.WHITE_BOX.getBooleanVMFlag("TieredCompilation");
|
||||||
|
private static final int TIERED_STOP_AT_LEVEL
|
||||||
|
= Helper.WHITE_BOX.getIntxVMFlag("TieredStopAtLevel").intValue();
|
||||||
|
private static final int[] AVAILABLE_LEVELS;
|
||||||
|
static {
|
||||||
|
if (TIERED_COMPILATION) {
|
||||||
|
AVAILABLE_LEVELS = IntStream
|
||||||
|
.rangeClosed(LEVEL_SIMPLE, TIERED_STOP_AT_LEVEL)
|
||||||
|
.toArray();
|
||||||
|
} else if (Platform.isServer()) {
|
||||||
|
AVAILABLE_LEVELS = new int[] { LEVEL_FULL_OPTIMIZATION };
|
||||||
|
} else if (Platform.isClient() || Platform.isMinimal()) {
|
||||||
|
AVAILABLE_LEVELS = new int[] { LEVEL_SIMPLE };
|
||||||
|
} else {
|
||||||
|
throw new Error(String.format(
|
||||||
|
"TESTBUG: unknown VM: %s", System.getProperty("java.vm.name")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
if (INTERPRETED) {
|
||||||
|
System.err.println("Test isn't applicable for interpreter. Skip test.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new CodeCacheStressRunner(new OverloadCompileQueueTest()).runTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public OverloadCompileQueueTest() {
|
||||||
|
Helper.startInfiniteLoopThread(this::lockUnlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Helper.TestCase obj = Helper.TestCase.get();
|
||||||
|
Class clazz = obj.getClass();
|
||||||
|
Method mEnqueue;
|
||||||
|
try {
|
||||||
|
mEnqueue = clazz.getMethod(METHOD_TO_ENQUEUE);
|
||||||
|
} catch (NoSuchMethodException | SecurityException e) {
|
||||||
|
throw new Error(String.format(
|
||||||
|
"TESTBUG: cannot get method '%s' of class %s",
|
||||||
|
METHOD_TO_ENQUEUE, clazz.getName()), e);
|
||||||
|
}
|
||||||
|
for (int compLevel : AVAILABLE_LEVELS) {
|
||||||
|
Helper.WHITE_BOX.enqueueMethodForCompilation(mEnqueue, compLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lockUnlock() {
|
||||||
|
try {
|
||||||
|
Helper.WHITE_BOX.lockCompilation();
|
||||||
|
Thread.sleep(Helper.RNG.nextInt(MAX_SLEEP));
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new Error("TESTBUG: lockUnlocker thread was unexpectedly interrupted", e);
|
||||||
|
} finally {
|
||||||
|
Helper.WHITE_BOX.unlockCompilation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import sun.hotspot.code.BlobType;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test RandomAllocationTest
|
||||||
|
* @library /testlibrary /../../test/lib
|
||||||
|
* @build RandomAllocationTest
|
||||||
|
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
|
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||||
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -XX:CompileCommand=dontinline,Helper$TestCase::method
|
||||||
|
* -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache RandomAllocationTest
|
||||||
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -XX:CompileCommand=dontinline,Helper$TestCase::method
|
||||||
|
* -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache RandomAllocationTest
|
||||||
|
* @summary stressing code cache by allocating randomly sized "dummy" code blobs
|
||||||
|
*/
|
||||||
|
public class RandomAllocationTest implements Runnable {
|
||||||
|
private static final long CODE_CACHE_SIZE
|
||||||
|
= Helper.WHITE_BOX.getUintxVMFlag("ReservedCodeCacheSize");
|
||||||
|
private static final int MAX_BLOB_SIZE = (int) (CODE_CACHE_SIZE >> 7);
|
||||||
|
private static final BlobType[] BLOB_TYPES
|
||||||
|
= BlobType.getAvailable().toArray(new BlobType[0]);
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new CodeCacheStressRunner(new RandomAllocationTest()).runTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ArrayList<Long> blobs = new ArrayList<>();
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
boolean allocate = blobs.isEmpty() || Helper.RNG.nextBoolean();
|
||||||
|
if (allocate) {
|
||||||
|
int type = Helper.RNG.nextInt(BLOB_TYPES.length);
|
||||||
|
long addr = Helper.WHITE_BOX.allocateCodeBlob(
|
||||||
|
Helper.RNG.nextInt(MAX_BLOB_SIZE), BLOB_TYPES[type].id);
|
||||||
|
if (addr != 0) {
|
||||||
|
blobs.add(addr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int index = Helper.RNG.nextInt(blobs.size());
|
||||||
|
Helper.WHITE_BOX.freeCodeBlob(blobs.remove(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test UnexpectedDeoptimizationTest
|
||||||
|
* @library /testlibrary /../../test/lib
|
||||||
|
* @build UnexpectedDeoptimizationTest
|
||||||
|
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
|
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||||
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -XX:CompileCommand=dontinline,Helper$TestCase::method
|
||||||
|
* -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache -XX:-DeoptimizeRandom
|
||||||
|
* UnexpectedDeoptimizationTest
|
||||||
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -XX:CompileCommand=dontinline,Helper$TestCase::method
|
||||||
|
* -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom
|
||||||
|
* UnexpectedDeoptimizationTest
|
||||||
|
* @summary stressing code cache by forcing unexpected deoptimizations
|
||||||
|
*/
|
||||||
|
public class UnexpectedDeoptimizationTest implements Runnable {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new CodeCacheStressRunner(new UnexpectedDeoptimizationTest()).runTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Helper.WHITE_BOX.deoptimizeFrames(Helper.RNG.nextBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -25,7 +25,7 @@
|
|||||||
* @test
|
* @test
|
||||||
* @bug 8054224
|
* @bug 8054224
|
||||||
* @summary Recursive method compiled by C1 is unable to catch StackOverflowError
|
* @summary Recursive method compiled by C1 is unable to catch StackOverflowError
|
||||||
* @run main/othervm -Xcomp -XX:CompileOnly=Test.run -XX:+TieredCompilation -XX:TieredStopAtLevel=2 -Xss256K TestRecursiveReplacedException
|
* @run main/othervm -Xcomp -XX:CompileOnly=Test.run -XX:+TieredCompilation -XX:TieredStopAtLevel=2 -Xss392K TestRecursiveReplacedException
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
73
hotspot/test/compiler/floatingpoint/TestPow2.java
Normal file
73
hotspot/test/compiler/floatingpoint/TestPow2.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8063086
|
||||||
|
* @summary X^2 special case for C2 yields different result than interpreter
|
||||||
|
* @library /testlibrary /../../test/lib /compiler/whitebox
|
||||||
|
* @build TestPow2
|
||||||
|
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||||
|
* -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestPow2
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
import sun.hotspot.WhiteBox;
|
||||||
|
|
||||||
|
public class TestPow2 {
|
||||||
|
|
||||||
|
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
|
||||||
|
|
||||||
|
private static final double base = 5350.456329377186;
|
||||||
|
private static final double exp = 2.0;
|
||||||
|
|
||||||
|
static double m() {
|
||||||
|
return Math.pow(base, exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void main(String[] args) throws NoSuchMethodException {
|
||||||
|
Method test_method = TestPow2.class.getDeclaredMethod("m");
|
||||||
|
|
||||||
|
double interpreter_result = m();
|
||||||
|
|
||||||
|
// Compile with C1 if possible
|
||||||
|
WHITE_BOX.enqueueMethodForCompilation(test_method, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
|
||||||
|
|
||||||
|
double c1_result = m();
|
||||||
|
|
||||||
|
WHITE_BOX.deoptimizeMethod(test_method);
|
||||||
|
|
||||||
|
// Compile it with C2 if possible
|
||||||
|
WHITE_BOX.enqueueMethodForCompilation(test_method, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION);
|
||||||
|
|
||||||
|
double c2_result = m();
|
||||||
|
|
||||||
|
if (interpreter_result != c1_result || interpreter_result != c2_result ||
|
||||||
|
c1_result != c2_result) {
|
||||||
|
System.out.println("interpreter = " + interpreter_result + " c1 = " + c1_result + " c2 = " + c2_result);
|
||||||
|
throw new RuntimeException("Test Failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@
|
|||||||
* @bug 8042235
|
* @bug 8042235
|
||||||
* @summary redefining method used by multiple MethodHandles crashes VM
|
* @summary redefining method used by multiple MethodHandles crashes VM
|
||||||
* @compile -XDignore.symbol.file RedefineMethodUsedByMultipleMethodHandles.java
|
* @compile -XDignore.symbol.file RedefineMethodUsedByMultipleMethodHandles.java
|
||||||
|
* @ignore 7076820
|
||||||
* @run main RedefineMethodUsedByMultipleMethodHandles
|
* @run main RedefineMethodUsedByMultipleMethodHandles
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ public class CheckCompileCommandOption {
|
|||||||
out.shouldContain(expected_output);
|
out.shouldContain(expected_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
out.shouldNotContain("CompilerOracle: unrecognized line");
|
out.shouldNotContain("CompileCommand: unrecognized line");
|
||||||
out.shouldHaveExitValue(0);
|
out.shouldHaveExitValue(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +183,7 @@ public class CheckCompileCommandOption {
|
|||||||
pb = ProcessTools.createJavaProcessBuilder(arguments);
|
pb = ProcessTools.createJavaProcessBuilder(arguments);
|
||||||
out = new OutputAnalyzer(pb.start());
|
out = new OutputAnalyzer(pb.start());
|
||||||
|
|
||||||
out.shouldContain("CompilerOracle: unrecognized line");
|
out.shouldContain("CompileCommand: unrecognized line");
|
||||||
out.shouldHaveExitValue(0);
|
out.shouldHaveExitValue(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import com.oracle.java.testlibrary.*;
|
|||||||
* @bug 8038636
|
* @bug 8038636
|
||||||
* @library /testlibrary
|
* @library /testlibrary
|
||||||
* @build Agent
|
* @build Agent
|
||||||
|
* @ignore 7076820
|
||||||
* @run main ClassFileInstaller Agent
|
* @run main ClassFileInstaller Agent
|
||||||
* @run main Launcher
|
* @run main Launcher
|
||||||
* @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -XX:ReservedCodeCacheSize=3M Agent
|
* @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -XX:ReservedCodeCacheSize=3M Agent
|
||||||
|
@ -28,6 +28,7 @@ import com.oracle.java.testlibrary.*;
|
|||||||
* @bug 8040237
|
* @bug 8040237
|
||||||
* @library /testlibrary
|
* @library /testlibrary
|
||||||
* @build Agent Test A B
|
* @build Agent Test A B
|
||||||
|
* @ignore 7076820
|
||||||
* @run main ClassFileInstaller Agent
|
* @run main ClassFileInstaller Agent
|
||||||
* @run main Launcher
|
* @run main Launcher
|
||||||
* @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -XX:ReservedCodeCacheSize=3M Agent
|
* @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -XX:ReservedCodeCacheSize=3M Agent
|
||||||
|
@ -53,6 +53,7 @@ import sun.misc.Unsafe;
|
|||||||
*/
|
*/
|
||||||
public class TestRTMDeoptOnLowAbortRatio extends CommandLineOptionTest {
|
public class TestRTMDeoptOnLowAbortRatio extends CommandLineOptionTest {
|
||||||
private static final long LOCKING_THRESHOLD = 100L;
|
private static final long LOCKING_THRESHOLD = 100L;
|
||||||
|
private static final long ABORT_THRESHOLD = LOCKING_THRESHOLD / 2L;
|
||||||
|
|
||||||
private TestRTMDeoptOnLowAbortRatio() {
|
private TestRTMDeoptOnLowAbortRatio() {
|
||||||
super(new AndPredicate(new SupportedCPU(), new SupportedVM()));
|
super(new AndPredicate(new SupportedCPU(), new SupportedVM()));
|
||||||
@ -77,7 +78,8 @@ public class TestRTMDeoptOnLowAbortRatio extends CommandLineOptionTest {
|
|||||||
useStackLock),
|
useStackLock),
|
||||||
CommandLineOptionTest.prepareNumericFlag("RTMLockingThreshold",
|
CommandLineOptionTest.prepareNumericFlag("RTMLockingThreshold",
|
||||||
TestRTMDeoptOnLowAbortRatio.LOCKING_THRESHOLD),
|
TestRTMDeoptOnLowAbortRatio.LOCKING_THRESHOLD),
|
||||||
"-XX:RTMAbortThreshold=1",
|
CommandLineOptionTest.prepareNumericFlag("RTMAbortThreshold",
|
||||||
|
TestRTMDeoptOnLowAbortRatio.ABORT_THRESHOLD),
|
||||||
"-XX:RTMAbortRatio=100",
|
"-XX:RTMAbortRatio=100",
|
||||||
"-XX:CompileThreshold=1",
|
"-XX:CompileThreshold=1",
|
||||||
"-XX:RTMRetryCount=0",
|
"-XX:RTMRetryCount=0",
|
||||||
@ -107,7 +109,7 @@ public class TestRTMDeoptOnLowAbortRatio extends CommandLineOptionTest {
|
|||||||
|
|
||||||
for (RTMLockingStatistics s : statistics) {
|
for (RTMLockingStatistics s : statistics) {
|
||||||
if (s.getTotalLocks()
|
if (s.getTotalLocks()
|
||||||
== TestRTMDeoptOnLowAbortRatio.LOCKING_THRESHOLD + 1L) {
|
== TestRTMDeoptOnLowAbortRatio.LOCKING_THRESHOLD) {
|
||||||
Asserts.assertNull(statisticsBeforeDeopt,
|
Asserts.assertNull(statisticsBeforeDeopt,
|
||||||
"Only one abort was expected during test run");
|
"Only one abort was expected during test run");
|
||||||
statisticsBeforeDeopt = s;
|
statisticsBeforeDeopt = s;
|
||||||
@ -154,8 +156,7 @@ public class TestRTMDeoptOnLowAbortRatio extends CommandLineOptionTest {
|
|||||||
}
|
}
|
||||||
for (int i = 0; i < AbortProvoker.DEFAULT_ITERATIONS; i++) {
|
for (int i = 0; i < AbortProvoker.DEFAULT_ITERATIONS; i++) {
|
||||||
AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated);
|
AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated);
|
||||||
t.forceAbort(
|
t.forceAbort(i >= TestRTMDeoptOnLowAbortRatio.ABORT_THRESHOLD);
|
||||||
i == TestRTMDeoptOnLowAbortRatio.LOCKING_THRESHOLD);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ public class TestRTMLockingThreshold extends CommandLineOptionTest {
|
|||||||
* interrupts, VMM calls, etc. during first lock attempt.
|
* interrupts, VMM calls, etc. during first lock attempt.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static final int ABORT_THRESHOLD = 10;
|
private static final int MIN_ABORT_THRESHOLD = 10;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void runTestCases() throws Throwable {
|
protected void runTestCases() throws Throwable {
|
||||||
@ -75,6 +75,9 @@ public class TestRTMLockingThreshold extends CommandLineOptionTest {
|
|||||||
boolean useStackLock) throws Throwable {
|
boolean useStackLock) throws Throwable {
|
||||||
CompilableTest test = new Test();
|
CompilableTest test = new Test();
|
||||||
|
|
||||||
|
int abortThreshold = Math.max(lockingThreshold / 2,
|
||||||
|
TestRTMLockingThreshold.MIN_ABORT_THRESHOLD);
|
||||||
|
|
||||||
OutputAnalyzer outputAnalyzer = RTMTestBase.executeRTMTest(
|
OutputAnalyzer outputAnalyzer = RTMTestBase.executeRTMTest(
|
||||||
test,
|
test,
|
||||||
"-XX:CompileThreshold=1",
|
"-XX:CompileThreshold=1",
|
||||||
@ -84,7 +87,7 @@ public class TestRTMLockingThreshold extends CommandLineOptionTest {
|
|||||||
"-XX:RTMTotalCountIncrRate=1",
|
"-XX:RTMTotalCountIncrRate=1",
|
||||||
"-XX:RTMRetryCount=0",
|
"-XX:RTMRetryCount=0",
|
||||||
CommandLineOptionTest.prepareNumericFlag("RTMAbortThreshold",
|
CommandLineOptionTest.prepareNumericFlag("RTMAbortThreshold",
|
||||||
TestRTMLockingThreshold.ABORT_THRESHOLD),
|
abortThreshold),
|
||||||
CommandLineOptionTest.prepareNumericFlag("RTMLockingThreshold",
|
CommandLineOptionTest.prepareNumericFlag("RTMLockingThreshold",
|
||||||
lockingThreshold),
|
lockingThreshold),
|
||||||
"-XX:RTMAbortRatio=100",
|
"-XX:RTMAbortRatio=100",
|
||||||
@ -103,16 +106,12 @@ public class TestRTMLockingThreshold extends CommandLineOptionTest {
|
|||||||
+ "RTM locking statistics entries.");
|
+ "RTM locking statistics entries.");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We force abort on each odd iteration, so if RTMLockingThreshold==0,
|
* If RTMLockingThreshold==0, then we have to make at least 1 call.
|
||||||
* then we have to make 1 call without abort to avoid rtm state
|
|
||||||
* transition to NoRTM (otherwise actual abort ratio will be 100%),
|
|
||||||
* and after that make 1 call with abort to force deoptimization.
|
|
||||||
* This leads us to two locks for threshold 0.
|
|
||||||
* For other threshold values we have to make RTMLockingThreshold + 1
|
|
||||||
* locks if locking threshold is even, or + 0 if odd.
|
|
||||||
*/
|
*/
|
||||||
long expectedValue = lockingThreshold +
|
long expectedValue = lockingThreshold;
|
||||||
(lockingThreshold == 0L ? 2L : lockingThreshold % 2L);
|
if (expectedValue == 0) {
|
||||||
|
expectedValue++;
|
||||||
|
}
|
||||||
|
|
||||||
RTMLockingStatistics statBeforeDeopt = null;
|
RTMLockingStatistics statBeforeDeopt = null;
|
||||||
for (RTMLockingStatistics s : statistics) {
|
for (RTMLockingStatistics s : statistics) {
|
||||||
@ -159,15 +158,16 @@ public class TestRTMLockingThreshold extends CommandLineOptionTest {
|
|||||||
* Test <inflate monitor>
|
* Test <inflate monitor>
|
||||||
*/
|
*/
|
||||||
public static void main(String args[]) throws Throwable {
|
public static void main(String args[]) throws Throwable {
|
||||||
Asserts.assertGTE(args.length, 1, "One argument required.");
|
Asserts.assertGTE(args.length, 2, "Two arguments required.");
|
||||||
Test t = new Test();
|
Test t = new Test();
|
||||||
boolean shouldBeInflated = Boolean.valueOf(args[0]);
|
boolean shouldBeInflated = Boolean.valueOf(args[0]);
|
||||||
|
int lockingThreshold = Integer.valueOf(args[1]);
|
||||||
if (shouldBeInflated) {
|
if (shouldBeInflated) {
|
||||||
AbortProvoker.inflateMonitor(t.monitor);
|
AbortProvoker.inflateMonitor(t.monitor);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < Test.TOTAL_ITERATIONS; i++) {
|
for (int i = 0; i < Test.TOTAL_ITERATIONS; i++) {
|
||||||
AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated);
|
AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated);
|
||||||
t.lock(i % 2 == 1);
|
t.lock(i >= lockingThreshold / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
* -XX:+WhiteBoxAPI TestRTMTotalCountIncrRate
|
* -XX:+WhiteBoxAPI TestRTMTotalCountIncrRate
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import sun.misc.Unsafe;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.oracle.java.testlibrary.*;
|
import com.oracle.java.testlibrary.*;
|
||||||
@ -97,14 +98,12 @@ public class TestRTMTotalCountIncrRate extends CommandLineOptionTest {
|
|||||||
Asserts.assertEQ(lock.getTotalLocks(), Test.TOTAL_ITERATIONS,
|
Asserts.assertEQ(lock.getTotalLocks(), Test.TOTAL_ITERATIONS,
|
||||||
"Total locks should be exactly the same as amount of "
|
"Total locks should be exactly the same as amount of "
|
||||||
+ "iterations.");
|
+ "iterations.");
|
||||||
} else {
|
|
||||||
Asserts.assertGT(lock.getTotalLocks(), 0L, "RTM statistics "
|
|
||||||
+ "should contain information for at least on lock.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Test implements CompilableTest {
|
public static class Test implements CompilableTest {
|
||||||
private static final long TOTAL_ITERATIONS = 10000L;
|
private static final long TOTAL_ITERATIONS = 10000L;
|
||||||
|
private static final Unsafe UNSAFE = Utils.getUnsafe();
|
||||||
private final Object monitor = new Object();
|
private final Object monitor = new Object();
|
||||||
// Following field have to be static in order to avoid escape analysis.
|
// Following field have to be static in order to avoid escape analysis.
|
||||||
@SuppressWarnings("UnsuedDeclaration")
|
@SuppressWarnings("UnsuedDeclaration")
|
||||||
@ -120,8 +119,17 @@ public class TestRTMTotalCountIncrRate extends CommandLineOptionTest {
|
|||||||
return new String[] { getMethodWithLockName() };
|
return new String[] { getMethodWithLockName() };
|
||||||
}
|
}
|
||||||
|
|
||||||
public void lock() {
|
public void lock(booleab forceAbort) {
|
||||||
synchronized(monitor) {
|
synchronized(monitor) {
|
||||||
|
if (forceAbort) {
|
||||||
|
// We're calling native method in order to force
|
||||||
|
// abort. It's done by explicit xabort call emitted
|
||||||
|
// in SharedRuntime::generate_native_wrapper.
|
||||||
|
// If an actuall JNI call will be replaced by
|
||||||
|
// intrinsic - we'll be in trouble, since xabort
|
||||||
|
// will be no longer called and test may fail.
|
||||||
|
UNSAFE.addressSize();
|
||||||
|
}
|
||||||
Test.field++;
|
Test.field++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,7 +148,11 @@ public class TestRTMTotalCountIncrRate extends CommandLineOptionTest {
|
|||||||
for (long i = 0L; i < Test.TOTAL_ITERATIONS; i++) {
|
for (long i = 0L; i < Test.TOTAL_ITERATIONS; i++) {
|
||||||
AbortProvoker.verifyMonitorState(test.monitor,
|
AbortProvoker.verifyMonitorState(test.monitor,
|
||||||
shouldBeInflated);
|
shouldBeInflated);
|
||||||
test.lock();
|
// Force abort on first iteration to avoid rare case when
|
||||||
|
// there were no aborts and locks count was not incremented
|
||||||
|
// with RTMTotalCountIncrRate > 1 (in such case JVM won't
|
||||||
|
// print JVM locking statistics).
|
||||||
|
test.lock(i == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,9 +125,6 @@ public class TestPrintPreciseRTMLockingStatistics
|
|||||||
|
|
||||||
RTMLockingStatistics lock = statistics.get(0);
|
RTMLockingStatistics lock = statistics.get(0);
|
||||||
|
|
||||||
Asserts.assertGT(lock.getTotalLocks(), 0L, "RTM locking statistics "
|
|
||||||
+ "should contain non zero total locks count");
|
|
||||||
|
|
||||||
Asserts.assertGT(lock.getTotalAborts(), 0L,
|
Asserts.assertGT(lock.getTotalAborts(), 0L,
|
||||||
"RTM locking statistics should contain non zero total aborts "
|
"RTM locking statistics should contain non zero total aborts "
|
||||||
+ "count");
|
+ "count");
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
* @summary JVM crashes with "missing exception handler" error
|
* @summary JVM crashes with "missing exception handler" error
|
||||||
* @author volker.simonis@sap.com
|
* @author volker.simonis@sap.com
|
||||||
*
|
*
|
||||||
* @run main/othervm -XX:CompileThreshold=100 -Xbatch -Xss248k StackOverflowBug
|
* @run main/othervm -XX:CompileThreshold=100 -Xbatch -Xss392k StackOverflowBug
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
145
hotspot/test/compiler/testlibrary/uncommontrap/Verifier.java
Normal file
145
hotspot/test/compiler/testlibrary/uncommontrap/Verifier.java
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package uncommontrap;
|
||||||
|
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import com.oracle.java.testlibrary.Asserts;
|
||||||
|
/**
|
||||||
|
* Utility tool aimed to verify presence or absence of specified uncommon trap
|
||||||
|
* in compilation log.
|
||||||
|
*/
|
||||||
|
public class Verifier {
|
||||||
|
public static final String PROPERTIES_FILE_SUFFIX = ".verify.properties";
|
||||||
|
public static final String VERIFICATION_SHOULD_BE_SKIPPED
|
||||||
|
= "uncommon.trap.verification.skipped";
|
||||||
|
public static final String UNCOMMON_TRAP_NAME = "uncommon.trap.name";
|
||||||
|
public static final String UNCOMMON_TRAP_BCI = "uncommon.trap.bci";
|
||||||
|
public static final String UNCOMMON_TRAP_COMMENT = "uncommon.trap.comment";
|
||||||
|
public static final String UNCOMMON_TRAP_ACTION = "uncommon.trap.action";
|
||||||
|
public static final String UNCOMMON_TRAP_SHOULD_EMITTED
|
||||||
|
= "uncommon.trap.emitted";
|
||||||
|
public static final String UNCOMMON_TRAP_SHOULD_FIRED
|
||||||
|
= "uncommon.trap.fired";
|
||||||
|
|
||||||
|
private static final String EMITTED_TRAP_PATTERN
|
||||||
|
= "<uncommon_trap bci='%s' reason='%s' action='%s' "
|
||||||
|
+ "comment='%s'";
|
||||||
|
private static final String FIRED_TRAP_PATTERN
|
||||||
|
= "<uncommon_trap thread='[0-9]*' reason='%s' action='%s'";
|
||||||
|
private static final String JVMS_PATTERN = "<jvms bci='%s'";
|
||||||
|
|
||||||
|
public static void main(String args[]) {
|
||||||
|
if (args.length == 0) {
|
||||||
|
throw new Error("At least one argument containing name of "
|
||||||
|
+ "compilation log file is expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String compLogFile : args) {
|
||||||
|
try {
|
||||||
|
verify(Paths.get(compLogFile));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new Error("Unable to process compilation log.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verify(Path compLogFile) throws IOException {
|
||||||
|
Path propertiesFile = Paths.get(compLogFile.toString() +
|
||||||
|
PROPERTIES_FILE_SUFFIX);
|
||||||
|
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.load(new FileReader(propertiesFile.toFile()));
|
||||||
|
|
||||||
|
if (Boolean.valueOf(properties.getProperty(
|
||||||
|
VERIFICATION_SHOULD_BE_SKIPPED, "false"))) {
|
||||||
|
System.out.println("Skipping verification for log file: "
|
||||||
|
+ compLogFile.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Verifying log file: " + compLogFile.toString());
|
||||||
|
|
||||||
|
List<String> compLogContent = Files.readAllLines(compLogFile);
|
||||||
|
verifyUncommonTrapEmitted(properties, compLogContent);
|
||||||
|
verifyUncommonTrapFired(properties, compLogContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verifyUncommonTrapEmitted(Properties properties,
|
||||||
|
List<String> compLogContent) {
|
||||||
|
String emittedTrapRE = String.format(EMITTED_TRAP_PATTERN,
|
||||||
|
properties.getProperty(UNCOMMON_TRAP_BCI, ".*"),
|
||||||
|
properties.getProperty(UNCOMMON_TRAP_NAME, ".*"),
|
||||||
|
properties.getProperty(UNCOMMON_TRAP_ACTION, ".*"),
|
||||||
|
properties.getProperty(UNCOMMON_TRAP_COMMENT, ".*"));
|
||||||
|
Pattern pattern = Pattern.compile(emittedTrapRE);
|
||||||
|
|
||||||
|
long trapsCount = compLogContent.stream()
|
||||||
|
.filter(line -> pattern.matcher(line).find())
|
||||||
|
.count();
|
||||||
|
|
||||||
|
boolean shouldBeEmitted = Boolean.valueOf(
|
||||||
|
properties.getProperty(UNCOMMON_TRAP_SHOULD_EMITTED));
|
||||||
|
|
||||||
|
Asserts.assertEQ(shouldBeEmitted, trapsCount > 0, String.format(
|
||||||
|
"Uncommon trap that matches following string in compilation log"
|
||||||
|
+ " should %sbe emitted: %s.",
|
||||||
|
(shouldBeEmitted ? " " : "not "), emittedTrapRE));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verifyUncommonTrapFired(Properties properties,
|
||||||
|
List<String> compLogContent) {
|
||||||
|
String firedTrapRE = String.format(FIRED_TRAP_PATTERN,
|
||||||
|
properties.getProperty(UNCOMMON_TRAP_NAME, ".*"),
|
||||||
|
properties.getProperty(UNCOMMON_TRAP_ACTION, ".*"));
|
||||||
|
String jvmsRE = String.format(JVMS_PATTERN,
|
||||||
|
properties.getProperty(UNCOMMON_TRAP_BCI, ".*"));
|
||||||
|
|
||||||
|
boolean trapFired = false;
|
||||||
|
Pattern firedTrapPattern = Pattern.compile(firedTrapRE);
|
||||||
|
Pattern jvmsPattern = Pattern.compile(jvmsRE);
|
||||||
|
|
||||||
|
Iterator<String> iterator = compLogContent.iterator();
|
||||||
|
while (iterator.hasNext() && !trapFired) {
|
||||||
|
trapFired = firedTrapPattern.matcher(iterator.next()).find()
|
||||||
|
&& jvmsPattern.matcher(iterator.next()).find();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean shouldBeFired = Boolean.valueOf(
|
||||||
|
properties.getProperty(UNCOMMON_TRAP_SHOULD_FIRED));
|
||||||
|
Asserts.assertEQ(shouldBeFired, trapFired, String.format(
|
||||||
|
"Uncommon trap that matches following string in compilation log"
|
||||||
|
+ " should %sbe fired: %s.",
|
||||||
|
(shouldBeFired ? "" : "not "), firedTrapRE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -32,7 +32,7 @@ import java.lang.reflect.Method;
|
|||||||
* @build Test8009761
|
* @build Test8009761
|
||||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=exclude,Test8009761::m2 -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -Xss256K Test8009761
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=exclude,Test8009761::m2 -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -Xss392K Test8009761
|
||||||
*/
|
*/
|
||||||
public class Test8009761 {
|
public class Test8009761 {
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
* @test
|
* @test
|
||||||
* @bug 8029383
|
* @bug 8029383
|
||||||
* @summary stack overflow if callee is marked for deoptimization causes crash
|
* @summary stack overflow if callee is marked for deoptimization causes crash
|
||||||
* @run main/othervm -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,StackOverflowGuardPagesOff::m1 -XX:CompileCommand=exclude,StackOverflowGuardPagesOff::m2 -Xss256K -XX:-UseOnStackReplacement StackOverflowGuardPagesOff
|
* @run main/othervm -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,StackOverflowGuardPagesOff::m1 -XX:CompileCommand=exclude,StackOverflowGuardPagesOff::m2 -Xss392K -XX:-UseOnStackReplacement StackOverflowGuardPagesOff
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
* @test
|
* @test
|
||||||
* @bug 8032410
|
* @bug 8032410
|
||||||
* @summary Stack overflow at deoptimization doesn't release owned monitors
|
* @summary Stack overflow at deoptimization doesn't release owned monitors
|
||||||
* @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestStackBangMonitorOwned::m1 -XX:CompileCommand=exclude,TestStackBangMonitorOwned::m2 -Xss256K -XX:-UseOnStackReplacement TestStackBangMonitorOwned
|
* @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestStackBangMonitorOwned::m1 -XX:CompileCommand=exclude,TestStackBangMonitorOwned::m2 -Xss392K -XX:-UseOnStackReplacement TestStackBangMonitorOwned
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class TestStackBangMonitorOwned {
|
public class TestStackBangMonitorOwned {
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
* @test
|
* @test
|
||||||
* @bug 8028308
|
* @bug 8028308
|
||||||
* @summary rbp not restored when stack overflow is thrown from deopt/uncommon trap blobs
|
* @summary rbp not restored when stack overflow is thrown from deopt/uncommon trap blobs
|
||||||
* @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestStackBangRbp::m1 -XX:CompileCommand=exclude,TestStackBangRbp::m2 -Xss256K -XX:-UseOnStackReplacement TestStackBangRbp
|
* @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestStackBangRbp::m1 -XX:CompileCommand=exclude,TestStackBangRbp::m2 -Xss392K -XX:-UseOnStackReplacement TestStackBangRbp
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class TestStackBangRbp {
|
public class TestStackBangRbp {
|
||||||
|
257
hotspot/test/compiler/uncommontrap/TestUnstableIfTrap.java
Normal file
257
hotspot/test/compiler/uncommontrap/TestUnstableIfTrap.java
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import com.oracle.java.testlibrary.ByteCodeLoader;
|
||||||
|
import com.oracle.java.testlibrary.Platform;
|
||||||
|
import jdk.internal.org.objectweb.asm.ClassVisitor;
|
||||||
|
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||||
|
import jdk.internal.org.objectweb.asm.Label;
|
||||||
|
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||||
|
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||||
|
|
||||||
|
import sun.hotspot.WhiteBox;
|
||||||
|
import uncommontrap.Verifier;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8030976 8059226
|
||||||
|
* @library /testlibrary /compiler/testlibrary /../../test/lib
|
||||||
|
* @build TestUnstableIfTrap com.oracle.java.testlibrary.* uncommontrap.Verifier
|
||||||
|
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
|
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||||
|
* @run main/othervm -Xbatch -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -XX:+WhiteBoxAPI -XX:+LogCompilation
|
||||||
|
* -XX:CompileCommand=compileonly,UnstableIfExecutable.test
|
||||||
|
* -XX:LogFile=always_taken_not_fired.xml
|
||||||
|
* TestUnstableIfTrap ALWAYS_TAKEN false
|
||||||
|
* @run main/othervm -Xbatch -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -XX:+WhiteBoxAPI -XX:+LogCompilation
|
||||||
|
* -XX:CompileCommand=compileonly,UnstableIfExecutable.test
|
||||||
|
* -XX:LogFile=always_taken_fired.xml
|
||||||
|
* TestUnstableIfTrap ALWAYS_TAKEN true
|
||||||
|
* @run main/othervm -Xbatch -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -XX:+WhiteBoxAPI -XX:+LogCompilation
|
||||||
|
* -XX:CompileCommand=compileonly,UnstableIfExecutable.test
|
||||||
|
* -XX:LogFile=never_taken_not_fired.xml
|
||||||
|
* TestUnstableIfTrap NEVER_TAKEN false
|
||||||
|
* @run main/othervm -Xbatch -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -XX:+WhiteBoxAPI -XX:+LogCompilation
|
||||||
|
* -XX:CompileCommand=compileonly,UnstableIfExecutable.test
|
||||||
|
* -XX:LogFile=never_taken_fired.xml
|
||||||
|
* TestUnstableIfTrap NEVER_TAKEN true
|
||||||
|
* @run main uncommontrap.Verifier always_taken_not_fired.xml
|
||||||
|
* always_taken_fired.xml
|
||||||
|
* never_taken_not_fired.xml
|
||||||
|
* never_taken_fired.xml
|
||||||
|
*/
|
||||||
|
public class TestUnstableIfTrap {
|
||||||
|
private static final WhiteBox WB = WhiteBox.getWhiteBox();
|
||||||
|
private static final String CLASS_NAME = "UnstableIfExecutable";
|
||||||
|
private static final String METHOD_NAME = "test";
|
||||||
|
private static final String FIELD_NAME = "field";
|
||||||
|
private static final int ITERATIONS = 1_000_000;
|
||||||
|
// There is no dependency on particular class file version, so it could be
|
||||||
|
// set to any version (if you're updating this test for Java 42).
|
||||||
|
private static final int CLASS_FILE_VERSION = 49;
|
||||||
|
private static final int MAX_TIER = 4;
|
||||||
|
// This test aimed to verify that uncommon trap with reason "unstable_if"
|
||||||
|
// is emitted when method that contain control-flow divergence such that
|
||||||
|
// one of two branches is never taken (and other one is taken always).
|
||||||
|
// C2 will made a decision whether or not the branch was ever taken
|
||||||
|
// depending on method's profile.
|
||||||
|
// If profile was collected for a few method's invocations, then C2 will not
|
||||||
|
// trust in branches' probabilities and the tested trap won't be emitted.
|
||||||
|
// In fact, a method has to be invoked at least 40 time at the day when this
|
||||||
|
// comment was written (see Parse::dynamic_branch_prediction for an actual
|
||||||
|
// value). It would be to implementation dependent to use "40" as
|
||||||
|
// a threshold value in the test, so in order to improve test's robustness
|
||||||
|
// the threshold value is 1000: if the tested method was compiled by C2
|
||||||
|
// before it was invoked 1000 times, then we won't verify that trap was
|
||||||
|
// emitted and fired.
|
||||||
|
private static final int MIN_INVOCATIONS_BEFORE_C2_COMPILATION = 1000;
|
||||||
|
/**
|
||||||
|
* Description of test case parameters and uncommon trap that will
|
||||||
|
* be emitted during tested method compilation.
|
||||||
|
*/
|
||||||
|
private static enum TestCaseName {
|
||||||
|
ALWAYS_TAKEN(false, "taken always"),
|
||||||
|
NEVER_TAKEN(true, "taken never");
|
||||||
|
TestCaseName(boolean predicate, String comment) {
|
||||||
|
this.predicate = predicate;
|
||||||
|
this.comment = comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean predicate;
|
||||||
|
public final String name = "unstable_if";
|
||||||
|
public final String comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String args[]) {
|
||||||
|
if (args.length != 2) {
|
||||||
|
throw new Error("Expected two arguments: test case name and a "
|
||||||
|
+ "boolean determining if uncommon trap should be fired.");
|
||||||
|
}
|
||||||
|
test(TestCaseName.valueOf(args[0]), Boolean.valueOf(args[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test(TestCaseName testCase, boolean shouldBeFired) {
|
||||||
|
Method testMethod;
|
||||||
|
Label unstableIfLocation = new Label();
|
||||||
|
boolean shouldBeEmitted;
|
||||||
|
boolean compiledToEarly = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class testClass = ByteCodeLoader.load(CLASS_NAME,
|
||||||
|
generateTest(unstableIfLocation));
|
||||||
|
testMethod = testClass.getDeclaredMethod(METHOD_NAME,
|
||||||
|
boolean.class);
|
||||||
|
for (int i = 0; i < ITERATIONS; i++) {
|
||||||
|
testMethod.invoke(null, testCase.predicate);
|
||||||
|
if (i < MIN_INVOCATIONS_BEFORE_C2_COMPILATION
|
||||||
|
&& isMethodCompiledByC2(testMethod)) {
|
||||||
|
compiledToEarly = true;
|
||||||
|
// There is no sense in further invocations: we already
|
||||||
|
// decided to avoid verification.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We're checking that trap should be emitted (i.e. it was compiled
|
||||||
|
// by C2) before the trap is fired, because otherwise the nmethod
|
||||||
|
// will be deoptimized and isMethodCompiledByC2 will return false.
|
||||||
|
shouldBeEmitted = isMethodCompiledByC2(testMethod)
|
||||||
|
&& !compiledToEarly;
|
||||||
|
if (shouldBeFired) {
|
||||||
|
testMethod.invoke(null, !testCase.predicate);
|
||||||
|
}
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new Error("Test case should be generated, loaded and executed"
|
||||||
|
+ " without any issues.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldBeFired &= shouldBeEmitted;
|
||||||
|
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty(Verifier.VERIFICATION_SHOULD_BE_SKIPPED,
|
||||||
|
Boolean.toString(compiledToEarly));
|
||||||
|
properties.setProperty(Verifier.UNCOMMON_TRAP_SHOULD_EMITTED,
|
||||||
|
Boolean.toString(shouldBeEmitted));
|
||||||
|
properties.setProperty(Verifier.UNCOMMON_TRAP_SHOULD_FIRED,
|
||||||
|
Boolean.toString(shouldBeFired));
|
||||||
|
properties.setProperty(Verifier.UNCOMMON_TRAP_NAME, testCase.name);
|
||||||
|
properties.setProperty(Verifier.UNCOMMON_TRAP_COMMENT,
|
||||||
|
testCase.comment);
|
||||||
|
properties.setProperty(Verifier.UNCOMMON_TRAP_BCI,
|
||||||
|
Integer.toString(unstableIfLocation.getOffset()));
|
||||||
|
|
||||||
|
properties.list(System.out);
|
||||||
|
|
||||||
|
File f = new File(WB.getStringVMFlag("LogFile") +
|
||||||
|
Verifier.PROPERTIES_FILE_SUFFIX);
|
||||||
|
try (FileWriter wr = new FileWriter(f)) {
|
||||||
|
properties.store(wr, "");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new Error("Unable to store test properties.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isMethodCompiledByC2(Method m) {
|
||||||
|
boolean isTiered = WB.getBooleanVMFlag("TieredCompilation");
|
||||||
|
boolean isMethodCompiled = WB.isMethodCompiled(m);
|
||||||
|
boolean isMethodCompiledAtMaxTier
|
||||||
|
= WB.getMethodCompilationLevel(m) == MAX_TIER;
|
||||||
|
|
||||||
|
return Platform.isServer() && isMethodCompiled
|
||||||
|
&& (!isTiered || isMethodCompiledAtMaxTier);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates class with name {@code CLASS_NAME}, which will contain a
|
||||||
|
* static method {@code METHOD_NAME}:
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
* public abstract class UnstableIfExecutable {
|
||||||
|
* private static int field = 0;
|
||||||
|
*
|
||||||
|
* public static void test(boolean alwaysTrue) {
|
||||||
|
* if (alwaysTrue) {
|
||||||
|
* field++;
|
||||||
|
* } else {
|
||||||
|
* field--;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @return generated bytecode.
|
||||||
|
*/
|
||||||
|
private static byte[] generateTest(Label unstableIfLocation) {
|
||||||
|
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||||
|
|
||||||
|
cw.visit(CLASS_FILE_VERSION, ACC_PUBLIC | ACC_ABSTRACT, CLASS_NAME,
|
||||||
|
null, "java/lang/Object", null);
|
||||||
|
|
||||||
|
cw.visitField(ACC_PUBLIC | ACC_STATIC | ACC_VOLATILE, FIELD_NAME,
|
||||||
|
"I", null, Integer.valueOf(0));
|
||||||
|
|
||||||
|
generateTestMethod(cw, unstableIfLocation);
|
||||||
|
|
||||||
|
return cw.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void generateTestMethod(ClassVisitor cv,
|
||||||
|
Label unstableIfLocation) {
|
||||||
|
MethodVisitor mv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, METHOD_NAME,
|
||||||
|
"(Z)V", null, null);
|
||||||
|
mv.visitCode();
|
||||||
|
|
||||||
|
Label end = new Label();
|
||||||
|
Label falseBranch = new Label();
|
||||||
|
|
||||||
|
// push "field" field's value and 1 to stack
|
||||||
|
mv.visitFieldInsn(GETSTATIC, CLASS_NAME, FIELD_NAME, "I");
|
||||||
|
mv.visitInsn(ICONST_1);
|
||||||
|
// load argument's value
|
||||||
|
mv.visitVarInsn(ILOAD, 0); // alwaysTrue
|
||||||
|
// here is our unstable if
|
||||||
|
mv.visitLabel(unstableIfLocation);
|
||||||
|
mv.visitJumpInsn(IFEQ, falseBranch);
|
||||||
|
// increment on "true"
|
||||||
|
mv.visitInsn(IADD);
|
||||||
|
mv.visitJumpInsn(GOTO, end);
|
||||||
|
// decrement on "false"
|
||||||
|
mv.visitLabel(falseBranch);
|
||||||
|
mv.visitInsn(ISUB);
|
||||||
|
mv.visitLabel(end);
|
||||||
|
// bye bye
|
||||||
|
mv.visitInsn(RETURN);
|
||||||
|
|
||||||
|
mv.visitMaxs(0, 0);
|
||||||
|
mv.visitEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -34,6 +34,7 @@ import com.oracle.java.testlibrary.InfiniteLoop;
|
|||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 8059624 8064669
|
* @bug 8059624 8064669
|
||||||
|
* @ignore 8066998
|
||||||
* @library /testlibrary /../../test/lib
|
* @library /testlibrary /../../test/lib
|
||||||
* @build ForceNMethodSweepTest
|
* @build ForceNMethodSweepTest
|
||||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -26,34 +26,46 @@
|
|||||||
* @bug 8067438
|
* @bug 8067438
|
||||||
* @requires vm.gc=="null"
|
* @requires vm.gc=="null"
|
||||||
* @summary Verify that starting the VM with a small heap works
|
* @summary Verify that starting the VM with a small heap works
|
||||||
* @library /testlibrary
|
* @library /testlibrary /../../test/lib
|
||||||
* @run main/othervm -Xmx4m -XX:+UseParallelGC TestSmallHeap
|
* @build TestSmallHeap
|
||||||
* @run main/othervm -Xmx4m -XX:+UseSerialGC TestSmallHeap
|
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
* @run main/othervm -Xmx4m -XX:+UseG1GC TestSmallHeap
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseParallelGC TestSmallHeap
|
||||||
* @run main/othervm -Xmx4m -XX:+UseConcMarkSweepGC -XX:CMSMarkStackSizeMax=1032 TestSmallHeap
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseSerialGC TestSmallHeap
|
||||||
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseG1GC TestSmallHeap
|
||||||
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseConcMarkSweepGC TestSmallHeap
|
||||||
|
*
|
||||||
|
* Note: It would be nice to verify the minimal supported heap size (2m) here,
|
||||||
|
* but we align the heap size based on the card table size. And the card table
|
||||||
|
* size is aligned based on the minimal pages size provided by the os. This
|
||||||
|
* means that on most platforms, where the minimal page size is 4k, we get a
|
||||||
|
* minimal heap size of 2m but on Solaris/Sparc we have a page size of 8k and
|
||||||
|
* get a minimal heap size of 4m. And on platforms where the page size is 64k
|
||||||
|
* we get a minimal heap size of 32m. We never use large pages for the card table.
|
||||||
*
|
*
|
||||||
* Note: It would be nice to verify the minimal supported heap size here,
|
|
||||||
* but that turns out to be quite tricky since we align the heap size based
|
|
||||||
* on the card table size. And the card table size is aligned based on the
|
|
||||||
* minimal pages size provided by the os. This means that on most platforms,
|
|
||||||
* where the minimal page size is 4k, we get a minimal heap size of 2m but
|
|
||||||
* on Solaris/Sparc we have a page size of 8k and get a minimal heap size
|
|
||||||
* of 8m.
|
|
||||||
* There is also no check in the VM for verifying that the maximum heap size
|
* There is also no check in the VM for verifying that the maximum heap size
|
||||||
* is larger than the supported minimal heap size. This means that specifying
|
* is larger than the supported minimal heap size. This means that specifying
|
||||||
* -Xmx1m on the command line is fine but will give a heap of 2m (or 4m).
|
* -Xmx1m on the command line is fine but will give a heap of 2m (or 4m or 32m).
|
||||||
* To work around these rather strange behaviors this test uses 4m for all
|
*
|
||||||
* platforms.
|
* To work around these rather strange behaviors this test uses -Xmx2m but then
|
||||||
|
* calculates what the expected heap size should be. The calculation is a
|
||||||
|
* simplified version of the code in the VM. We assume that the card table will
|
||||||
|
* use one page. Each byte in the card table corresponds to 512 bytes on the heap.
|
||||||
|
* So, the expected heap size is page_size * 512.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import sun.management.ManagementFactoryHelper;
|
import com.oracle.java.testlibrary.*;
|
||||||
import static com.oracle.java.testlibrary.Asserts.*;
|
import static com.oracle.java.testlibrary.Asserts.*;
|
||||||
|
import sun.hotspot.WhiteBox;
|
||||||
|
import sun.management.ManagementFactoryHelper;
|
||||||
|
|
||||||
public class TestSmallHeap {
|
public class TestSmallHeap {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
WhiteBox wb = WhiteBox.getWhiteBox();
|
||||||
|
int pageSize = wb.getVMPageSize();
|
||||||
|
int heapBytesPerCard = 512;
|
||||||
|
long expectedMaxHeap = pageSize * heapBytesPerCard;
|
||||||
String maxHeap = ManagementFactoryHelper.getDiagnosticMXBean().getVMOption("MaxHeapSize").getValue();
|
String maxHeap = ManagementFactoryHelper.getDiagnosticMXBean().getVMOption("MaxHeapSize").getValue();
|
||||||
String expectedMaxHeap = "4194304";
|
assertEQ(Long.parseLong(maxHeap), expectedMaxHeap);
|
||||||
assertEQ(maxHeap, expectedMaxHeap);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ class TestMaxHeapSizeTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void checkInvalidMinInitialHeapCombinations(String gcflag) throws Exception {
|
private static void checkInvalidMinInitialHeapCombinations(String gcflag) throws Exception {
|
||||||
expectError(new String[] { gcflag, "-Xms8M", "-XX:InitialHeapSize=4M", "-version" });
|
expectError(new String[] { gcflag, "-Xms64M", "-XX:InitialHeapSize=32M", "-version" });
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkValidMinInitialHeapCombinations(String gcflag) throws Exception {
|
private static void checkValidMinInitialHeapCombinations(String gcflag) throws Exception {
|
||||||
|
@ -107,8 +107,8 @@ public class TestGCLogMessages {
|
|||||||
|
|
||||||
private static void testWithToSpaceExhaustionLogs() throws Exception {
|
private static void testWithToSpaceExhaustionLogs() throws Exception {
|
||||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
|
||||||
"-Xmx10M",
|
"-Xmx32M",
|
||||||
"-Xmn5M",
|
"-Xmn16M",
|
||||||
"-XX:+PrintGCDetails",
|
"-XX:+PrintGCDetails",
|
||||||
GCTestWithToSpaceExhaustion.class.getName());
|
GCTestWithToSpaceExhaustion.class.getName());
|
||||||
|
|
||||||
@ -120,8 +120,8 @@ public class TestGCLogMessages {
|
|||||||
output.shouldHaveExitValue(0);
|
output.shouldHaveExitValue(0);
|
||||||
|
|
||||||
pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
|
pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
|
||||||
"-Xmx10M",
|
"-Xmx32M",
|
||||||
"-Xmn5M",
|
"-Xmn16M",
|
||||||
"-XX:+PrintGCDetails",
|
"-XX:+PrintGCDetails",
|
||||||
"-XX:+UnlockExperimentalVMOptions",
|
"-XX:+UnlockExperimentalVMOptions",
|
||||||
"-XX:G1LogLevel=finest",
|
"-XX:G1LogLevel=finest",
|
||||||
@ -151,7 +151,7 @@ public class TestGCLogMessages {
|
|||||||
private static byte[] garbage;
|
private static byte[] garbage;
|
||||||
private static byte[] largeObject;
|
private static byte[] largeObject;
|
||||||
public static void main(String [] args) {
|
public static void main(String [] args) {
|
||||||
largeObject = new byte[5*1024*1024];
|
largeObject = new byte[16*1024*1024];
|
||||||
System.out.println("Creating garbage");
|
System.out.println("Creating garbage");
|
||||||
// create 128MB of garbage. This should result in at least one GC,
|
// create 128MB of garbage. This should result in at least one GC,
|
||||||
// some of them with to-space exhaustion.
|
// some of them with to-space exhaustion.
|
||||||
|
@ -31,7 +31,9 @@
|
|||||||
import com.oracle.java.testlibrary.*;
|
import com.oracle.java.testlibrary.*;
|
||||||
|
|
||||||
public class TestHumongousAllocInitialMark {
|
public class TestHumongousAllocInitialMark {
|
||||||
private static final int heapSize = 200; // MB
|
// Heap sizes < 224 MB are increased to 224 MB if vm_page_size == 64K to
|
||||||
|
// fulfill alignment constraints.
|
||||||
|
private static final int heapSize = 224; // MB
|
||||||
private static final int heapRegionSize = 1; // MB
|
private static final int heapRegionSize = 1; // MB
|
||||||
private static final int initiatingHeapOccupancyPercent = 50; // %
|
private static final int initiatingHeapOccupancyPercent = 50; // %
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -71,11 +71,12 @@ bad_data_ptr_re='(SIGILL|SIGSEGV|EXCEPTION_ACCESS_VIOLATION).* at pc='
|
|||||||
# EXCEPTION_ACCESS_VIOLATION - Win-*
|
# EXCEPTION_ACCESS_VIOLATION - Win-*
|
||||||
# SIGBUS - Solaris SPARC-64
|
# SIGBUS - Solaris SPARC-64
|
||||||
# SIGSEGV - Linux-*, Solaris SPARC-32, Solaris X86-*
|
# SIGSEGV - Linux-*, Solaris SPARC-32, Solaris X86-*
|
||||||
|
# SIGILL - Aix
|
||||||
#
|
#
|
||||||
# Note: would like to use "pc=0x00*0f," in the pattern, but Solaris SPARC-*
|
# Note: would like to use "pc=0x00*0f," in the pattern, but Solaris SPARC-*
|
||||||
# gets its signal at a PC in test_error_handler().
|
# gets its signal at a PC in test_error_handler().
|
||||||
#
|
#
|
||||||
bad_func_ptr_re='(SIGBUS|SIGSEGV|EXCEPTION_ACCESS_VIOLATION).* at pc='
|
bad_func_ptr_re='(SIGBUS|SIGSEGV|SIGILL|EXCEPTION_ACCESS_VIOLATION).* at pc='
|
||||||
guarantee_re='guarantee[(](str|num).*failed: *'
|
guarantee_re='guarantee[(](str|num).*failed: *'
|
||||||
fatal_re='fatal error: *'
|
fatal_re='fatal error: *'
|
||||||
tail_1='.*expected null'
|
tail_1='.*expected null'
|
||||||
|
@ -43,7 +43,7 @@ public class CompilerConfigFileWarning {
|
|||||||
|
|
||||||
pb = ProcessTools.createJavaProcessBuilder("-XX:CompileCommandFile=hs_comp.txt", "-version");
|
pb = ProcessTools.createJavaProcessBuilder("-XX:CompileCommandFile=hs_comp.txt", "-version");
|
||||||
output = new OutputAnalyzer(pb.start());
|
output = new OutputAnalyzer(pb.start());
|
||||||
output.shouldContain("CompilerOracle: unrecognized line");
|
output.shouldContain("CompileCommand: unrecognized command");
|
||||||
output.shouldContain("aaa aaa");
|
output.shouldContain("aaa aaa");
|
||||||
|
|
||||||
// Skip on debug builds since we'll always read the file there
|
// Skip on debug builds since we'll always read the file there
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
* @summary Test that you can decrease NMT tracking level but not increase it.
|
* @summary Test that you can decrease NMT tracking level but not increase it.
|
||||||
* @key nmt
|
* @key nmt
|
||||||
* @library /testlibrary /../../test/lib
|
* @library /testlibrary /../../test/lib
|
||||||
|
* @ignore 8067167
|
||||||
* @build ChangeTrackingLevel
|
* @build ChangeTrackingLevel
|
||||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
* @bug 8005936 8058606
|
* @bug 8005936 8058606
|
||||||
* @summary Verify PrintNMTStatistics on normal JVM exit for detail and summary tracking level
|
* @summary Verify PrintNMTStatistics on normal JVM exit for detail and summary tracking level
|
||||||
* @library /testlibrary
|
* @library /testlibrary
|
||||||
|
* @ignore 8067167
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import com.oracle.java.testlibrary.*;
|
import com.oracle.java.testlibrary.*;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user