This commit is contained in:
Lana Steuck 2015-07-23 15:28:52 -07:00
commit 0b717619ae
84 changed files with 3089 additions and 563 deletions

View File

@ -10,3 +10,4 @@
.igv.log
^.hgtip
.DS_Store
\.class$

View File

@ -34,7 +34,6 @@
define_pd_global(bool, ConvertSleepToYield, true);
define_pd_global(bool, ShareVtableStubs, true);
define_pd_global(bool, CountInterpCalls, true);
define_pd_global(bool, NeedsDeoptSuspend, false); // only register window machines need this
define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks
@ -61,8 +60,6 @@ define_pd_global(intx, StackRedPages, 1);
define_pd_global(intx, StackShadowPages, 4 DEBUG_ONLY(+5));
define_pd_global(intx, PreInflateSpin, 10);
define_pd_global(bool, RewriteBytecodes, true);
define_pd_global(bool, RewriteFrequentPairs, true);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -869,7 +869,7 @@ void InterpreterGenerator::bang_stack_shadow_pages(bool native_call) {
// native method than the typical interpreter frame setup.
address InterpreterGenerator::generate_native_entry(bool synchronized) {
// determine code generation flags
bool inc_counter = UseCompiler || CountCompiledCalls;
bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
// r1: Method*
// rscratch1: sender sp
@ -1307,7 +1307,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
//
address InterpreterGenerator::generate_normal_entry(bool synchronized) {
// determine code generation flags
bool inc_counter = UseCompiler || CountCompiledCalls;
bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
// rscratch1: sender sp
address entry_point = __ pc();

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012, 2014 SAP AG. All rights reserved.
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012, 2015 SAP AG. 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
@ -225,7 +225,7 @@ inline BasicObjectLock* frame::interpreter_frame_monitor_begin() const {
return (BasicObjectLock *) get_ijava_state();
}
// SAPJVM ASc 2012-11-21. Return register stack slot addr at which currently interpreted method is found
// Return register stack slot addr at which currently interpreted method is found.
inline Method** frame::interpreter_frame_method_addr() const {
return (Method**) &(get_ijava_state()->method);
}

View File

@ -47,8 +47,6 @@ define_pd_global(intx, OptoLoopAlignment, 16);
define_pd_global(intx, InlineFrequencyCount, 100);
define_pd_global(intx, InlineSmallCode, 1500);
define_pd_global(intx, PreInflateSpin, 10);
// Flags for template interpreter.
define_pd_global(bool, RewriteBytecodes, true);
define_pd_global(bool, RewriteFrequentPairs, true);

View File

@ -3433,6 +3433,376 @@ void MacroAssembler::char_arrays_equalsImm(Register str1_reg, Register str2_reg,
bind(Ldone_false);
}
// dest_lo += src1 + src2
// dest_hi += carry1 + carry2
void MacroAssembler::add2_with_carry(Register dest_hi,
Register dest_lo,
Register src1, Register src2) {
li(R0, 0);
addc(dest_lo, dest_lo, src1);
adde(dest_hi, dest_hi, R0);
addc(dest_lo, dest_lo, src2);
adde(dest_hi, dest_hi, R0);
}
// Multiply 64 bit by 64 bit first loop.
void MacroAssembler::multiply_64_x_64_loop(Register x, Register xstart,
Register x_xstart,
Register y, Register y_idx,
Register z,
Register carry,
Register product_high, Register product,
Register idx, Register kdx,
Register tmp) {
// jlong carry, x[], y[], z[];
// for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx--, kdx--) {
// huge_128 product = y[idx] * x[xstart] + carry;
// z[kdx] = (jlong)product;
// carry = (jlong)(product >>> 64);
// }
// z[xstart] = carry;
Label L_first_loop, L_first_loop_exit;
Label L_one_x, L_one_y, L_multiply;
addic_(xstart, xstart, -1);
blt(CCR0, L_one_x); // Special case: length of x is 1.
// Load next two integers of x.
sldi(tmp, xstart, LogBytesPerInt);
ldx(x_xstart, x, tmp);
#ifdef VM_LITTLE_ENDIAN
rldicl(x_xstart, x_xstart, 32, 0);
#endif
align(32, 16);
bind(L_first_loop);
cmpdi(CCR0, idx, 1);
blt(CCR0, L_first_loop_exit);
addi(idx, idx, -2);
beq(CCR0, L_one_y);
// Load next two integers of y.
sldi(tmp, idx, LogBytesPerInt);
ldx(y_idx, y, tmp);
#ifdef VM_LITTLE_ENDIAN
rldicl(y_idx, y_idx, 32, 0);
#endif
bind(L_multiply);
multiply64(product_high, product, x_xstart, y_idx);
li(tmp, 0);
addc(product, product, carry); // Add carry to result.
adde(product_high, product_high, tmp); // Add carry of the last addition.
addi(kdx, kdx, -2);
// Store result.
#ifdef VM_LITTLE_ENDIAN
rldicl(product, product, 32, 0);
#endif
sldi(tmp, kdx, LogBytesPerInt);
stdx(product, z, tmp);
mr_if_needed(carry, product_high);
b(L_first_loop);
bind(L_one_y); // Load one 32 bit portion of y as (0,value).
lwz(y_idx, 0, y);
b(L_multiply);
bind( L_one_x ); // Load one 32 bit portion of x as (0,value).
lwz(x_xstart, 0, x);
b(L_first_loop);
bind(L_first_loop_exit);
}
// Multiply 64 bit by 64 bit and add 128 bit.
void MacroAssembler::multiply_add_128_x_128(Register x_xstart, Register y,
Register z, Register yz_idx,
Register idx, Register carry,
Register product_high, Register product,
Register tmp, int offset) {
// huge_128 product = (y[idx] * x_xstart) + z[kdx] + carry;
// z[kdx] = (jlong)product;
sldi(tmp, idx, LogBytesPerInt);
if ( offset ) {
addi(tmp, tmp, offset);
}
ldx(yz_idx, y, tmp);
#ifdef VM_LITTLE_ENDIAN
rldicl(yz_idx, yz_idx, 32, 0);
#endif
multiply64(product_high, product, x_xstart, yz_idx);
ldx(yz_idx, z, tmp);
#ifdef VM_LITTLE_ENDIAN
rldicl(yz_idx, yz_idx, 32, 0);
#endif
add2_with_carry(product_high, product, carry, yz_idx);
sldi(tmp, idx, LogBytesPerInt);
if ( offset ) {
addi(tmp, tmp, offset);
}
#ifdef VM_LITTLE_ENDIAN
rldicl(product, product, 32, 0);
#endif
stdx(product, z, tmp);
}
// Multiply 128 bit by 128 bit. Unrolled inner loop.
void MacroAssembler::multiply_128_x_128_loop(Register x_xstart,
Register y, Register z,
Register yz_idx, Register idx, Register carry,
Register product_high, Register product,
Register carry2, Register tmp) {
// jlong carry, x[], y[], z[];
// int kdx = ystart+1;
// for (int idx=ystart-2; idx >= 0; idx -= 2) { // Third loop
// huge_128 product = (y[idx+1] * x_xstart) + z[kdx+idx+1] + carry;
// z[kdx+idx+1] = (jlong)product;
// jlong carry2 = (jlong)(product >>> 64);
// product = (y[idx] * x_xstart) + z[kdx+idx] + carry2;
// z[kdx+idx] = (jlong)product;
// carry = (jlong)(product >>> 64);
// }
// idx += 2;
// if (idx > 0) {
// product = (y[idx] * x_xstart) + z[kdx+idx] + carry;
// z[kdx+idx] = (jlong)product;
// carry = (jlong)(product >>> 64);
// }
Label L_third_loop, L_third_loop_exit, L_post_third_loop_done;
const Register jdx = R0;
// Scale the index.
srdi_(jdx, idx, 2);
beq(CCR0, L_third_loop_exit);
mtctr(jdx);
align(32, 16);
bind(L_third_loop);
addi(idx, idx, -4);
multiply_add_128_x_128(x_xstart, y, z, yz_idx, idx, carry, product_high, product, tmp, 8);
mr_if_needed(carry2, product_high);
multiply_add_128_x_128(x_xstart, y, z, yz_idx, idx, carry2, product_high, product, tmp, 0);
mr_if_needed(carry, product_high);
bdnz(L_third_loop);
bind(L_third_loop_exit); // Handle any left-over operand parts.
andi_(idx, idx, 0x3);
beq(CCR0, L_post_third_loop_done);
Label L_check_1;
addic_(idx, idx, -2);
blt(CCR0, L_check_1);
multiply_add_128_x_128(x_xstart, y, z, yz_idx, idx, carry, product_high, product, tmp, 0);
mr_if_needed(carry, product_high);
bind(L_check_1);
addi(idx, idx, 0x2);
andi_(idx, idx, 0x1) ;
addic_(idx, idx, -1);
blt(CCR0, L_post_third_loop_done);
sldi(tmp, idx, LogBytesPerInt);
lwzx(yz_idx, y, tmp);
multiply64(product_high, product, x_xstart, yz_idx);
lwzx(yz_idx, z, tmp);
add2_with_carry(product_high, product, yz_idx, carry);
sldi(tmp, idx, LogBytesPerInt);
stwx(product, z, tmp);
srdi(product, product, 32);
sldi(product_high, product_high, 32);
orr(product, product, product_high);
mr_if_needed(carry, product);
bind(L_post_third_loop_done);
} // multiply_128_x_128_loop
void MacroAssembler::multiply_to_len(Register x, Register xlen,
Register y, Register ylen,
Register z, Register zlen,
Register tmp1, Register tmp2,
Register tmp3, Register tmp4,
Register tmp5, Register tmp6,
Register tmp7, Register tmp8,
Register tmp9, Register tmp10,
Register tmp11, Register tmp12,
Register tmp13) {
ShortBranchVerifier sbv(this);
assert_different_registers(x, xlen, y, ylen, z, zlen,
tmp1, tmp2, tmp3, tmp4, tmp5, tmp6);
assert_different_registers(x, xlen, y, ylen, z, zlen,
tmp1, tmp2, tmp3, tmp4, tmp5, tmp7);
assert_different_registers(x, xlen, y, ylen, z, zlen,
tmp1, tmp2, tmp3, tmp4, tmp5, tmp8);
const Register idx = tmp1;
const Register kdx = tmp2;
const Register xstart = tmp3;
const Register y_idx = tmp4;
const Register carry = tmp5;
const Register product = tmp6;
const Register product_high = tmp7;
const Register x_xstart = tmp8;
const Register tmp = tmp9;
// First Loop.
//
// final static long LONG_MASK = 0xffffffffL;
// int xstart = xlen - 1;
// int ystart = ylen - 1;
// long carry = 0;
// for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx-, kdx--) {
// long product = (y[idx] & LONG_MASK) * (x[xstart] & LONG_MASK) + carry;
// z[kdx] = (int)product;
// carry = product >>> 32;
// }
// z[xstart] = (int)carry;
mr_if_needed(idx, ylen); // idx = ylen
mr_if_needed(kdx, zlen); // kdx = xlen + ylen
li(carry, 0); // carry = 0
Label L_done;
addic_(xstart, xlen, -1);
blt(CCR0, L_done);
multiply_64_x_64_loop(x, xstart, x_xstart, y, y_idx, z,
carry, product_high, product, idx, kdx, tmp);
Label L_second_loop;
cmpdi(CCR0, kdx, 0);
beq(CCR0, L_second_loop);
Label L_carry;
addic_(kdx, kdx, -1);
beq(CCR0, L_carry);
// Store lower 32 bits of carry.
sldi(tmp, kdx, LogBytesPerInt);
stwx(carry, z, tmp);
srdi(carry, carry, 32);
addi(kdx, kdx, -1);
bind(L_carry);
// Store upper 32 bits of carry.
sldi(tmp, kdx, LogBytesPerInt);
stwx(carry, z, tmp);
// Second and third (nested) loops.
//
// for (int i = xstart-1; i >= 0; i--) { // Second loop
// carry = 0;
// for (int jdx=ystart, k=ystart+1+i; jdx >= 0; jdx--, k--) { // Third loop
// long product = (y[jdx] & LONG_MASK) * (x[i] & LONG_MASK) +
// (z[k] & LONG_MASK) + carry;
// z[k] = (int)product;
// carry = product >>> 32;
// }
// z[i] = (int)carry;
// }
//
// i = xlen, j = tmp1, k = tmp2, carry = tmp5, x[i] = rdx
bind(L_second_loop);
li(carry, 0); // carry = 0;
addic_(xstart, xstart, -1); // i = xstart-1;
blt(CCR0, L_done);
Register zsave = tmp10;
mr(zsave, z);
Label L_last_x;
sldi(tmp, xstart, LogBytesPerInt);
add(z, z, tmp); // z = z + k - j
addi(z, z, 4);
addic_(xstart, xstart, -1); // i = xstart-1;
blt(CCR0, L_last_x);
sldi(tmp, xstart, LogBytesPerInt);
ldx(x_xstart, x, tmp);
#ifdef VM_LITTLE_ENDIAN
rldicl(x_xstart, x_xstart, 32, 0);
#endif
Label L_third_loop_prologue;
bind(L_third_loop_prologue);
Register xsave = tmp11;
Register xlensave = tmp12;
Register ylensave = tmp13;
mr(xsave, x);
mr(xlensave, xstart);
mr(ylensave, ylen);
multiply_128_x_128_loop(x_xstart, y, z, y_idx, ylen,
carry, product_high, product, x, tmp);
mr(z, zsave);
mr(x, xsave);
mr(xlen, xlensave); // This is the decrement of the loop counter!
mr(ylen, ylensave);
addi(tmp3, xlen, 1);
sldi(tmp, tmp3, LogBytesPerInt);
stwx(carry, z, tmp);
addic_(tmp3, tmp3, -1);
blt(CCR0, L_done);
srdi(carry, carry, 32);
sldi(tmp, tmp3, LogBytesPerInt);
stwx(carry, z, tmp);
b(L_second_loop);
// Next infrequent code is moved outside loops.
bind(L_last_x);
lwz(x_xstart, 0, x);
b(L_third_loop_prologue);
bind(L_done);
} // multiply_to_len
void MacroAssembler::asm_assert(bool check_equal, const char *msg, int id) {
#ifdef ASSERT

View File

@ -677,6 +677,31 @@ class MacroAssembler: public Assembler {
void char_arrays_equalsImm(Register str1_reg, Register str2_reg, int cntval, Register result_reg,
Register tmp1_reg, Register tmp2_reg);
// Emitters for BigInteger.multiplyToLen intrinsic.
inline void multiply64(Register dest_hi, Register dest_lo,
Register x, Register y);
void add2_with_carry(Register dest_hi, Register dest_lo,
Register src1, Register src2);
void multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart,
Register y, Register y_idx, Register z,
Register carry, Register product_high, Register product,
Register idx, Register kdx, Register tmp);
void multiply_add_128_x_128(Register x_xstart, Register y, Register z,
Register yz_idx, Register idx, Register carry,
Register product_high, Register product, Register tmp,
int offset);
void multiply_128_x_128_loop(Register x_xstart,
Register y, Register z,
Register yz_idx, Register idx, Register carry,
Register product_high, Register product,
Register carry2, Register tmp);
void multiply_to_len(Register x, Register xlen,
Register y, Register ylen,
Register z, Register zlen,
Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5,
Register tmp6, Register tmp7, Register tmp8, Register tmp9, Register tmp10,
Register tmp11, Register tmp12, Register tmp13);
//
// Debugging
//

View File

@ -423,6 +423,13 @@ inline void MacroAssembler::trap_range_check_ge(Register a, int si16) {
twi(traptoEqual | traptoGreaterThanUnsigned, a/*reg a*/, si16);
}
// unsigned integer multiplication 64*64 -> 128 bits
inline void MacroAssembler::multiply64(Register dest_hi, Register dest_lo,
Register x, Register y) {
mulld(dest_lo, x, y);
mulhdu(dest_hi, x, y);
}
#if defined(ABI_ELFv2)
inline address MacroAssembler::function_entry() { return pc(); }
#else

View File

@ -10930,7 +10930,7 @@ instruct partialSubtypeCheck(iRegPdst result, iRegP_N2P subklass, iRegP_N2P supe
instruct cmpFastLock(flagsReg crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3) %{
match(Set crx (FastLock oop box));
effect(TEMP tmp1, TEMP tmp2, TEMP tmp3);
predicate(/*(!UseNewFastLockPPC64 || UseBiasedLocking) &&*/ !Compile::current()->use_rtm());
predicate(!Compile::current()->use_rtm());
format %{ "FASTLOCK $oop, $box, $tmp1, $tmp2, $tmp3" %}
ins_encode %{

View File

@ -2053,6 +2053,79 @@ class StubGenerator: public StubCodeGenerator {
__ blr();
}
// Stub for BigInteger::multiplyToLen()
//
// Arguments:
//
// Input:
// R3 - x address
// R4 - x length
// R5 - y address
// R6 - y length
// R7 - z address
// R8 - z length
//
address generate_multiplyToLen() {
StubCodeMark mark(this, "StubRoutines", "multiplyToLen");
address start = __ function_entry();
const Register x = R3;
const Register xlen = R4;
const Register y = R5;
const Register ylen = R6;
const Register z = R7;
const Register zlen = R8;
const Register tmp1 = R2; // TOC not used.
const Register tmp2 = R9;
const Register tmp3 = R10;
const Register tmp4 = R11;
const Register tmp5 = R12;
// non-volatile regs
const Register tmp6 = R31;
const Register tmp7 = R30;
const Register tmp8 = R29;
const Register tmp9 = R28;
const Register tmp10 = R27;
const Register tmp11 = R26;
const Register tmp12 = R25;
const Register tmp13 = R24;
BLOCK_COMMENT("Entry:");
// Save non-volatile regs (frameless).
int current_offs = 8;
__ std(R24, -current_offs, R1_SP); current_offs += 8;
__ std(R25, -current_offs, R1_SP); current_offs += 8;
__ std(R26, -current_offs, R1_SP); current_offs += 8;
__ std(R27, -current_offs, R1_SP); current_offs += 8;
__ std(R28, -current_offs, R1_SP); current_offs += 8;
__ std(R29, -current_offs, R1_SP); current_offs += 8;
__ std(R30, -current_offs, R1_SP); current_offs += 8;
__ std(R31, -current_offs, R1_SP);
__ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5,
tmp6, tmp7, tmp8, tmp9, tmp10, tmp11, tmp12, tmp13);
// Restore non-volatile regs.
current_offs = 8;
__ ld(R24, -current_offs, R1_SP); current_offs += 8;
__ ld(R25, -current_offs, R1_SP); current_offs += 8;
__ ld(R26, -current_offs, R1_SP); current_offs += 8;
__ ld(R27, -current_offs, R1_SP); current_offs += 8;
__ ld(R28, -current_offs, R1_SP); current_offs += 8;
__ ld(R29, -current_offs, R1_SP); current_offs += 8;
__ ld(R30, -current_offs, R1_SP); current_offs += 8;
__ ld(R31, -current_offs, R1_SP);
__ blr(); // Return to caller.
return start;
}
// Initialization
void generate_initial() {
// Generates all stubs and initializes the entry points
@ -2102,6 +2175,12 @@ class StubGenerator: public StubCodeGenerator {
generate_safefetch("SafeFetchN", sizeof(intptr_t), &StubRoutines::_safefetchN_entry,
&StubRoutines::_safefetchN_fault_pc,
&StubRoutines::_safefetchN_continuation_pc);
#ifdef COMPILER2
if (UseMultiplyToLenIntrinsic) {
StubRoutines::_multiplyToLen = generate_multiplyToLen();
}
#endif
}
public:

View File

@ -668,7 +668,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
address entry = __ pc();
const bool inc_counter = UseCompiler || CountCompiledCalls;
const bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
// -----------------------------------------------------------------------------
// Allocate a new frame that represents the native callee (i2n frame).
@ -1118,7 +1118,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
// Generic interpreted method entry to (asm) interpreter.
//
address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) {
bool inc_counter = UseCompiler || CountCompiledCalls;
bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
address entry = __ pc();
// Generate the code to allocate the interpreter stack frame.
Register Rsize_of_parameters = R4_ARG2, // Written by generate_fixed_frame.

View File

@ -198,6 +198,10 @@ void VM_Version::initialize() {
FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
}
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
UseMultiplyToLenIntrinsic = true;
}
// Adjust RTM (Restricted Transactional Memory) flags.
if (!has_tcheck() && UseRTMLocking) {
// Can't continue because UseRTMLocking affects UseBiasedLocking flag
@ -228,7 +232,6 @@ void VM_Version::initialize() {
warning("RTMAbortRatio must be in the range 0 to 100, resetting it to 50");
FLAG_SET_DEFAULT(RTMAbortRatio, 50);
}
FLAG_SET_ERGO(bool, UseNewFastLockPPC64, false); // Does not implement TM.
guarantee(RTMSpinLoopCount > 0, "unsupported");
#else
// Only C2 does RTM locking optimization.

View File

@ -39,7 +39,6 @@
define_pd_global(bool, DontYieldALot, true); // yield no more than 100 times per second
define_pd_global(bool, ConvertSleepToYield, false); // do not convert sleep(0) to yield. Helps GUI
define_pd_global(bool, ShareVtableStubs, false); // improves performance markedly for mtrt and compress
define_pd_global(bool, CountInterpCalls, false); // not implemented in the interpreter
define_pd_global(bool, NeedsDeoptSuspend, true); // register window machines need this
define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks
@ -67,8 +66,6 @@ define_pd_global(intx, StackShadowPages, 3 DEBUG_ONLY(+1));
define_pd_global(intx, StackYellowPages, 2);
define_pd_global(intx, StackRedPages, 1);
define_pd_global(intx, PreInflateSpin, 40); // Determined by running design center
define_pd_global(bool, RewriteBytecodes, true);
define_pd_global(bool, RewriteFrequentPairs, true);

View File

@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@ -801,7 +801,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// the following temporary registers are used during frame creation
const Register Gtmp1 = G3_scratch ;
const Register Gtmp2 = G1_scratch;
bool inc_counter = UseCompiler || CountCompiledCalls;
bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
// make sure registers are different!
assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2);
@ -1225,7 +1225,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
address InterpreterGenerator::generate_normal_entry(bool synchronized) {
address entry = __ pc();
bool inc_counter = UseCompiler || CountCompiledCalls;
bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
// the following temporary registers are used during frame creation
const Register Gtmp1 = G3_scratch ;

View File

@ -308,7 +308,7 @@ void VM_Version::initialize() {
}
} else if (UseGHASHIntrinsics) {
if (!FLAG_IS_DEFAULT(UseGHASHIntrinsics))
warning("GHASH intrinsics require VIS3 insructions support. Intriniscs will be disabled");
warning("GHASH intrinsics require VIS3 instruction support. Intrinsics will be disabled");
FLAG_SET_DEFAULT(UseGHASHIntrinsics, false);
}

View File

@ -33,7 +33,6 @@
define_pd_global(bool, ConvertSleepToYield, true);
define_pd_global(bool, ShareVtableStubs, true);
define_pd_global(bool, CountInterpCalls, true);
define_pd_global(bool, NeedsDeoptSuspend, false); // only register window machines need this
define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks
@ -66,8 +65,6 @@ define_pd_global(intx, StackShadowPages, NOT_WIN64(20) WIN64_ONLY(6) DEBUG_ONLY(
define_pd_global(intx, StackShadowPages, 4 DEBUG_ONLY(+5));
#endif // AMD64
define_pd_global(intx, PreInflateSpin, 10);
define_pd_global(bool, RewriteBytecodes, true);
define_pd_global(bool, RewriteFrequentPairs, true);

View File

@ -1781,6 +1781,7 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg
cmpxchgptr(scrReg, Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
} else
if ((EmitSync & 128) == 0) { // avoid ST-before-CAS
// register juggle because we need tmpReg for cmpxchgptr below
movptr(scrReg, boxReg);
movptr(boxReg, tmpReg); // consider: LEA box, [tmp-2]
@ -1814,7 +1815,10 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg
}
cmpxchgptr(scrReg, Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
movptr(Address(scrReg, 0), 3); // box->_displaced_header = 3
// If we weren't able to swing _owner from NULL to the BasicLock
// then take the slow path.
jccb (Assembler::notZero, DONE_LABEL);
// update _owner from BasicLock to thread
get_thread (scrReg); // beware: clobbers ICCs
movptr(Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), scrReg);
xorptr(boxReg, boxReg); // set icc.ZFlag = 1 to indicate success
@ -2083,6 +2087,9 @@ void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpR
xorptr(boxReg, boxReg); // box is really EAX
if (os::is_MP()) { lock(); }
cmpxchgptr(rsp, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
// There's no successor so we tried to regrab the lock with the
// placeholder value. If that didn't work, then another thread
// grabbed the lock so we're done (and exit was a success).
jccb (Assembler::notEqual, LSuccess);
// Since we're low on registers we installed rsp as a placeholding in _owner.
// Now install Self over rsp. This is safe as we're transitioning from
@ -2190,6 +2197,9 @@ void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpR
movptr(boxReg, (int32_t)NULL_WORD);
if (os::is_MP()) { lock(); }
cmpxchgptr(r15_thread, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
// There's no successor so we tried to regrab the lock.
// If that didn't work, then another thread grabbed the
// lock so we're done (and exit was a success).
jccb (Assembler::notEqual, LSuccess);
// Intentional fall-through into slow-path

View File

@ -2456,7 +2456,8 @@ void SharedRuntime::generate_deopt_blob() {
// allocate space for the code
ResourceMark rm;
// setup code generation tools
CodeBuffer buffer("deopt_blob", 1024, 1024);
// note: the buffer code size must account for StackShadowPages=50
CodeBuffer buffer("deopt_blob", 1536, 1024);
MacroAssembler* masm = new MacroAssembler(&buffer);
int frame_size_in_words;
OopMap* map = NULL;

View File

@ -2780,6 +2780,7 @@ class StubGenerator: public StubCodeGenerator {
const XMMRegister xmm_temp7 = xmm7;
__ enter();
handleSOERegisters(true); // Save registers
__ movptr(state, state_param);
__ movptr(subkeyH, subkeyH_param);
@ -2883,6 +2884,7 @@ class StubGenerator: public StubCodeGenerator {
__ pshufb(xmm_temp6, ExternalAddress(StubRoutines::x86::ghash_long_swap_mask_addr()));
__ movdqu(Address(state, 0), xmm_temp6); // store the result
handleSOERegisters(false); // restore registers
__ leave();
__ ret(0);
return start;

View File

@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@ -849,7 +849,7 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret
address InterpreterGenerator::generate_native_entry(bool synchronized) {
// determine code generation flags
bool inc_counter = UseCompiler || CountCompiledCalls;
bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
// rbx,: Method*
// rsi: sender sp
@ -1265,7 +1265,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
//
address InterpreterGenerator::generate_normal_entry(bool synchronized) {
// determine code generation flags
bool inc_counter = UseCompiler || CountCompiledCalls;
bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
// rbx,: Method*
// rsi: sender sp

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2015, 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
@ -809,7 +809,7 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret
// native method than the typical interpreter frame setup.
address InterpreterGenerator::generate_native_entry(bool synchronized) {
// determine code generation flags
bool inc_counter = UseCompiler || CountCompiledCalls;
bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
// rbx: Method*
// r13: sender sp
@ -1256,7 +1256,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
//
address InterpreterGenerator::generate_normal_entry(bool synchronized) {
// determine code generation flags
bool inc_counter = UseCompiler || CountCompiledCalls;
bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
// ebx: Method*
// r13: sender sp

View File

@ -34,7 +34,6 @@
define_pd_global(bool, ConvertSleepToYield, true);
define_pd_global(bool, ShareVtableStubs, true);
define_pd_global(bool, CountInterpCalls, true);
define_pd_global(bool, NeedsDeoptSuspend, false);
define_pd_global(bool, ImplicitNullChecks, true);
@ -45,7 +44,6 @@ define_pd_global(intx, CodeEntryAlignment, 32);
define_pd_global(intx, OptoLoopAlignment, 16);
define_pd_global(intx, InlineFrequencyCount, 100);
define_pd_global(intx, InlineSmallCode, 1000 );
define_pd_global(intx, PreInflateSpin, 10);
define_pd_global(intx, StackYellowPages, 2);
define_pd_global(intx, StackRedPages, 1);

View File

@ -3740,15 +3740,6 @@ void os::win32::initialize_system_info() {
"stack size not a multiple of page size");
initialize_performance_counter();
// Win95/Win98 scheduler bug work-around. The Win95/98 scheduler is
// known to deadlock the system, if the VM issues to thread operations with
// a too high frequency, e.g., such as changing the priorities.
// The 6000 seems to work well - no deadlocks has been notices on the test
// programs that we have seen experience this problem.
if (!os::win32::is_nt()) {
StarvationMonitorInterval = 6000;
}
}

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2009, 2015, 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
@ -62,7 +62,7 @@ all: logc.jar
logc.jar: filelist manifest.mf
@mkdir -p $(OUTPUT_DIR)
$(JAVAC) -source 1.5 -deprecation -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) @filelist
$(JAVAC) -deprecation -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) @filelist
$(JAR) cvfm logc.jar manifest.mf -C $(OUTPUT_DIR) com
.PHONY: filelist

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2015, 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
@ -27,14 +27,29 @@ package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
/**
*
* @author never
* Provide basic data structures and behaviour for {@link LogEvent}s.
*/
public abstract class BasicLogEvent implements LogEvent {
/**
* The event's ID. This is a number; we represent it as a string for
* convenience.
*/
protected final String id;
/**
* The event's start time.
*/
protected final double start;
/**
* The event's end time.
*/
protected double end;
/**
* The compilation during which this event was signalled.
*/
protected Compilation compilation;
BasicLogEvent(double start, String id) {
@ -43,33 +58,37 @@ public abstract class BasicLogEvent implements LogEvent {
this.id = id;
}
public double getStart() {
public final double getStart() {
return start;
}
public double getEnd() {
public final double getEnd() {
return end;
}
public void setEnd(double end) {
public final void setEnd(double end) {
this.end = end;
}
public double getElapsedTime() {
public final double getElapsedTime() {
return ((int) ((getEnd() - getStart()) * 1000)) / 1000.0;
}
public String getId() {
public final String getId() {
return id;
}
public Compilation getCompilation() {
public final Compilation getCompilation() {
return compilation;
}
/**
* Set the compilation for this event. This is not a {@code final} method
* as it is overridden in {@link UncommonTrapEvent}.
*/
public void setCompilation(Compilation compilation) {
this.compilation = compilation;
}
abstract public void print(PrintStream stream);
abstract public void print(PrintStream stream, boolean printID);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,41 +29,119 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
/**
* Representation of a compilation scope in a compilation log. This class is a
* hybrid: its instances can represent original scopes of methods being
* compiled, but are also used to represent call sites in given methods.
*/
public class CallSite {
/**
* The index of the call in the caller. This will be 0 if this instance
* represents a compilation root.
*/
private int bci;
/**
* The method that is called at this call site. This will be {@code null}
* if this instance represents a compilation root.
*/
private Method method;
/**
* The invocation count for this call site.
*/
private int count;
/**
* The receiver type of the call represented by this instance, if known.
*/
private String receiver;
/**
* In case the {@linkplain receiver receiver type} of the call represented
* by this instance is known, this is how often the type was encountered.
*/
private int receiver_count;
/**
* The reason for a success or failure of an inlining operation at this
* call site.
*/
private String reason;
/**
* A list of all calls in this compilation scope.
*/
private List<CallSite> calls;
/**
* Number of nodes in the graph at the end of parsing this compilation
* scope.
*/
private int endNodes;
/**
* Number of live nodes in the graph at the end of parsing this compilation
* scope.
*/
private int endLiveNodes;
/**
* Time in seconds since VM startup at which parsing this compilation scope
* ended.
*/
private double timeStamp;
/**
* The inline ID in case the call represented by this instance is inlined,
* 0 otherwise.
*/
private long inlineId;
CallSite() {
}
/**
* List of uncommon traps in this compilation scope.
*/
private List<UncommonTrap> traps;
/**
* Default constructor: used to create an instance that represents the top
* scope of a compilation.
*/
CallSite() {}
/**
* Constructor to create an instance that represents an actual method call.
*/
CallSite(int bci, Method m) {
this.bci = bci;
this.method = m;
}
/**
* Add a call site to the compilation scope represented by this instance.
*/
void add(CallSite site) {
if (getCalls() == null) {
setCalls(new ArrayList<CallSite>());
calls = new ArrayList<>();
}
getCalls().add(site);
}
/**
* Return the last of the {@linkplain #getCalls() call sites} in this
* compilation scope.
*/
CallSite last() {
return last(-1);
return getCalls().get(getCalls().size() - 1);
}
CallSite last(int fromEnd) {
return getCalls().get(getCalls().size() + fromEnd);
/**
* Return the last-but-one of the {@linkplain #getCalls() call sites} in
* this compilation scope.
*/
CallSite lastButOne() {
return getCalls().get(getCalls().size() - 2);
}
public String toString() {
@ -84,7 +162,7 @@ public class CallSite {
}
public void print(PrintStream stream) {
print(stream, 0);
print(stream, 0, true, false);
}
void emit(PrintStream stream, int indent) {
@ -92,21 +170,14 @@ public class CallSite {
stream.print(' ');
}
}
private static boolean compat = true;
public void print(PrintStream stream, int indent) {
public void print(PrintStream stream, int indent, boolean printInlining, boolean printUncommonTraps) {
emit(stream, indent);
String m = getMethod().getHolder() + "::" + getMethod().getName();
if (getReason() == null) {
stream.print(" @ " + getBci() + " " + m + " (" + getMethod().getBytes() + " bytes)");
} else {
if (isCompat()) {
stream.print(" @ " + getBci() + " " + m + " " + getReason());
} else {
stream.print("- @ " + getBci() + " " + m +
" (" + getMethod().getBytes() + " bytes) " + getReason());
}
stream.print(" @ " + getBci() + " " + m + " " + getReason());
}
stream.printf(" (end time: %6.4f", getTimeStamp());
if (getEndNodes() > 0) {
@ -116,13 +187,16 @@ public class CallSite {
if (getReceiver() != null) {
emit(stream, indent + 4);
// stream.println("type profile " + method.holder + " -> " + receiver + " (" +
// receiver_count + "/" + count + "," + (receiver_count * 100 / count) + "%)");
stream.println("type profile " + getMethod().getHolder() + " -> " + getReceiver() + " (" +
(getReceiverCount() * 100 / getCount()) + "%)");
}
if (getCalls() != null) {
if (printInlining && getCalls() != null) {
for (CallSite site : getCalls()) {
site.print(stream, indent + 2, printInlining, printUncommonTraps);
}
}
if (printUncommonTraps && getTraps() != null) {
for (UncommonTrap site : getTraps()) {
site.print(stream, indent + 2);
}
}
@ -180,16 +254,15 @@ public class CallSite {
return calls;
}
public void setCalls(List<CallSite> calls) {
this.calls = calls;
public List<UncommonTrap> getTraps() {
return traps;
}
public static boolean isCompat() {
return compat;
}
public static void setCompat(boolean aCompat) {
compat = aCompat;
void add(UncommonTrap e) {
if (traps == null) {
traps = new ArrayList<UncommonTrap>();
}
traps.add(e);
}
void setEndNodes(int n) {
@ -216,21 +289,30 @@ public class CallSite {
return timeStamp;
}
/**
* Check whether this call site matches another. Every late inline call
* site has a unique inline ID. If the call site we're looking for has one,
* then use it; otherwise rely on method name and byte code index.
*/
private boolean matches(CallSite other) {
// Every late inline call site has a unique inline id. If the
// call site we're looking for has one then use it other rely
// on method name and bci.
if (other.inlineId != 0) {
return inlineId == other.inlineId;
}
return method.equals(other.method) && bci == other.bci;
}
/**
* Locate a late inline call site: find, in this instance's
* {@linkplain #calls call sites}, the one furthest down the given call
* stack.
*
* Multiple chains of identical call sites with the same method name / bci
* combination are possible, so we have to try them all until we find the
* late inline call site that has a matching inline ID.
*
* @return a matching call site, or {@code null} if none was found.
*/
public CallSite findCallSite(ArrayDeque<CallSite> sites) {
// Locate a late inline call site. Multiple chains of
// identical call sites with the same method name/bci are
// possible so we have to try them all until we find the late
// inline call site that has a matching inline id.
if (calls == null) {
return null;
}
@ -253,6 +335,11 @@ public class CallSite {
return null;
}
/**
* Locate a late inline call site in the tree spanned by all this instance's
* {@linkplain #calls call sites}, and return the sequence of call sites
* (scopes) leading to that late inline call site.
*/
public ArrayDeque<CallSite> findCallSite2(CallSite site) {
if (calls == null) {
return null;
@ -260,7 +347,7 @@ public class CallSite {
for (CallSite c : calls) {
if (c.matches(site)) {
ArrayDeque<CallSite> stack = new ArrayDeque<CallSite>();
ArrayDeque<CallSite> stack = new ArrayDeque<>();
stack.push(c);
return stack;
} else {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2015, 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
@ -27,22 +27,94 @@ package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
import java.util.ArrayList;
/**
* One particular compilation, represented in the compilation log file as a
* {@code task} element.
*/
public class Compilation implements LogEvent {
/**
* The compilation ID.
*/
private int id;
/**
* Whether this is a compilation for on-stack replacement (OSR).
*/
private boolean osr;
/**
* The method being compiled.
*/
private Method method;
/**
* The {@linkplain CallSite scope} of this compilation. This is created as
* an empty {@link CallSite} instance, to be filled with data (and
* meaning) later on.
*/
private CallSite call = new CallSite();
/**
* In case a {@code late_inline} event occurs during the compilation, this
* field holds the information about it.
*/
private CallSite lateInlineCall = new CallSite();
private int osrBci;
/**
* The bytecode instruction index for on-stack replacement compilations; -1
* if this is not an OSR compilation.
*/
private int bci;
/**
* The method under compilation's invocation count.
*/
private String icount;
/**
* The method under compilation's backedge count.
*/
private String bcount;
/**
* Additional information for special compilations (e.g., adapters).
*/
private String special;
/**
* The name of the compiler performing this compilation.
*/
private String compiler;
/**
* Start time stamp.
*/
private double start;
/**
* End time stamp.
*/
private double end;
/**
* Trip count of the register allocator.
*/
private int attempts;
/**
* The compilation result (a native method).
*/
private NMethod nmethod;
private ArrayList<Phase> phases = new ArrayList<Phase>(4);
/**
* The phases through which this compilation goes.
*/
private ArrayList<Phase> phases = new ArrayList<>(4);
/**
* In case this compilation fails, the reason for that.
*/
private String failureReason;
Compilation(int id) {
@ -52,9 +124,17 @@ public class Compilation implements LogEvent {
void reset() {
call = new CallSite();
lateInlineCall = new CallSite();
phases = new ArrayList<Phase>(4);
phases = new ArrayList<>(4);
}
/**
* Get a compilation phase by name, or {@code null}.
*
* @param s the name of the phase to retrieve in this compilation.
*
* @return a compilation phase, or {@code null} if no phase with the given
* name is found.
*/
Phase getPhase(String s) {
for (Phase p : getPhases()) {
if (p.getName().equals(s)) {
@ -72,20 +152,32 @@ public class Compilation implements LogEvent {
return start;
}
public void setCompiler(String compiler) {
this.compiler = compiler;
}
public String getCompiler() {
return compiler;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getId());
sb.append(" ");
sb.append(getCompiler());
sb.append(" ");
sb.append(getMethod());
sb.append(" ");
sb.append(getIcount());
sb.append("+");
sb.append(getBcount());
sb.append("\n");
for (CallSite site : getCall().getCalls()) {
sb.append(site);
sb.append("\n");
if (getCall() != null && getCall().getCalls() != null) {
for (CallSite site : getCall().getCalls()) {
sb.append(site);
sb.append("\n");
}
}
if (getLateInlineCall().getCalls() != null) {
sb.append("late inline:\n");
@ -101,38 +193,50 @@ public class Compilation implements LogEvent {
if (getMethod() == null) {
stream.println(getSpecial());
} else {
int bc = isOsr() ? getOsr_bci() : -1;
stream.print(getId() + getMethod().decodeFlags(bc) + getMethod().format(bc));
int bc = isOsr() ? getBCI() : -1;
stream.print(getId() + getMethod().decodeFlags(bc) + " " + compiler + " " + getMethod().format(bc));
}
}
public void print(PrintStream stream) {
print(stream, 0, false);
public void print(PrintStream stream, boolean printID) {
print(stream, 0, printID, true, false);
}
public void print(PrintStream stream, boolean printInlining) {
print(stream, 0, printInlining);
public void print(PrintStream stream, boolean printID, boolean printInlining) {
print(stream, 0, printID, printInlining, false);
}
public void print(PrintStream stream, int indent, boolean printInlining) {
public void print(PrintStream stream, boolean printID, boolean printInlining, boolean printUncommonTraps) {
print(stream, 0, printID, printInlining, printUncommonTraps);
}
public void print(PrintStream stream, int indent, boolean printID, boolean printInlining, boolean printUncommonTraps) {
if (getMethod() == null) {
stream.println(getSpecial());
} else {
int bc = isOsr() ? getOsr_bci() : -1;
stream.print(getId() + getMethod().decodeFlags(bc) + getMethod().format(bc));
if (printID) {
stream.print(getId());
}
int bc = isOsr() ? getBCI() : -1;
stream.print(getMethod().decodeFlags(bc) + " " + compiler + " " + getMethod().format(bc));
stream.println();
if (getFailureReason() != null) {
stream.println("COMPILE FAILED " + getFailureReason());
stream.println("COMPILE SKIPPED: " + getFailureReason() + " (not retryable)");
}
if (printInlining && call.getCalls() != null) {
for (CallSite site : call.getCalls()) {
site.print(stream, indent + 2, printInlining, printUncommonTraps);
}
}
if (printUncommonTraps && call.getTraps() != null) {
for (UncommonTrap site : call.getTraps()) {
site.print(stream, indent + 2);
}
}
if (printInlining && lateInlineCall.getCalls() != null) {
stream.println("late inline:");
for (CallSite site : lateInlineCall.getCalls()) {
site.print(stream, indent + 2);
site.print(stream, indent + 2, printInlining, printUncommonTraps);
}
}
}
@ -154,12 +258,12 @@ public class Compilation implements LogEvent {
this.osr = osr;
}
public int getOsr_bci() {
return osrBci;
public int getBCI() {
return bci;
}
public void setOsr_bci(int osrBci) {
this.osrBci = osrBci;
public void setBCI(int osrBci) {
this.bci = osrBci;
}
public String getIcount() {
@ -230,9 +334,13 @@ public class Compilation implements LogEvent {
return method;
}
/**
* Set the method under compilation. If it is already set, ignore the
* argument to avoid changing the method by post-parse inlining info.
*
* @param method the method under compilation. May be ignored.
*/
public void setMethod(Method method) {
// Don't change method if it is already set to avoid changing
// it by post parse inlining info.
if (getMethod() == null) {
this.method = method;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2015, 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
@ -31,10 +31,9 @@ import java.util.regex.*;
* This class is a filter class to deal with malformed XML that used
* to be produced by the JVM when generating LogCompilation. In 1.6
* and later releases it shouldn't be required.
* @author never
*/
class LogCleanupReader extends Reader {
private Reader reader;
private char[] buffer = new char[4096];
@ -55,32 +54,38 @@ class LogCleanupReader extends Reader {
reader = r;
}
static final private Matcher pattern = Pattern.compile(".+ compile_id='[0-9]+'.*( compile_id='[0-9]+)").matcher("");
static final private Matcher pattern2 = Pattern.compile("' (C[12]) compile_id=").matcher("");
static final private Matcher pattern3 = Pattern.compile("'(destroy_vm)/").matcher("");
static final private Matcher duplicateCompileID = Pattern.compile(".+ compile_id='[0-9]+'.*( compile_id='[0-9]+)").matcher("");
static final private Matcher compilerName = Pattern.compile("' (C[12]) compile_id=").matcher("");
static final private Matcher destroyVM = Pattern.compile("'(destroy_vm)/").matcher("");
/**
* The log cleanup takes place in this method. If any of the three patterns
* ({@link #duplicateCompileID}, {@link #compilerName}, {@link #destroyVM})
* match, that indicates a problem in the log. The cleanup is performed by
* correcting the input line and writing it back into the {@link #line}
* buffer.
*/
private void fill() throws IOException {
rawFill();
if (length != -1) {
boolean changed = false;
String s = new String(line, 0, length);
String orig = s;
pattern2.reset(s);
if (pattern2.find()) {
s = s.substring(0, pattern2.start(1)) + s.substring(pattern2.end(1) + 1);
compilerName.reset(s);
if (compilerName.find()) {
s = s.substring(0, compilerName.start(1)) + s.substring(compilerName.end(1) + 1);
changed = true;
}
pattern.reset(s);
if (pattern.lookingAt()) {
s = s.substring(0, pattern.start(1)) + s.substring(pattern.end(1) + 1);
duplicateCompileID.reset(s);
if (duplicateCompileID.lookingAt()) {
s = s.substring(0, duplicateCompileID.start(1)) + s.substring(duplicateCompileID.end(1) + 1);
changed = true;
}
pattern3.reset(s);
if (pattern3.find()) {
s = s.substring(0, pattern3.start(1)) + s.substring(pattern3.end(1));
destroyVM.reset(s);
if (destroyVM.find()) {
s = s.substring(0, destroyVM.start(1)) + s.substring(destroyVM.end(1));
changed = true;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2015, 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
@ -22,60 +22,102 @@
*
*/
/**
* The main command line driver of a parser for LogCompilation output.
* @author never
*/
package com.sun.hotspot.tools.compiler;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
public class LogCompilation extends DefaultHandler implements ErrorHandler, Constants {
/**
* The LogCompilation tool parses log files generated by HotSpot using the
* {@code -XX:+LogCompilation} command line flag, and outputs the data
* collected therein in a nicely formatted way. There are various sorting
* options available, as well as options that select specific compilation
* events (such as inlining decisions) for inclusion in the output.
*
* The tool is also capable of fixing broken compilation logs as sometimes
* generated by Java 1.5 JVMs.
*/
public class LogCompilation extends DefaultHandler implements ErrorHandler {
/**
* Print usage information and terminate with a given exit code.
*/
public static void usage(int exitcode) {
System.out.println("Usage: LogCompilation [ -v ] [ -c ] [ -s ] [ -e | -n ] file1 ...");
System.out.println("By default, the tool will print the logged compilations ordered by start time.");
System.out.println(" -c: clean up malformed 1.5 xml");
System.out.println(" -i: print inlining decisions");
System.out.println(" -S: print compilation statistics");
System.out.println(" -s: sort events by start time");
System.out.println(" -U: print uncommon trap statistics");
System.out.println(" -t: print with time stamps");
System.out.println(" -s: sort events by start time (default)");
System.out.println(" -e: sort events by elapsed time");
System.out.println(" -n: sort events by name and start");
System.out.println(" -C: compare logs (give files to compare on command line)");
System.out.println(" -d: do not print compilation IDs");
System.exit(exitcode);
}
/**
* Process command line arguments, parse log files and trigger desired
* functionality.
*/
public static void main(String[] args) throws Exception {
Comparator<LogEvent> defaultSort = LogParser.sortByStart;
Comparator<LogEvent> sort = LogParser.sortByStart;
boolean statistics = false;
boolean printInlining = false;
boolean cleanup = false;
boolean trapHistory = false;
boolean printTimeStamps = false;
boolean compare = false;
boolean printID = true;
int index = 0;
while (args.length > index) {
if (args[index].equals("-e")) {
defaultSort = LogParser.sortByElapsed;
String a = args[index];
if (a.equals("-e")) {
sort = LogParser.sortByElapsed;
index++;
} else if (args[index].equals("-n")) {
defaultSort = LogParser.sortByNameAndStart;
} else if (a.equals("-n")) {
sort = LogParser.sortByNameAndStart;
index++;
} else if (args[index].equals("-s")) {
defaultSort = LogParser.sortByStart;
} else if (a.equals("-s")) {
sort = LogParser.sortByStart;
index++;
} else if (args[index].equals("-c")) {
} else if (a.equals("-t")) {
printTimeStamps = true;
index++;
} else if (a.equals("-c")) {
cleanup = true;
index++;
} else if (args[index].equals("-S")) {
} else if (a.equals("-S")) {
statistics = true;
index++;
} else if (args[index].equals("-h")) {
} else if (a.equals("-U")) {
trapHistory = true;
index++;
} else if (a.equals("-h")) {
usage(0);
} else if (args[index].equals("-i")) {
} else if (a.equals("-i")) {
printInlining = true;
index++;
} else if (a.equals("-C")) {
compare = true;
index++;
} else if (a.equals("-d")) {
printID = false;
index++;
} else {
if (a.charAt(0) == '-') {
System.out.println("Unknown option '" + a + "', assuming file name.");
}
break;
}
}
@ -84,19 +126,40 @@ public class LogCompilation extends DefaultHandler implements ErrorHandler, Cons
usage(1);
}
if (compare) {
compareLogs(index, args);
return;
}
while (index < args.length) {
ArrayList<LogEvent> events = LogParser.parse(args[index], cleanup);
ArrayList<LogEvent> events = null;
try {
events = LogParser.parse(args[index], cleanup);
} catch (FileNotFoundException fnfe) {
System.out.println("File not found: " + args[index]);
System.exit(1);
}
Collections.sort(events, sort);
if (statistics) {
printStatistics(events, System.out);
} else if (trapHistory) {
printTrapHistory(events, System.out);
} else {
Collections.sort(events, defaultSort);
for (LogEvent c : events) {
if (printInlining && c instanceof Compilation) {
Compilation comp = (Compilation)c;
comp.print(System.out, true);
if (c instanceof NMethod) {
// skip these
continue;
}
if (printTimeStamps) {
System.out.print(c.getStart() + ": ");
}
if (c instanceof Compilation) {
Compilation comp = (Compilation) c;
comp.print(System.out, printID, printInlining);
} else {
c.print(System.out);
c.print(System.out, printID);
}
}
}
@ -104,17 +167,25 @@ public class LogCompilation extends DefaultHandler implements ErrorHandler, Cons
}
}
/**
* Print extensive statistics from parsed log files.
*/
public static void printStatistics(ArrayList<LogEvent> events, PrintStream out) {
// track code cache size
long cacheSize = 0;
long maxCacheSize = 0;
// track number of nmethods
int nmethodsCreated = 0;
int nmethodsLive = 0;
// track how many compilations were attempted multiple times
// (indexed by attempts, mapping to number of compilations)
int[] attempts = new int[32];
double regallocTime = 0;
int maxattempts = 0;
LinkedHashMap<String, Double> phaseTime = new LinkedHashMap<String, Double>(7);
LinkedHashMap<String, Integer> phaseNodes = new LinkedHashMap<String, Integer>(7);
// track time spent in compiler phases
LinkedHashMap<String, Double> phaseTime = new LinkedHashMap<>(7);
// track nodes created per phase
LinkedHashMap<String, Integer> phaseNodes = new LinkedHashMap<>(7);
double elapsed = 0;
for (LogEvent e : events) {
@ -137,18 +208,17 @@ public class LogCompilation extends DefaultHandler implements ErrorHandler, Cons
v2 = Integer.valueOf(0);
}
phaseNodes.put(phase.getName(), Integer.valueOf(v2.intValue() + phase.getNodes()));
/* Print phase name, elapsed time, nodes at the start of the phase,
nodes created in the phase, live nodes at the start of the phase,
live nodes added in the phase.
*/
out.printf("\t%s %6.4f %d %d %d %d\n", phase.getName(), phase.getElapsedTime(), phase.getStartNodes(), phase.getNodes(), phase.getStartLiveNodes(), phase.getLiveNodes());
// Print phase name, elapsed time, nodes at the start of
// the phase, nodes created in the phase, live nodes at the
// start of the phase, live nodes added in the phase.
out.printf("\t%s %6.4f %d %d %d %d\n", phase.getName(), phase.getElapsedTime(), phase.getStartNodes(), phase.getNodes(), phase.getStartLiveNodes(), phase.getAddedLiveNodes());
}
} else if (e instanceof MakeNotEntrantEvent) {
MakeNotEntrantEvent mne = (MakeNotEntrantEvent) e;
NMethod nm = mne.getNMethod();
if (mne.isZombie()) {
if (nm == null) {
System.err.println(mne.getId());
System.err.println("zombie make not entrant event without nmethod: " + mne.getId());
}
cacheSize -= nm.getSize();
nmethodsLive--;
@ -161,8 +231,7 @@ public class LogCompilation extends DefaultHandler implements ErrorHandler, Cons
maxCacheSize = Math.max(cacheSize, maxCacheSize);
}
}
out.printf("NMethods: %d created %d live %d bytes (%d peak) in the code cache\n",
nmethodsCreated, nmethodsLive, cacheSize, maxCacheSize);
out.printf("NMethods: %d created %d live %d bytes (%d peak) in the code cache\n", nmethodsCreated, nmethodsLive, cacheSize, maxCacheSize);
out.println("Phase times:");
for (String name : phaseTime.keySet()) {
Double v = phaseTime.get(name);
@ -178,4 +247,265 @@ public class LogCompilation extends DefaultHandler implements ErrorHandler, Cons
}
}
}
/**
* Container class for a pair of a method and a bytecode instruction index
* used by a compiler. This is used in
* {@linkplain #compareLogs() comparing logs}.
*/
static class MethodBCIPair {
public MethodBCIPair(Method m, int b, String c) {
method = m;
bci = b;
compiler = c;
}
Method method;
int bci;
String compiler;
public boolean equals(Object other) {
if (!(other instanceof MethodBCIPair)) {
return false;
}
MethodBCIPair otherp = (MethodBCIPair)other;
return (otherp.bci == bci &&
otherp.method.equals(method) &&
otherp.compiler.equals(compiler));
}
public int hashCode() {
return method.hashCode() + bci;
}
public String toString() {
if (bci != -1) {
return method + "@" + bci + " (" + compiler + ")";
} else {
return method + " (" + compiler + ")";
}
}
}
/**
* Compare a number of compilation log files. Each of the logs is parsed,
* and all compilations found therein are written to a sorted file (prefix
* {@code sorted-}. A summary is written to a new file {@code summary.txt}.
*
* @param index the index in the command line arguments at which to start
* looking for files to compare.
* @param args the command line arguments with which {@link LogCompilation}
* was originally invoked.
*
* @throws Exception in case any exceptions are thrown in the called
* methods.
*/
@SuppressWarnings("unchecked")
static void compareLogs(int index, String[] args) throws Exception {
HashMap<MethodBCIPair,MethodBCIPair> methods = new HashMap<>();
ArrayList<HashMap<MethodBCIPair,Object>> logs = new ArrayList<>();
PrintStream[] outs = new PrintStream[args.length - index];
PrintStream summary = new PrintStream(new FileOutputStream("summary.txt"));
int o = 0;
// Process all logs given on the command line: collect compilation
// data; in particular, method/bci pairs.
while (index < args.length) {
String basename = new File(args[index]).getName();
String outname = "sorted-" + basename;
System.out.println("Sorting " + basename + " to " + outname);
outs[o] = new PrintStream(new FileOutputStream(outname));
o++;
System.out.println("Parsing " + args[index]);
ArrayList<LogEvent> events = LogParser.parse(args[index], false);
HashMap<MethodBCIPair,Object> compiles = new HashMap<>();
logs.add(compiles);
for (LogEvent c : events) {
if (c instanceof Compilation) {
Compilation comp = (Compilation) c;
MethodBCIPair key = new MethodBCIPair(comp.getMethod(), comp.getBCI(),
comp.getCompiler());
MethodBCIPair e = methods.get(key);
if (e == null) {
methods.put(key, key);
} else {
key = e;
}
Object other = compiles.get(key);
if (other == null) {
compiles.put(key, comp);
} else {
if (!(other instanceof List)) {
List<Object> l = new LinkedList<>();
l.add(other);
l.add(comp);
compiles.put(key, l);
} else {
List<Object> l = (List<Object>) other;
l.add(comp);
}
}
}
}
index++;
}
// Process the collected method/bci pairs and write the output.
for (MethodBCIPair pair : methods.keySet()) {
summary.print(pair + " ");
int base = -1;
String first = null;
boolean mismatch = false;
boolean different = false;
String[] output = new String[outs.length];
o = 0;
for (HashMap<MethodBCIPair,Object> set : logs) {
Object e = set.get(pair);
String thisone = null;
Compilation lastc = null;
int n;
if (e == null) {
n = 0;
} else if (e instanceof Compilation) {
n = 1;
lastc = (Compilation) e;
} else {
// Compare the last compilation that was done for this method
n = ((List<Object>) e).size();
lastc = (Compilation) ((List<Object>) e).get(n - 1);
}
if (lastc != null) {
n = 1;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
lastc.print(ps, false);
ps.close();
thisone = new String(baos.toByteArray());
}
if (base == -1) {
base = n;
} else if (base != n) {
mismatch = true;
}
output[o++] = thisone;
if (thisone != null) {
if (first == null) {
first = thisone;
} else {
if (!first.equals(thisone)) {
different = true;
}
}
}
if (different) {
summary.print(n + "d ");
} else {
summary.print(n + " ");
}
}
if (mismatch) {
summary.print("mismatch");
}
summary.println();
if (different) {
for (int i = 0; i < outs.length; i++) {
if (output[i] != null) {
outs[i].println(output[i]);
}
}
}
}
for (int i = 0; i < outs.length; i++) {
outs[i].close();
}
if (summary != System.out) {
summary.close();
}
}
/**
* Print the history of uncommon trap events.
*/
public static void printTrapHistory(ArrayList<LogEvent> events, PrintStream out) {
// map method names to a list of log events
LinkedHashMap<String, ArrayList<LogEvent>> traps = new LinkedHashMap<>();
// map compilation IDs to compilations
HashMap<Integer, Compilation> comps = new HashMap<>();
// First, iterate over all logged events, collecting data about
// uncommon trap events.
for (LogEvent e : events) {
if (e instanceof NMethod) {
// skip these
continue;
}
if (e instanceof Compilation) {
Compilation c = (Compilation) e;
String name = c.getMethod().getFullName();
ArrayList<LogEvent> elist = traps.get(name);
if (elist != null && comps.get(c.getId()) == null) {
comps.put(c.getId(), c);
// If there were previous events for the method
// then keep track of later compiles too.
elist.add(c);
}
continue;
}
if (e instanceof BasicLogEvent) {
BasicLogEvent ble = (BasicLogEvent) e;
Compilation c = ble.getCompilation();
if (c == null) {
if (!(ble instanceof NMethod)) {
throw new InternalError("only nmethods should have a null compilation; here's a " + ble.getClass());
}
continue;
}
String name = c.getMethod().getFullName();
ArrayList<LogEvent> elist = traps.get(name);
if (elist == null) {
elist = new ArrayList<LogEvent>();
traps.put(name, elist);
}
int bleId = Integer.parseInt(ble.getId());
if (comps.get(bleId) == null) {
comps.put(bleId, c);
// Add the associated compile to the list. It
// will likely go at the end but we need to search
// backwards for the proper insertion point.
double start = c.getStart();
int ipoint = 0;
while (ipoint < elist.size() && elist.get(ipoint).getStart() < start) {
ipoint++;
}
if (ipoint == elist.size()) {
elist.add(c);
} else {
elist.add(ipoint, c);
}
}
elist.add(ble);
}
}
// Second, iterate over collected traps and output information.
for (String c: traps.keySet()) {
ArrayList<LogEvent> elist = traps.get(c);
String name = ((Compilation) elist.get(0)).getMethod().getFullName();
System.out.println(name);
double start = 0;
for (LogEvent e: elist) {
if (start > e.getStart() && e.getStart() != 0) {
throw new InternalError("wrong sorting order for traps");
}
start = e.getStart();
out.print(e.getStart() + ": ");
if (e instanceof Compilation) {
((Compilation) e).print(out, true, true, true);
} else {
e.print(out, true);
}
}
out.println();
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2015, 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
@ -25,14 +25,31 @@
package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
import java.util.*;
/**
* The interface of an event from a HotSpot compilation log. Events can have a
* duration, e.g., a compiler {@link Phase} is an event, and so is an entire
* {@link Compilation}.
*/
public interface LogEvent {
/**
* The event's start time.
*/
public double getStart();
/**
* The event's duration in milliseconds.
*/
public double getElapsedTime();
/**
* The compilation during which this event was signalled.
*/
public Compilation getCompilation();
public void print(PrintStream stream);
/**
* Print the event to the given stream.
*/
public void print(PrintStream stream, boolean printID);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2015, 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
@ -21,14 +21,25 @@
* questions.
*
*/
package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
/**
* In a compilation log, represent the event of making a given compiled method
* not-entrant, e.g., during an OSR compilation.
*/
class MakeNotEntrantEvent extends BasicLogEvent {
/**
* Denote whether the method is marked as a zombie, i.e., no further
* activations exist.
*/
private final boolean zombie;
/**
* The method in question.
*/
private NMethod nmethod;
MakeNotEntrantEvent(double s, String i, boolean z, NMethod nm) {
@ -41,7 +52,7 @@ class MakeNotEntrantEvent extends BasicLogEvent {
return nmethod;
}
public void print(PrintStream stream) {
public void print(PrintStream stream, boolean printID) {
if (isZombie()) {
stream.printf("%s make_zombie\n", getId());
} else {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2015, 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
@ -26,16 +26,58 @@ package com.sun.hotspot.tools.compiler;
import java.util.Arrays;
public class Method implements Constants {
import static com.sun.hotspot.tools.compiler.Constants.*;
/**
* Representation of a Java method in a compilation log.
*/
public class Method {
/**
* The name of the class holding the method.
*/
private String holder;
/**
* The method's name.
*/
private String name;
/**
* The return type of the method, as a fully qualified (source-level) class
* or primitive type name.
*/
private String returnType;
private String arguments;
/**
* The method's signature, in internal form.
*/
private String signature;
/**
* The length of the method's byte code.
*/
private String bytes;
/**
* The number of times this method was invoked in the interpreter.
*/
private String iicount;
/**
* The method's flags, in the form of a {@code String} representing the
* {@code int} encoding them.
*/
private String flags;
/**
* Decode the {@link flags} numerical string to a format for console
* output. The result does not honour all possible flags but includes
* information about OSR compilation.
*
* @param osr_bci the byte code index at which an OSR compilation takes
* place, or -1 if the compilation is not an OSR one.
*/
String decodeFlags(int osr_bci) {
int f = Integer.parseInt(getFlags());
char[] c = new char[4];
@ -49,6 +91,12 @@ public class Method implements Constants {
return new String(c);
}
/**
* Format this method for console output.
*
* @param osr_bci the byte code index at which OSR takes place, or -1 if no
* OSR compilation is going on.
*/
String format(int osr_bci) {
if (osr_bci >= 0) {
return getHolder() + "::" + getName() + " @ " + osr_bci + " (" + getBytes() + " bytes)";
@ -62,6 +110,10 @@ public class Method implements Constants {
return getHolder() + "::" + getName() + " (" + getBytes() + " bytes)";
}
public String getFullName() {
return getHolder().replace('/', '.') + "." + getName() + signature;
}
public String getHolder() {
return holder;
}
@ -86,12 +138,16 @@ public class Method implements Constants {
this.returnType = returnType;
}
public String getArguments() {
return arguments;
public String getSignature() {
return signature;
}
public void setArguments(String arguments) {
this.arguments = arguments;
public void setSignature(String signature) {
this.signature = signature.replace('/', '.');
}
public String getArguments() {
return signature.substring(0, signature.indexOf(')') + 1);
}
public String getBytes() {
@ -121,10 +177,13 @@ public class Method implements Constants {
@Override
public boolean equals(Object o) {
if (o instanceof Method) {
Method other = (Method)o;
return holder.equals(other.holder) && name.equals(other.name) &&
arguments.equals(other.arguments) && returnType.equals(other.returnType);
Method other = (Method) o;
return holder.equals(other.holder) && name.equals(other.name) && signature.equals(other.signature);
}
return false;
}
public int hashCode() {
return holder.hashCode() ^ name.hashCode();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2015, 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
@ -26,9 +26,20 @@ package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
/**
* A compilation log event that is signalled whenever a new nmethod (a native
* method, a compilation result) is created.
*/
public class NMethod extends BasicLogEvent {
/**
* The nmethod's starting address in memory.
*/
private long address;
/**
* The nmethod's size in bytes.
*/
private long size;
NMethod(double s, String i, long a, long sz) {
@ -37,7 +48,7 @@ public class NMethod extends BasicLogEvent {
size = sz;
}
public void print(PrintStream out) {
public void print(PrintStream out, boolean printID) {
// XXX Currently we do nothing
// throw new InternalError();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2015, 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
@ -26,11 +26,30 @@ package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
/**
* Representation of a compilation phase as a log event.
*/
public class Phase extends BasicLogEvent {
/**
* The number of nodes in the compilation at the beginning of this phase.
*/
private final int startNodes;
/**
* The number of nodes in the compilation at the end of this phase.
*/
private int endNodes;
/**
* The number of live nodes in the compilation at the beginning of this
* phase.
*/
private final int startLiveNodes;
/**
* The number of live nodes in the compilation at the end of this phase.
*/
private int endLiveNodes;
Phase(String n, double s, int nodes, int live) {
@ -58,8 +77,11 @@ public class Phase extends BasicLogEvent {
public int getEndNodes() {
return endNodes;
}
/* Number of live nodes added by the phase */
int getLiveNodes() {
/**
* The number of live nodes added by this phase.
*/
int getAddedLiveNodes() {
return getEndLiveNodes() - getStartLiveNodes();
}
@ -76,7 +98,7 @@ public class Phase extends BasicLogEvent {
}
@Override
public void print(PrintStream stream) {
public void print(PrintStream stream, boolean printID) {
throw new UnsupportedOperationException("Not supported yet.");
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2009, 2015, 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
/**
* An instance of this class represents an uncommon trap associated with a
* given bytecode instruction. An uncommon trap is described in terms of its
* reason and action to be taken. An instance of this class is always relative
* to a specific method and only contains the relevant bytecode instruction
* index.
*/
class UncommonTrap {
private int bci;
private String reason;
private String action;
private String bytecode;
public UncommonTrap(int b, String r, String a, String bc) {
bci = b;
reason = r;
action = a;
bytecode = bc;
}
public int getBCI() {
return bci;
}
public String getReason() {
return reason;
}
public String getAction() {
return action;
}
public String getBytecode() {
return bytecode;
}
void emit(PrintStream stream, int indent) {
for (int i = 0; i < indent; i++) {
stream.print(' ');
}
}
public void print(PrintStream stream, int indent) {
emit(stream, indent);
stream.println(this);
}
public String toString() {
return "@ " + bci + " " + getBytecode() + " uncommon trap " + getReason() + " " + getAction();
}
}

View File

@ -21,17 +21,33 @@
* questions.
*
*/
package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
/**
* Represents an uncommon trap encountered during a compilation.
*/
class UncommonTrapEvent extends BasicLogEvent {
private final String reason;
private final String action;
/**
* Denote how many times this trap has been encountered.
*/
private int count;
private String jvms = "";
/**
* The name of the bytecode instruction at which the trap occurred.
*/
private String bytecode;
private List<String> jvmsMethods = new ArrayList<>();
private List<Integer> jvmsBCIs = new ArrayList<>();
UncommonTrapEvent(double s, String i, String r, String a, int c) {
super(s, i);
@ -40,20 +56,26 @@ class UncommonTrapEvent extends BasicLogEvent {
count = c;
}
public void addJVMS(String method, int bci) {
setJvms(getJvms() + " @" + bci + " " + method + "\n");
}
public void updateCount(UncommonTrapEvent trap) {
setCount(Math.max(getCount(), trap.getCount()));
}
public void print(PrintStream stream) {
stream.printf("%s uncommon trap %.3f %s %s\n", getId(), getStart(), getReason(), getAction());
stream.print(getJvms());
public void print(PrintStream stream, boolean printID) {
if (printID) {
stream.print(getId() + " ");
}
stream.printf("uncommon trap %s %s %s\n", bytecode, getReason(), getAction());
int indent = 2;
for (int j = 0; j < jvmsMethods.size(); j++) {
for (int i = 0; i < indent; i++) {
stream.print(' ');
}
stream.println("@ " + jvmsBCIs.get(j) + " " + jvmsMethods.get(j));
indent += 2;
}
}
public String getReason() {
return reason;
}
@ -70,15 +92,56 @@ class UncommonTrapEvent extends BasicLogEvent {
this.count = count;
}
public String getJvms() {
return jvms;
}
public void setJvms(String jvms) {
this.jvms = jvms;
}
/**
* Set the compilation for this event. This involves identifying the call
* site to which this uncommon trap event belongs. In addition to setting
* the {@link #compilation} link, this method will consequently also set
* the {@link #bytecode} field.
*/
public void setCompilation(Compilation compilation) {
this.compilation = compilation;
super.setCompilation(compilation);
// Attempt to associate a bytecode with with this trap
CallSite site = compilation.getCall();
int i = 0;
try {
List<UncommonTrap> traps = site.getTraps();
while (i + 1 < jvmsMethods.size()) {
if (!jvmsMethods.get(i).equals(site.getMethod().getFullName())) {
throw new InternalError(jvmsMethods.get(i) + " != " + site.getMethod().getFullName());
}
CallSite result = null;
for (CallSite call : site.getCalls()) {
if (call.getBci() == jvmsBCIs.get(i) &&
call.getMethod().getFullName().equals(jvmsMethods.get(i + 1)) &&
call.getReceiver() == null) {
result = call;
i++;
break;
}
}
if (result == null) {
throw new InternalError("couldn't find call site");
}
site = result;
traps = site.getTraps();
}
for (UncommonTrap trap : traps) {
if (trap.getBCI() == jvmsBCIs.get(i) &&
trap.getReason().equals(getReason()) &&
trap.getAction().equals(getAction())) {
bytecode = trap.getBytecode();
return;
}
}
throw new InternalError("couldn't find bytecode");
} catch (Exception e) {
bytecode = "<unknown>";
}
}
public void addMethodAndBCI(String method, int bci) {
jvmsMethods.add(0, method);
jvmsBCIs.add(0, bci);
}
}

View File

@ -75,6 +75,9 @@ ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) :
{
assert(h_m() != NULL, "no null method");
if (LogTouchedMethods) {
h_m()->log_touched(Thread::current());
}
// These fields are always filled in in loaded methods.
_flags = ciFlags(h_m()->access_flags());

View File

@ -2698,8 +2698,7 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(u1* inner_classes_at
// Inner class index
u2 inner_class_info_index = cfs->get_u2_fast();
check_property(
inner_class_info_index == 0 ||
valid_klass_reference_at(inner_class_info_index),
valid_klass_reference_at(inner_class_info_index),
"inner_class_info_index %u has bad constant type in class file %s",
inner_class_info_index, CHECK_0);
// Outer class index
@ -5163,8 +5162,8 @@ int ClassFileParser::verify_legal_method_signature(Symbol* name, Symbol* signatu
// The first non-signature thing better be a ')'
if ((length > 0) && (*p++ == JVM_SIGNATURE_ENDFUNC)) {
length--;
if (name->utf8_length() > 0 && name->byte_at(0) == '<') {
// All internal methods must return void
if (name == vmSymbols::object_initializer_name()) {
// All "<init>" methods must return void
if ((length == 1) && (p[0] == JVM_SIGNATURE_VOID)) {
return args_size;
}

View File

@ -58,14 +58,14 @@ Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS
if (DumpSharedSpaces) {
// Allocate all symbols to CLD shared metaspace
sym = new (len, ClassLoaderData::the_null_class_loader_data(), THREAD) Symbol(name, len, -1);
sym = new (len, ClassLoaderData::the_null_class_loader_data(), THREAD) Symbol(name, len, PERM_REFCOUNT);
} else if (c_heap) {
// refcount starts as 1
sym = new (len, THREAD) Symbol(name, len, 1);
assert(sym != NULL, "new should call vm_exit_out_of_memory if C_HEAP is exhausted");
} else {
// Allocate to global arena
sym = new (len, arena(), THREAD) Symbol(name, len, -1);
sym = new (len, arena(), THREAD) Symbol(name, len, PERM_REFCOUNT);
}
return sym;
}

View File

@ -2846,7 +2846,7 @@ void ClassVerifier::verify_invoke_instructions(
if (sig_stream.type() != T_VOID) {
if (method_name == vmSymbols::object_initializer_name()) {
// <init> method must have a void return type
/* Unreachable? Class file parser verifies that methods with '<' have
/* Unreachable? Class file parser verifies that <init> methods have
* void return */
verify_error(ErrorContext::bad_code(bci),
"Return type must be void in <init> method");

View File

@ -501,8 +501,8 @@ void CompileTask::log_task(xmlStream* log) {
methodHandle method(thread, this->method());
ResourceMark rm(thread);
// <task id='9' method='M' osr_bci='X' level='1' blocking='1' stamp='1.234'>
log->print(" compile_id='%d'", _compile_id);
// <task compiler='Cx' id='9' method='M' osr_bci='X' level='1' blocking='1' stamp='1.234'>
log->print(" compiler='%s' compile_id='%d'", _comp_level <= CompLevel_full_profile ? "C1" : "C2", _compile_id);
if (_osr_bci != CompileBroker::standard_entry_bci) {
log->print(" compile_kind='osr'"); // same as nmethod::compile_kind
} // else compile_kind='c2c'

View File

@ -848,7 +848,7 @@ void EvacuateFollowersClosureGeneral::do_void() {
_gch->oop_since_save_marks_iterate(GenCollectedHeap::YoungGen,
_scan_cur_or_nonheap,
_scan_older);
} while (!_gch->no_allocs_since_save_marks(true /* include_young */));
} while (!_gch->no_allocs_since_save_marks());
}

View File

@ -96,7 +96,7 @@ EvacuateFollowersClosure(GenCollectedHeap* gch,
void DefNewGeneration::EvacuateFollowersClosure::do_void() {
do {
_gch->oop_since_save_marks_iterate(GenCollectedHeap::YoungGen, _scan_cur_or_nonheap, _scan_older);
} while (!_gch->no_allocs_since_save_marks(GenCollectedHeap::YoungGen));
} while (!_gch->no_allocs_since_save_marks());
}
DefNewGeneration::FastEvacuateFollowersClosure::
@ -112,7 +112,7 @@ FastEvacuateFollowersClosure(GenCollectedHeap* gch,
void DefNewGeneration::FastEvacuateFollowersClosure::do_void() {
do {
_gch->oop_since_save_marks_iterate(GenCollectedHeap::YoungGen, _scan_cur_or_nonheap, _scan_older);
} while (!_gch->no_allocs_since_save_marks(GenCollectedHeap::YoungGen));
} while (!_gch->no_allocs_since_save_marks());
guarantee(_gen->promo_failure_scan_is_complete(), "Failed to finish scan");
}
@ -597,7 +597,7 @@ void DefNewGeneration::collect(bool full,
gch->rem_set()->prepare_for_younger_refs_iterate(false);
assert(gch->no_allocs_since_save_marks(GenCollectedHeap::YoungGen),
assert(gch->no_allocs_since_save_marks(),
"save marks have not been newly set.");
// Not very pretty.
@ -617,7 +617,7 @@ void DefNewGeneration::collect(bool full,
&fsc_with_no_gc_barrier,
&fsc_with_gc_barrier);
assert(gch->no_allocs_since_save_marks(GenCollectedHeap::YoungGen),
assert(gch->no_allocs_since_save_marks(),
"save marks have not been newly set.");
{

View File

@ -741,11 +741,9 @@ ALL_SINCE_SAVE_MARKS_CLOSURES(GCH_SINCE_SAVE_MARKS_ITERATE_DEFN)
#undef GCH_SINCE_SAVE_MARKS_ITERATE_DEFN
bool GenCollectedHeap::no_allocs_since_save_marks(bool include_young) {
if (include_young && !_young_gen->no_allocs_since_save_marks()) {
return false;
}
return _old_gen->no_allocs_since_save_marks();
bool GenCollectedHeap::no_allocs_since_save_marks() {
return _young_gen->no_allocs_since_save_marks() &&
_old_gen->no_allocs_since_save_marks();
}
bool GenCollectedHeap::supports_inline_contig_alloc() const {

View File

@ -436,7 +436,7 @@ public:
// Returns "true" iff no allocations have occurred since the last
// call to "save_marks".
bool no_allocs_since_save_marks(bool include_young);
bool no_allocs_since_save_marks();
// Returns true if an incremental collection is likely to fail.
// We optionally consult the young gen, if asked to do so;

View File

@ -32,26 +32,32 @@ PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
void markOopDesc::print_on(outputStream* st) const {
if (is_marked()) {
st->print(" marked(" INTPTR_FORMAT ")", value());
} else if (has_monitor()) {
// have to check has_monitor() before is_locked()
st->print(" monitor(" INTPTR_FORMAT ")=", value());
ObjectMonitor* mon = monitor();
if (mon == NULL) {
st->print("NULL (this should never be seen!)");
} else {
st->print("{count=" INTPTR_FORMAT ",waiters=" INTPTR_FORMAT
",recursions=" INTPTR_FORMAT ",owner=" INTPTR_FORMAT "}",
mon->count(), mon->waiters(), mon->recursions(),
p2i(mon->owner()));
}
} else if (is_locked()) {
st->print(" locked(" INTPTR_FORMAT ")->", value());
if (is_neutral()) {
st->print("is_neutral");
if (has_no_hash()) st->print(" no_hash");
else st->print(" hash=" INTPTR_FORMAT, hash());
if (has_no_hash()) {
st->print(" no_hash");
} else {
st->print(" hash=" INTPTR_FORMAT, hash());
}
st->print(" age=%d", age());
} else if (has_bias_pattern()) {
st->print("is_biased");
JavaThread* jt = biased_locker();
st->print(" biased_locker=" INTPTR_FORMAT, p2i(jt));
} else if (has_monitor()) {
ObjectMonitor* mon = monitor();
if (mon == NULL)
st->print("monitor=NULL");
else {
BasicLock * bl = (BasicLock *) mon->owner();
st->print("monitor={count=" INTPTR_FORMAT ",waiters=" INTPTR_FORMAT ",recursions=" INTPTR_FORMAT ",owner=" INTPTR_FORMAT "}",
mon->count(), mon->waiters(), mon->recursions(), p2i(bl));
}
} else {
st->print("??");
}

View File

@ -422,6 +422,11 @@ MethodCounters* Method::build_method_counters(Method* m, TRAPS) {
if (!mh->init_method_counters(counters)) {
MetadataFactory::free_metadata(mh->method_holder()->class_loader_data(), counters);
}
if (LogTouchedMethods) {
mh->log_touched(CHECK_NULL);
}
return mh->method_counters();
}
@ -2130,6 +2135,85 @@ void Method::collect_statistics(KlassSizeStats *sz) const {
}
#endif // INCLUDE_SERVICES
// LogTouchedMethods and PrintTouchedMethods
// TouchedMethodRecord -- we can't use a HashtableEntry<Method*> because
// the Method may be garbage collected. Let's roll our own hash table.
class TouchedMethodRecord : CHeapObj<mtTracing> {
public:
// It's OK to store Symbols here because they will NOT be GC'ed if
// LogTouchedMethods is enabled.
TouchedMethodRecord* _next;
Symbol* _class_name;
Symbol* _method_name;
Symbol* _method_signature;
};
static const int TOUCHED_METHOD_TABLE_SIZE = 20011;
static TouchedMethodRecord** _touched_method_table = NULL;
void Method::log_touched(TRAPS) {
const int table_size = TOUCHED_METHOD_TABLE_SIZE;
Symbol* my_class = klass_name();
Symbol* my_name = name();
Symbol* my_sig = signature();
unsigned int hash = my_class->identity_hash() +
my_name->identity_hash() +
my_sig->identity_hash();
juint index = juint(hash) % table_size;
MutexLocker ml(TouchedMethodLog_lock, THREAD);
if (_touched_method_table == NULL) {
_touched_method_table = NEW_C_HEAP_ARRAY2(TouchedMethodRecord*, table_size,
mtTracing, CURRENT_PC);
memset(_touched_method_table, 0, sizeof(TouchedMethodRecord*)*table_size);
}
TouchedMethodRecord* ptr = _touched_method_table[index];
while (ptr) {
if (ptr->_class_name == my_class &&
ptr->_method_name == my_name &&
ptr->_method_signature == my_sig) {
return;
}
if (ptr->_next == NULL) break;
ptr = ptr->_next;
}
TouchedMethodRecord* nptr = NEW_C_HEAP_OBJ(TouchedMethodRecord, mtTracing);
my_class->set_permanent(); // prevent reclaimed by GC
my_name->set_permanent();
my_sig->set_permanent();
nptr->_class_name = my_class;
nptr->_method_name = my_name;
nptr->_method_signature = my_sig;
nptr->_next = NULL;
if (ptr == NULL) {
// first
_touched_method_table[index] = nptr;
} else {
ptr->_next = nptr;
}
}
void Method::print_touched_methods(outputStream* out) {
MutexLockerEx ml(Thread::current()->is_VM_thread() ? NULL : TouchedMethodLog_lock);
out->print_cr("# Method::print_touched_methods version 1");
if (_touched_method_table) {
for (int i = 0; i < TOUCHED_METHOD_TABLE_SIZE; i++) {
TouchedMethodRecord* ptr = _touched_method_table[i];
while(ptr) {
ptr->_class_name->print_symbol_on(out); out->print(".");
ptr->_method_name->print_symbol_on(out); out->print(":");
ptr->_method_signature->print_symbol_on(out); out->cr();
ptr = ptr->_next;
}
}
}
}
// Verification
void Method::verify_on(outputStream* st) {

View File

@ -625,6 +625,8 @@ class Method : public Metadata {
#if INCLUDE_SERVICES
void collect_statistics(KlassSizeStats *sz) const;
#endif
void log_touched(TRAPS);
static void print_touched_methods(outputStream* out);
// interpreter support
static ByteSize const_offset() { return byte_offset_of(Method, _constMethod ); }

View File

@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@ -96,12 +96,16 @@
// TempNewSymbol (passed in as a parameter) so the reference count on its symbol
// will be decremented when it goes out of scope.
// This cannot be inherited from ResourceObj because it cannot have a vtable.
// Since sometimes this is allocated from Metadata, pick a base allocation
// type without virtual functions.
class ClassLoaderData;
// Set _refcount to PERM_REFCOUNT to prevent the Symbol from being GC'ed.
#ifndef PERM_REFCOUNT
#define PERM_REFCOUNT -1
#endif
// We separate the fields in SymbolBase from Symbol::_body so that
// Symbol::size(int) can correctly calculate the space needed.
class SymbolBase : public MetaspaceObj {
@ -160,6 +164,13 @@ class Symbol : private SymbolBase {
int refcount() const { return _refcount; }
void increment_refcount();
void decrement_refcount();
// Set _refcount non zero to avoid being reclaimed by GC.
void set_permanent() {
assert(LogTouchedMethods, "Should not be called with LogTouchedMethods off");
if (_refcount != PERM_REFCOUNT) {
_refcount = PERM_REFCOUNT;
}
}
int byte_at(int index) const {
assert(index >=0 && index < _length, "symbol index overflow");

View File

@ -280,6 +280,10 @@ bool IdealLoopTree::policy_peeling( PhaseIdealLoop *phase ) const {
|| (body_size * body_size + phase->C->live_nodes()) > phase->C->max_node_limit() ) {
return false; // too large to safely clone
}
// check for vectorized loops, any peeling done was already applied
if (_head->is_CountedLoop() && _head->as_CountedLoop()->do_unroll_only()) return false;
while( test != _head ) { // Scan till run off top of loop
if( test->is_If() ) { // Test?
Node *ctrl = phase->get_ctrl(test->in(1));
@ -656,7 +660,12 @@ bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) {
_local_loop_unroll_limit = LoopUnrollLimit;
_local_loop_unroll_factor = 4;
int future_unroll_ct = cl->unrolled_count() * 2;
if (future_unroll_ct > LoopMaxUnroll) return false;
if (!cl->do_unroll_only()) {
if (future_unroll_ct > LoopMaxUnroll) return false;
} else {
// obey user constraints on vector mapped loops with additional unrolling applied
if ((future_unroll_ct / cl->slp_max_unroll()) > LoopMaxUnroll) return false;
}
// Check for initial stride being a small enough constant
if (abs(cl->stride_con()) > (1<<2)*future_unroll_ct) return false;
@ -759,13 +768,19 @@ bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) {
if (LoopMaxUnroll > _local_loop_unroll_factor) {
// Once policy_slp_analysis succeeds, mark the loop with the
// maximal unroll factor so that we minimize analysis passes
if ((future_unroll_ct > _local_loop_unroll_factor) ||
(body_size > (uint)_local_loop_unroll_limit)) {
if (future_unroll_ct >= _local_loop_unroll_factor) {
policy_unroll_slp_analysis(cl, phase, future_unroll_ct);
}
}
}
int slp_max_unroll_factor = cl->slp_max_unroll();
if (cl->has_passed_slp()) {
if (slp_max_unroll_factor >= future_unroll_ct) return true;
// Normal case: loop too big
return false;
}
// Check for being too big
if (body_size > (uint)_local_loop_unroll_limit) {
if (xors_in_loop >= 4 && body_size < (uint)LoopUnrollLimit*4) return true;
@ -773,6 +788,10 @@ bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) {
return false;
}
if(cl->do_unroll_only()) {
NOT_PRODUCT(if (TraceSuperWordLoopUnrollAnalysis) tty->print_cr("policy_unroll passed vector loop(vlen=%d,factor = %d)\n", slp_max_unroll_factor, future_unroll_ct));
}
// Unroll once! (Each trip will soon do double iterations)
return true;
}
@ -780,28 +799,24 @@ bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) {
void IdealLoopTree::policy_unroll_slp_analysis(CountedLoopNode *cl, PhaseIdealLoop *phase, int future_unroll_ct) {
// Enable this functionality target by target as needed
if (SuperWordLoopUnrollAnalysis) {
if (!cl->has_passed_slp()) {
if (!cl->was_slp_analyzed()) {
SuperWord sw(phase);
sw.transform_loop(this, false);
// If the loop is slp canonical analyze it
if (sw.early_return() == false) {
sw.unrolling_analysis(cl, _local_loop_unroll_factor);
sw.unrolling_analysis(_local_loop_unroll_factor);
}
}
int slp_max_unroll_factor = cl->slp_max_unroll();
if ((slp_max_unroll_factor > 4) &&
(slp_max_unroll_factor >= future_unroll_ct)) {
int new_limit = cl->node_count_before_unroll() * slp_max_unroll_factor;
if (new_limit > LoopUnrollLimit) {
#ifndef PRODUCT
if (TraceSuperWordLoopUnrollAnalysis) {
tty->print_cr("slp analysis is applying unroll limit %d, the original limit was %d\n",
new_limit, _local_loop_unroll_limit);
if (cl->has_passed_slp()) {
int slp_max_unroll_factor = cl->slp_max_unroll();
if (slp_max_unroll_factor >= future_unroll_ct) {
int new_limit = cl->node_count_before_unroll() * slp_max_unroll_factor;
if (new_limit > LoopUnrollLimit) {
NOT_PRODUCT(if (TraceSuperWordLoopUnrollAnalysis) tty->print_cr("slp analysis unroll=%d, default limit=%d\n", new_limit, _local_loop_unroll_limit));
_local_loop_unroll_limit = new_limit;
}
#endif
_local_loop_unroll_limit = new_limit;
}
}
}
@ -830,6 +845,9 @@ bool IdealLoopTree::policy_range_check( PhaseIdealLoop *phase ) const {
if (cl->is_main_no_pre_loop()) return false; // Disallowed for now.
Node *trip_counter = cl->phi();
// check for vectorized loops, some opts are no longer needed
if (cl->do_unroll_only()) return false;
// Check loop body for tests of trip-counter plus loop-invariant vs
// loop-invariant.
for (uint i = 0; i < _body.size(); i++) {
@ -880,6 +898,8 @@ bool IdealLoopTree::policy_range_check( PhaseIdealLoop *phase ) const {
// Return TRUE or FALSE if the loop should NEVER be RCE'd or aligned. Useful
// for unrolling loops with NO array accesses.
bool IdealLoopTree::policy_peel_only( PhaseIdealLoop *phase ) const {
// check for vectorized loops, any peeling done was already applied
if (_head->is_CountedLoop() && _head->as_CountedLoop()->do_unroll_only()) return false;
for( uint i = 0; i < _body.size(); i++ )
if( _body[i]->is_Mem() )

View File

@ -61,6 +61,12 @@ bool IdealLoopTree::policy_unswitching( PhaseIdealLoop *phase ) const {
if (!_head->is_Loop()) {
return false;
}
// check for vectorized loops, any unswitching was already applied
if (_head->is_CountedLoop() && _head->as_CountedLoop()->do_unroll_only()) {
return false;
}
int nodes_left = phase->C->max_node_limit() - phase->C->live_nodes();
if ((int)(2 * _body.size()) > nodes_left) {
return false; // Too speculative if running low on nodes.

View File

@ -2317,7 +2317,11 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts)
// Reassociate invariants and prep for split_thru_phi
for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
IdealLoopTree* lpt = iter.current();
if (!lpt->is_counted() || !lpt->is_inner()) continue;
bool is_counted = lpt->is_counted();
if (!is_counted || !lpt->is_inner()) continue;
// check for vectorized loops, any reassociation of invariants was already done
if (is_counted && lpt->_head->as_CountedLoop()->do_unroll_only()) continue;
lpt->reassociate_invariants(this);

View File

@ -64,7 +64,9 @@ protected:
PartialPeelLoop=32,
PartialPeelFailed=64,
HasReductions=128,
PassedSlpAnalysis=256 };
WasSlpAnalyzed=256,
PassedSlpAnalysis=512,
DoUnrollOnly=1024 };
char _unswitch_count;
enum { _unswitch_max=3 };
@ -80,7 +82,9 @@ public:
int partial_peel_has_failed() const { return _loop_flags & PartialPeelFailed; }
void mark_partial_peel_failed() { _loop_flags |= PartialPeelFailed; }
void mark_has_reductions() { _loop_flags |= HasReductions; }
void mark_was_slp() { _loop_flags |= WasSlpAnalyzed; }
void mark_passed_slp() { _loop_flags |= PassedSlpAnalysis; }
void mark_do_unroll_only() { _loop_flags |= DoUnrollOnly; }
int unswitch_max() { return _unswitch_max; }
int unswitch_count() { return _unswitch_count; }
@ -212,7 +216,9 @@ public:
int is_main_loop () const { return (_loop_flags&PreMainPostFlagsMask) == Main; }
int is_post_loop () const { return (_loop_flags&PreMainPostFlagsMask) == Post; }
int is_reduction_loop() const { return (_loop_flags&HasReductions) == HasReductions; }
int was_slp_analyzed () const { return (_loop_flags&WasSlpAnalyzed) == WasSlpAnalyzed; }
int has_passed_slp () const { return (_loop_flags&PassedSlpAnalysis) == PassedSlpAnalysis; }
int do_unroll_only () const { return (_loop_flags&DoUnrollOnly) == DoUnrollOnly; }
int is_main_no_pre_loop() const { return _loop_flags & MainHasNoPreLoop; }
void set_main_no_pre_loop() { _loop_flags |= MainHasNoPreLoop; }
@ -235,6 +241,9 @@ public:
void set_nonexact_trip_count() {
_loop_flags &= ~HasExactTripCount;
}
void set_notpassed_slp() {
_loop_flags &= ~PassedSlpAnalysis;
}
void set_profile_trip_cnt(float ptc) { _profile_trip_cnt = ptc; }
float profile_trip_cnt() { return _profile_trip_cnt; }

View File

@ -100,6 +100,10 @@ void SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) {
return;
}
// We only re-enter slp when we vector mapped a queried loop and we want to
// continue unrolling, in this case, slp is not subsequently done.
if (cl->do_unroll_only()) return;
// Check for pre-loop ending with CountedLoopEnd(Bool(Cmp(x,Opaque1(limit))))
CountedLoopEndNode* pre_end = get_pre_loop_end(cl);
if (pre_end == NULL) return;
@ -121,12 +125,13 @@ void SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) {
}
//------------------------------early unrolling analysis------------------------------
void SuperWord::unrolling_analysis(CountedLoopNode *cl, int &local_loop_unroll_factor) {
void SuperWord::unrolling_analysis(int &local_loop_unroll_factor) {
bool is_slp = true;
ResourceMark rm;
size_t ignored_size = lpt()->_body.size();
int *ignored_loop_nodes = NEW_RESOURCE_ARRAY(int, ignored_size);
Node_Stack nstack((int)ignored_size);
CountedLoopNode *cl = lpt()->_head->as_CountedLoop();
Node *cl_exit = cl->loopexit();
// First clear the entries
@ -249,13 +254,9 @@ void SuperWord::unrolling_analysis(CountedLoopNode *cl, int &local_loop_unroll_f
// If a max vector exists which is not larger than _local_loop_unroll_factor
// stop looking, we already have the max vector to map to.
if (cur_max_vector <= local_loop_unroll_factor) {
if (cur_max_vector < local_loop_unroll_factor) {
is_slp = false;
#ifndef PRODUCT
if (TraceSuperWordLoopUnrollAnalysis) {
tty->print_cr("slp analysis fails: unroll limit equals max vector\n");
}
#endif
NOT_PRODUCT(if (TraceSuperWordLoopUnrollAnalysis) tty->print_cr("slp analysis fails: unroll limit greater than max vector\n"));
break;
}
@ -268,8 +269,9 @@ void SuperWord::unrolling_analysis(CountedLoopNode *cl, int &local_loop_unroll_f
}
if (is_slp) {
local_loop_unroll_factor = max_vector;
cl->mark_passed_slp();
}
cl->mark_passed_slp();
cl->mark_was_slp();
cl->set_slp_max_unroll(local_loop_unroll_factor);
}
}
@ -1758,7 +1760,9 @@ void SuperWord::output() {
}
Compile* C = _phase->C;
CountedLoopNode *cl = lpt()->_head->as_CountedLoop();
uint max_vlen_in_bytes = 0;
uint max_vlen = 0;
for (int i = 0; i < _block.length(); i++) {
Node* n = _block.at(i);
Node_List* p = my_pack(n);
@ -1841,6 +1845,7 @@ void SuperWord::output() {
_igvn._worklist.push(vn);
if (vlen_in_bytes > max_vlen_in_bytes) {
max_vlen = vlen;
max_vlen_in_bytes = vlen_in_bytes;
}
#ifdef ASSERT
@ -1852,6 +1857,18 @@ void SuperWord::output() {
}
}
C->set_max_vector_size(max_vlen_in_bytes);
if (SuperWordLoopUnrollAnalysis) {
if (cl->has_passed_slp()) {
uint slp_max_unroll_factor = cl->slp_max_unroll();
if (slp_max_unroll_factor == max_vlen) {
NOT_PRODUCT(if (TraceSuperWordLoopUnrollAnalysis) tty->print_cr("vector loop(unroll=%d, len=%d)\n", max_vlen, max_vlen_in_bytes*BitsPerByte));
// For atomic unrolled loops which are vector mapped, instigate more unrolling.
cl->set_notpassed_slp();
C->set_major_progress();
cl->mark_do_unroll_only();
}
}
}
}
//------------------------------vector_opd---------------------------

View File

@ -241,7 +241,7 @@ class SuperWord : public ResourceObj {
void transform_loop(IdealLoopTree* lpt, bool do_optimization);
void unrolling_analysis(CountedLoopNode *cl, int &local_loop_unroll_factor);
void unrolling_analysis(int &local_loop_unroll_factor);
// Accessors for SWPointer
PhaseIdealLoop* phase() { return _phase; }

View File

@ -277,6 +277,8 @@ static ObsoleteFlag obsolete_jvm_flags[] = {
{ "ParallelGCRetainPLAB", JDK_Version::jdk(9), JDK_Version::jdk(10) },
{ "ThreadSafetyMargin", JDK_Version::jdk(9), JDK_Version::jdk(10) },
{ "LazyBootClassLoader", JDK_Version::jdk(9), JDK_Version::jdk(10) },
{ "StarvationMonitorInterval", JDK_Version::jdk(9), JDK_Version::jdk(10) },
{ "PreInflateSpin", JDK_Version::jdk(9), JDK_Version::jdk(10) },
{ NULL, JDK_Version(0), JDK_Version(0) }
};

View File

@ -1291,7 +1291,7 @@ public:
experimental(intx, hashCode, 5, \
"(Unstable) select hashCode generation algorithm") \
\
experimental(intx, WorkAroundNPTLTimedWaitHang, 1, \
experimental(intx, WorkAroundNPTLTimedWaitHang, 0, \
"(Unstable, Linux-specific) " \
"avoid NPTL-FUTEX hang pthread_cond_timedwait") \
\
@ -2717,6 +2717,12 @@ public:
develop(bool, EagerInitialization, false, \
"Eagerly initialize classes if possible") \
\
diagnostic(bool, LogTouchedMethods, false, \
"Log methods which have been ever touched in runtime") \
\
diagnostic(bool, PrintTouchedMethodsAtExit, false, \
"Print all methods that have been ever touched in runtime") \
\
develop(bool, TraceMethodReplacement, false, \
"Print when methods are replaced do to recompilation") \
\
@ -3282,9 +3288,6 @@ public:
develop(intx, ProfilerNodeSize, 1024, \
"Size in K to allocate for the Profile Nodes of each thread") \
\
product_pd(intx, PreInflateSpin, \
"Number of times to spin wait before inflation") \
\
/* gc parameters */ \
product(size_t, InitialHeapSize, 0, \
"Initial heap size (in bytes); zero means use ergonomics") \
@ -3725,9 +3728,6 @@ public:
develop(intx, LongCompileThreshold, 50, \
"Used with +TraceLongCompiles") \
\
product(intx, StarvationMonitorInterval, 200, \
"Pause between each check (in milliseconds)") \
\
/* recompilation */ \
product_pd(intx, CompileThreshold, \
"number of interpreted method invocations before (re-)compiling") \
@ -4080,9 +4080,6 @@ public:
develop(bool, TraceDefaultMethods, false, \
"Trace the default method processing steps") \
\
develop(bool, VerifyGenericSignatures, false, \
"Abort VM on erroneous or inconsistent generic signatures") \
\
diagnostic(bool, WhiteBoxAPI, false, \
"Enable internal testing APIs") \
\

View File

@ -330,6 +330,10 @@ void print_statistics() {
SystemDictionary::print();
}
if (LogTouchedMethods && PrintTouchedMethodsAtExit) {
Method::print_touched_methods(tty);
}
if (PrintBiasedLockingStatistics) {
BiasedLocking::print_counters();
}
@ -382,6 +386,10 @@ void print_statistics() {
if (PrintNMTStatistics) {
MemTracker::final_report(tty);
}
if (LogTouchedMethods && PrintTouchedMethodsAtExit) {
Method::print_touched_methods(tty);
}
}
#endif

View File

@ -63,6 +63,7 @@ Monitor* StringDedupQueue_lock = NULL;
Mutex* StringDedupTable_lock = NULL;
Monitor* CodeCache_lock = NULL;
Mutex* MethodData_lock = NULL;
Mutex* TouchedMethodLog_lock = NULL;
Mutex* RetData_lock = NULL;
Monitor* VMOperationQueue_lock = NULL;
Monitor* VMOperationRequest_lock = NULL;
@ -274,6 +275,7 @@ void mutex_init() {
def(Compile_lock , Mutex , nonleaf+3, true, Monitor::_safepoint_check_sometimes);
def(MethodData_lock , Mutex , nonleaf+3, false, Monitor::_safepoint_check_always);
def(TouchedMethodLog_lock , Mutex , nonleaf+3, false, Monitor::_safepoint_check_always);
def(MethodCompileQueue_lock , Monitor, nonleaf+4, true, Monitor::_safepoint_check_always);
def(Debug2_lock , Mutex , nonleaf+4, true, Monitor::_safepoint_check_never);

View File

@ -55,6 +55,7 @@ extern Monitor* StringDedupQueue_lock; // a lock on the string dedupli
extern Mutex* StringDedupTable_lock; // a lock on the string deduplication table
extern Monitor* CodeCache_lock; // a lock on the CodeCache, rank is special, use MutexLockerEx
extern Mutex* MethodData_lock; // a lock on installation of method data
extern Mutex* TouchedMethodLog_lock; // a lock on allocation of LogExecutedMethods info
extern Mutex* RetData_lock; // a lock on installation of RetData inside method data
extern Mutex* DerivedPointerTableGC_lock; // a lock to protect the derived pointer table
extern Monitor* VMOperationQueue_lock; // a lock on queue of vm_operations waiting to execute

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2015, 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
@ -103,8 +103,10 @@
// The knob* variables are effectively final. Once set they should
// never be modified hence. Consider using __read_mostly with GCC.
int ObjectMonitor::Knob_ExitRelease = 0;
int ObjectMonitor::Knob_Verbose = 0;
int ObjectMonitor::Knob_VerifyInUse = 0;
int ObjectMonitor::Knob_VerifyMatch = 0;
int ObjectMonitor::Knob_SpinLimit = 5000; // derived by an external tool -
static int Knob_LogSpins = 0; // enable jvmstat tally for spins
static int Knob_HandOff = 0;
@ -251,24 +253,6 @@ static volatile int InitDone = 0;
// -----------------------------------------------------------------------------
// Enter support
bool ObjectMonitor::try_enter(Thread* THREAD) {
if (THREAD != _owner) {
if (THREAD->is_lock_owned ((address)_owner)) {
assert(_recursions == 0, "internal state error");
_owner = THREAD;
_recursions = 1;
return true;
}
if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
return false;
}
return true;
} else {
_recursions++;
return true;
}
}
void NOINLINE ObjectMonitor::enter(TRAPS) {
// The following code is ordered to check the most common cases first
// and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors.
@ -2272,7 +2256,7 @@ void ObjectWaiter::wait_reenter_end(ObjectMonitor * const mon) {
}
inline void ObjectMonitor::AddWaiter(ObjectWaiter* node) {
assert(node != NULL, "should not dequeue NULL node");
assert(node != NULL, "should not add NULL node");
assert(node->_prev == NULL, "node already in list");
assert(node->_next == NULL, "node already in list");
// put node at end of queue (circular doubly linked list)
@ -2407,8 +2391,8 @@ static int kvGetInt(char * kvList, const char * Key, int Default) {
char * v = kvGet(kvList, Key);
int rslt = v ? ::strtol(v, NULL, 0) : Default;
if (Knob_ReportSettings && v != NULL) {
::printf (" SyncKnob: %s %d(%d)\n", Key, rslt, Default) ;
::fflush(stdout);
tty->print_cr("INFO: SyncKnob: %s %d(%d)", Key, rslt, Default) ;
tty->flush();
}
return rslt;
}
@ -2442,8 +2426,10 @@ void ObjectMonitor::DeferredInitialize() {
#define SETKNOB(x) { Knob_##x = kvGetInt(knobs, #x, Knob_##x); }
SETKNOB(ReportSettings);
SETKNOB(ExitRelease);
SETKNOB(Verbose);
SETKNOB(VerifyInUse);
SETKNOB(VerifyMatch);
SETKNOB(FixedSpin);
SETKNOB(SpinLimit);
SETKNOB(SpinBase);
@ -2477,7 +2463,9 @@ void ObjectMonitor::DeferredInitialize() {
if (os::is_MP()) {
BackOffMask = (1 << Knob_SpinBackOff) - 1;
if (Knob_ReportSettings) ::printf("BackOffMask=%X\n", BackOffMask);
if (Knob_ReportSettings) {
tty->print_cr("INFO: BackOffMask=0x%X", BackOffMask);
}
// CONSIDER: BackOffMask = ROUNDUP_NEXT_POWER2 (ncpus-1)
} else {
Knob_SpinLimit = 0;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2015, 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
@ -196,8 +196,10 @@ class ObjectMonitor {
static PerfCounter * _sync_Deflations;
static PerfLongVariable * _sync_MonExtant;
static int Knob_ExitRelease;
static int Knob_Verbose;
static int Knob_VerifyInUse;
static int Knob_VerifyMatch;
static int Knob_SpinLimit;
void* operator new (size_t size) throw() {
@ -317,7 +319,6 @@ class ObjectMonitor {
void print();
#endif
bool try_enter(TRAPS);
void enter(TRAPS);
void exit(bool not_suspended, TRAPS);
void wait(jlong millis, bool interruptable, TRAPS);
@ -354,14 +355,14 @@ class ObjectMonitor {
#undef TEVENT
#define TEVENT(nom) { if (SyncVerbose) FEVENT(nom); }
#define FEVENT(nom) \
{ \
static volatile int ctr = 0; \
int v = ++ctr; \
if ((v & (v - 1)) == 0) { \
::printf(#nom " : %d\n", v); \
::fflush(stdout); \
} \
#define FEVENT(nom) \
{ \
static volatile int ctr = 0; \
int v = ++ctr; \
if ((v & (v - 1)) == 0) { \
tty->print_cr("INFO: " #nom " : %d", v); \
tty->flush(); \
} \
}
#undef TEVENT

View File

@ -40,6 +40,7 @@
#include "runtime/stubRoutines.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/vframe.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
#include "utilities/preserveException.hpp"
@ -927,8 +928,9 @@ static void InduceScavenge(Thread * Self, const char * Whence) {
if (ForceMonitorScavenge == 0 && Atomic::xchg (1, &ForceMonitorScavenge) == 0) {
if (ObjectMonitor::Knob_Verbose) {
::printf ("Monitor scavenge - Induced STW @%s (%d)\n", Whence, ForceMonitorScavenge) ;
::fflush(stdout);
tty->print_cr("INFO: Monitor scavenge - Induced STW @%s (%d)",
Whence, ForceMonitorScavenge) ;
tty->flush();
}
// Induce a 'null' safepoint to scavenge monitors
// Must VM_Operation instance be heap allocated as the op will be enqueue and posted
@ -937,8 +939,9 @@ static void InduceScavenge(Thread * Self, const char * Whence) {
VMThread::execute(new VM_ForceAsyncSafepoint());
if (ObjectMonitor::Knob_Verbose) {
::printf ("Monitor scavenge - STW posted @%s (%d)\n", Whence, ForceMonitorScavenge) ;
::fflush(stdout);
tty->print_cr("INFO: Monitor scavenge - STW posted @%s (%d)",
Whence, ForceMonitorScavenge) ;
tty->flush();
}
}
}
@ -1603,10 +1606,11 @@ void ObjectSynchronizer::deflate_idle_monitors() {
// Consider: audit gFreeList to ensure that gMonitorFreeCount and list agree.
if (ObjectMonitor::Knob_Verbose) {
::printf("Deflate: InCirc=%d InUse=%d Scavenged=%d ForceMonitorScavenge=%d : pop=%d free=%d\n",
nInCirculation, nInuse, nScavenged, ForceMonitorScavenge,
gMonitorPopulation, gMonitorFreeCount);
::fflush(stdout);
tty->print_cr("INFO: Deflate: InCirc=%d InUse=%d Scavenged=%d "
"ForceMonitorScavenge=%d : pop=%d free=%d",
nInCirculation, nInuse, nScavenged, ForceMonitorScavenge,
gMonitorPopulation, gMonitorFreeCount);
tty->flush();
}
ForceMonitorScavenge = 0; // Reset
@ -1643,6 +1647,14 @@ class ReleaseJavaMonitorsClosure: public MonitorClosure {
ReleaseJavaMonitorsClosure(Thread* thread) : THREAD(thread) {}
void do_monitor(ObjectMonitor* mid) {
if (mid->owner() == THREAD) {
if (ObjectMonitor::Knob_VerifyMatch != 0) {
Handle obj((oop) mid->object());
tty->print("INFO: unexpected locked object:");
javaVFrame::print_locked_object_class_name(tty, obj, "locked");
fatal(err_msg("exiting JavaThread=" INTPTR_FORMAT
" unexpectedly owns ObjectMonitor=" INTPTR_FORMAT,
THREAD, mid));
}
(void)mid->complete_exit(CHECK);
}
}

View File

@ -1802,14 +1802,25 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
assert(!this->has_pending_exception(), "ensure_join should have cleared");
// 6282335 JNI DetachCurrentThread spec states that all Java monitors
// held by this thread must be released. A detach operation must only
// get here if there are no Java frames on the stack. Therefore, any
// owned monitors at this point MUST be JNI-acquired monitors which are
// pre-inflated and in the monitor cache.
// held by this thread must be released. The spec does not distinguish
// between JNI-acquired and regular Java monitors. We can only see
// regular Java monitors here if monitor enter-exit matching is broken.
//
// ensure_join() ignores IllegalThreadStateExceptions, and so does this.
if (exit_type == jni_detach && JNIDetachReleasesMonitors) {
assert(!this->has_last_Java_frame(), "detaching with Java frames?");
// Optionally release any monitors for regular JavaThread exits. This
// is provided as a work around for any bugs in monitor enter-exit
// matching. This can be expensive so it is not enabled by default.
// ObjectMonitor::Knob_ExitRelease is a superset of the
// JNIDetachReleasesMonitors option.
//
// ensure_join() ignores IllegalThreadStateExceptions, and so does
// ObjectSynchronizer::release_monitors_owned_by_thread().
if ((exit_type == jni_detach && JNIDetachReleasesMonitors) ||
ObjectMonitor::Knob_ExitRelease) {
// Sanity check even though JNI DetachCurrentThread() would have
// returned JNI_ERR if there was a Java frame. JavaThread exit
// should be done executing Java code by the time we get here.
assert(!this->has_last_Java_frame(),
"should not have a Java frame when detaching or exiting");
ObjectSynchronizer::release_monitors_owned_by_thread(this);
assert(!this->has_pending_exception(), "release_monitors should have cleared");
}

View File

@ -144,7 +144,7 @@ GrowableArray<MonitorInfo*>* javaVFrame::locked_monitors() {
return result;
}
static void print_locked_object_class_name(outputStream* st, Handle obj, const char* lock_state) {
void javaVFrame::print_locked_object_class_name(outputStream* st, Handle obj, const char* lock_state) {
if (obj.not_null()) {
st->print("\t- %s <" INTPTR_FORMAT "> ", lock_state, (address)obj());
if (obj->klass() == SystemDictionary::Class_klass()) {
@ -160,17 +160,29 @@ static void print_locked_object_class_name(outputStream* st, Handle obj, const c
void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) {
ResourceMark rm;
// If this is the first frame, and java.lang.Object.wait(...) then print out the receiver.
// If this is the first frame and it is java.lang.Object.wait(...)
// then print out the receiver. Locals are not always available,
// e.g., compiled native frames have no scope so there are no locals.
if (frame_count == 0) {
if (method()->name() == vmSymbols::wait_name() &&
method()->method_holder()->name() == vmSymbols::java_lang_Object()) {
const char *wait_state = "waiting on"; // assume we are waiting
// If earlier in the output we reported java.lang.Thread.State ==
// "WAITING (on object monitor)" and now we report "waiting on", then
// we are still waiting for notification or timeout. Otherwise if
// we earlier reported java.lang.Thread.State == "BLOCKED (on object
// monitor)", then we are actually waiting to re-lock the monitor.
// At this level we can't distinguish the two cases to report
// "waited on" rather than "waiting on" for the second case.
StackValueCollection* locs = locals();
if (!locs->is_empty()) {
StackValue* sv = locs->at(0);
if (sv->type() == T_OBJECT) {
Handle o = locs->at(0)->get_obj();
print_locked_object_class_name(st, o, "waiting on");
print_locked_object_class_name(st, o, wait_state);
}
} else {
st->print_cr("\t- %s <no object reference available>", wait_state);
}
} else if (thread()->current_park_blocker() != NULL) {
oop obj = thread()->current_park_blocker();
@ -179,8 +191,8 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) {
}
}
// Print out all monitors that we have locked or are trying to lock
// Print out all monitors that we have locked, or are trying to lock,
// including re-locking after being notified or timing out in a wait().
GrowableArray<MonitorInfo*>* mons = monitors();
if (!mons->is_empty()) {
bool found_first_monitor = false;
@ -202,14 +214,14 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) {
if (monitor->owner() != NULL) {
// the monitor is associated with an object, i.e., it is locked
// First, assume we have the monitor locked. If we haven't found an
// owned monitor before and this is the first frame, then we need to
// see if we have completed the lock or we are blocked trying to
// acquire it - we can only be blocked if the monitor is inflated
markOop mark = NULL;
const char *lock_state = "locked"; // assume we have the monitor locked
if (!found_first_monitor && frame_count == 0) {
// If this is the first frame and we haven't found an owned
// monitor before, then we need to see if we have completed
// the lock or if we are blocked trying to acquire it. Only
// an inflated monitor that is first on the monitor list in
// the first frame can block us on a monitor enter.
mark = monitor->owner()->mark();
if (mark->has_monitor() &&
( // we have marked ourself as pending on this monitor
@ -219,13 +231,35 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) {
)) {
lock_state = "waiting to lock";
} else {
mark = NULL; // Disable printing below
// We own the monitor which is not as interesting so
// disable the extra printing below.
mark = NULL;
}
} else if (frame_count != 0 && ObjectMonitor::Knob_Verbose) {
// This is not the first frame so we either own this monitor
// or we owned the monitor before and called wait(). Because
// wait() could have been called on any monitor in a lower
// numbered frame on the stack, we have to check all the
// monitors on the list for this frame.
// Note: Only enable this new output line in verbose mode
// since existing tests are not ready for it.
mark = monitor->owner()->mark();
if (mark->has_monitor() &&
( // we have marked ourself as pending on this monitor
mark->monitor() == thread()->current_pending_monitor() ||
// we are not the owner of this monitor
!mark->monitor()->is_entered(thread())
)) {
lock_state = "waiting to re-lock in wait()";
} else {
// We own the monitor which is not as interesting so
// disable the extra printing below.
mark = NULL;
}
}
print_locked_object_class_name(st, monitor->owner(), lock_state);
if (Verbose && mark != NULL) {
// match with format above, replacing "-" with " ".
st->print("\t lockbits=");
if (ObjectMonitor::Knob_Verbose && mark != NULL) {
st->print("\t- lockbits=");
mark->print_on(st);
st->cr();
}

View File

@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@ -135,7 +135,8 @@ class javaVFrame: public vframe {
// Return an array of monitors locked by this frame in the youngest to oldest order
GrowableArray<MonitorInfo*>* locked_monitors();
// printing used during stack dumps
// printing used during stack dumps and diagnostics
static void print_locked_object_class_name(outputStream* st, Handle obj, const char* lock_state);
void print_lock_info_on(outputStream* st, int frame_count);
void print_lock_info(int frame_count) { print_lock_info_on(tty, frame_count); }

View File

@ -101,6 +101,7 @@
template(WhiteBoxOperation) \
template(ClassLoaderStatsOperation) \
template(DumpHashtable) \
template(DumpTouchedMethods) \
template(MarkActiveNMethods) \
template(PrintCompileQueue) \
template(PrintCodeList) \

View File

@ -74,6 +74,7 @@ void DCmdRegistrant::register_dcmds(){
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompileQueueDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeListDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeCacheDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<TouchedMethodsDCmd>(full_export, true, false));
// Enhanced JMX Agent Support
// These commands won't be exported via the DiagnosticCommandMBean until an
@ -808,3 +809,35 @@ int ClassHierarchyDCmd::num_arguments() {
}
#endif
class VM_DumpTouchedMethods : public VM_Operation {
private:
outputStream* _out;
public:
VM_DumpTouchedMethods(outputStream* out) {
_out = out;
}
virtual VMOp_Type type() const { return VMOp_DumpTouchedMethods; }
virtual void doit() {
Method::print_touched_methods(_out);
}
};
TouchedMethodsDCmd::TouchedMethodsDCmd(outputStream* output, bool heap) :
DCmdWithParser(output, heap)
{}
void TouchedMethodsDCmd::execute(DCmdSource source, TRAPS) {
if (!UnlockDiagnosticVMOptions) {
output()->print_cr("VM.touched_methods command requires -XX:+UnlockDiagnosticVMOptions");
return;
}
VM_DumpTouchedMethods dumper(output());
VMThread::execute(&dumper);
}
int TouchedMethodsDCmd::num_arguments() {
return 0;
}

View File

@ -35,6 +35,7 @@
#include "services/diagnosticFramework.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
#include "oops/method.hpp"
class HelpDCmd : public DCmdWithParser {
protected:
@ -341,6 +342,22 @@ public:
virtual void execute(DCmdSource source, TRAPS);
};
class TouchedMethodsDCmd : public DCmdWithParser {
public:
TouchedMethodsDCmd(outputStream* output, bool heap);
static const char* name() {
return "VM.print_touched_methods";
}
static const char* description() {
return "Print all methods that have ever been touched during the lifetime of this JVM.";
}
static const char* impact() {
return "Medium: Depends on Java content.";
}
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
};
// See also: thread_dump in attachListener.cpp
class ThreadDumpDCmd : public DCmdWithParser {
protected:

View File

@ -61,12 +61,12 @@ abstract public class TestAESBase {
final Random random = Utils.getRandomInstance();
Cipher cipher;
Cipher dCipher;
AlgorithmParameters algParams;
AlgorithmParameters algParams = null;
SecretKey key;
GCMParameterSpec gcm_spec;
byte[] aad;
byte[] aad = { 0x11, 0x22, 0x33, 0x44, 0x55 };
int tlen = 12;
byte[] iv;
byte[] iv = new byte[16];
static int numThreads = 0;
int threadId;
@ -80,7 +80,10 @@ abstract public class TestAESBase {
public void prepare() {
try {
System.out.println("\nalgorithm=" + algorithm + ", mode=" + mode + ", paddingStr=" + paddingStr + ", msgSize=" + msgSize + ", keySize=" + keySize + ", noReinit=" + noReinit + ", checkOutput=" + checkOutput + ", encInputOffset=" + encInputOffset + ", encOutputOffset=" + encOutputOffset + ", decOutputOffset=" + decOutputOffset + ", lastChunkSize=" +lastChunkSize );
System.out.println("\nalgorithm=" + algorithm + ", mode=" + mode + ", paddingStr=" + paddingStr +
", msgSize=" + msgSize + ", keySize=" + keySize + ", noReinit=" + noReinit +
", checkOutput=" + checkOutput + ", encInputOffset=" + encInputOffset + ", encOutputOffset=" +
encOutputOffset + ", decOutputOffset=" + decOutputOffset + ", lastChunkSize=" +lastChunkSize );
if (encInputOffset % ALIGN != 0 || encOutputOffset % ALIGN != 0 || decOutputOffset % ALIGN !=0 )
testingMisalignment = true;
@ -101,22 +104,24 @@ abstract public class TestAESBase {
cipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE");
dCipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE");
// CBC init
if (mode.equals("CBC")) {
int ivLen = (algorithm.equals("AES") ? 16 : algorithm.equals("DES") ? 8 : 0);
IvParameterSpec initVector = new IvParameterSpec(new byte[ivLen]);
IvParameterSpec initVector = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, initVector);
} else if (mode.equals("GCM")) {
iv = new byte[64];
random.nextBytes(iv);
aad = new byte[5];
random.nextBytes(aad);
gcm_init();
} else {
algParams = cipher.getParameters();
dCipher.init(Cipher.DECRYPT_MODE, key, initVector);
// GCM init
} else if (mode.equals("GCM")) {
gcm_init(true);
gcm_init(false);
// ECB init
} else {
cipher.init(Cipher.ENCRYPT_MODE, key, algParams);
dCipher.init(Cipher.DECRYPT_MODE, key, algParams);
}
algParams = cipher.getParameters();
dCipher.init(Cipher.DECRYPT_MODE, key, algParams);
if (threadId == 0) {
childShowCipher();
}
@ -198,11 +203,18 @@ abstract public class TestAESBase {
abstract void childShowCipher();
void gcm_init() throws Exception {
tlen = 12;
void gcm_init(boolean encrypt) throws Exception {
gcm_spec = new GCMParameterSpec(tlen * 8, iv);
cipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE");
cipher.init(Cipher.ENCRYPT_MODE, key, gcm_spec);
cipher.update(aad);
if (encrypt) {
// Get a new instance everytime because of reuse IV restrictions
cipher = Cipher.getInstance(algorithm + "/" + mode + "/" + paddingStr, "SunJCE");
cipher.init(Cipher.ENCRYPT_MODE, key, gcm_spec);
cipher.updateAAD(aad);
} else {
dCipher.init(Cipher.DECRYPT_MODE, key, gcm_spec);
dCipher.updateAAD(aad);
}
}
}

View File

@ -32,7 +32,11 @@ public class TestAESDecode extends TestAESBase {
@Override
public void run() {
try {
if (!noReinit) dCipher.init(Cipher.DECRYPT_MODE, key, algParams);
if (mode.equals("GCM")) {
gcm_init(false);
} else if (!noReinit) {
dCipher.init(Cipher.DECRYPT_MODE, key, algParams);
}
decode = new byte[decodeLength];
if (testingMisalignment) {
int tempSize = dCipher.update(encode, encOutputOffset, (decodeMsgSize - lastChunkSize), decode, decOutputOffset);

View File

@ -33,7 +33,7 @@ public class TestAESEncode extends TestAESBase {
public void run() {
try {
if (mode.equals("GCM")) {
gcm_init();
gcm_init(true);
} else if (!noReinit) {
cipher.init(Cipher.ENCRYPT_MODE, key, algParams);
}

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 2015, 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 8025692
* @modules java.base/sun.misc
* java.management
* @library /testlibrary
* @compile TestLogTouchedMethods.java PrintTouchedMethods.java
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+LogTouchedMethods PrintTouchedMethods
*/
import java.io.File;
import java.util.List;
import jdk.test.lib.*;
public class PrintTouchedMethods {
public static void main(String args[]) throws Exception {
String[] javaArgs1 = {"-XX:-UnlockDiagnosticVMOptions", "-XX:+LogTouchedMethods", "-XX:+PrintTouchedMethodsAtExit", "TestLogTouchedMethods"};
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(javaArgs1);
// UnlockDiagnostic turned off, should fail
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("Error: VM option 'LogTouchedMethods' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.");
output.shouldContain("Error: Could not create the Java Virtual Machine.");
String[] javaArgs2 = {"-XX:+UnlockDiagnosticVMOptions", "-XX:+LogTouchedMethods", "-XX:+PrintTouchedMethodsAtExit", "TestLogTouchedMethods"};
pb = ProcessTools.createJavaProcessBuilder(javaArgs2);
output = new OutputAnalyzer(pb.start());
// check order:
// 1 "# Method::print_touched_methods version 1" is the first in first line
// 2 should contain TestLogMethods.methodA:()V
// 3 should not contain TestLogMethods.methodB:()V
// Repeat above for another run with -Xint
List<String> lines = output.asLines();
if (lines.size() < 1) {
throw new Exception("Empty output");
}
String first = lines.get(0);
if (!first.equals("# Method::print_touched_methods version 1")) {
throw new Exception("First line mismatch");
}
output.shouldContain("TestLogTouchedMethods.methodA:()V");
output.shouldNotContain("TestLogTouchedMethods.methodB:()V");
output.shouldHaveExitValue(0);
String[] javaArgs3 = {"-XX:+UnlockDiagnosticVMOptions", "-Xint", "-XX:+LogTouchedMethods", "-XX:+PrintTouchedMethodsAtExit", "TestLogTouchedMethods"};
pb = ProcessTools.createJavaProcessBuilder(javaArgs3);
output = new OutputAnalyzer(pb.start());
lines = output.asLines();
if (lines.size() < 1) {
throw new Exception("Empty output");
}
first = lines.get(0);
if (!first.equals("# Method::print_touched_methods version 1")) {
throw new Exception("First line mismatch");
}
output.shouldContain("TestLogTouchedMethods.methodA:()V");
output.shouldNotContain("TestLogTouchedMethods.methodB:()V");
output.shouldHaveExitValue(0);
// Test jcmd PrintTouchedMethods VM.print_touched_methods
String pid = Integer.toString(ProcessTools.getProcessId());
pb = new ProcessBuilder();
pb.command(new String[] {JDKToolFinder.getJDKTool("jcmd"), pid, "VM.print_touched_methods"});
output = new OutputAnalyzer(pb.start());
try {
output.shouldContain("PrintTouchedMethods.main:([Ljava/lang/String;)V");
} catch (RuntimeException e) {
output.shouldContain("Unknown diagnostic command");
}
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2015, 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.
*/
/* used by PrintTouchedMethods.java */
public class TestLogTouchedMethods {
public static void main(String[] args) {
new TestLogTouchedMethods().methodA();
}
public void methodA() {} // called
public void methodB() {} // this should not be called
}

View File

@ -46,16 +46,8 @@ public class CreateCoredumpOnCrash {
runTest("-XX:-CreateCoredumpOnCrash").shouldContain("CreateCoredumpOnCrash turned off, no core file dumped");
if (Platform.isWindows()) {
runTest("-XX:+CreateCoredumpOnCrash").shouldContain("Core dump will be written. Default location");
// The old CreateMinidumpOnCrash option should still work
runTest("-XX:+CreateMinidumpOnCrash").shouldContain("Core dump will be written. Default location");
runTest("-XX:-CreateMinidumpOnCrash").shouldContain("CreateCoredumpOnCrash turned off, no core file dumped");
if (Platform.isDebugBuild()) {
// Make sure we create dumps on Windows debug builds by default
runTest("-Ddummyopt=false").shouldContain("Core dump will be written. Default location");
}
} else {
runTest("-XX:+CreateCoredumpOnCrash").shouldNotContain("CreateCoredumpOnCrash turned off, no core file dumped");
}

View File

@ -45,6 +45,7 @@ public class TestOnError {
// Execute the VM so that a
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-XX:-TransmitErrorReport",
"-XX:-CreateCoredumpOnCrash",
"-XX:ErrorHandlerTest=12", // trigger potential SEGV
"-XX:OnError=echo " + msg,
TestOnError.class.getName());

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2015, 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 8130669
* @summary VM prohibits <clinit> methods with return values
* @compile ignoredClinit.jasm
* @compile badInit.jasm
* @run main/othervm -Xverify:all BadInitMethod
*/
// Test that a non-void <clinit> method does not cause an exception to be
// thrown. But that a non-void <init> method causes a ClassFormatError
// exception.
public class BadInitMethod {
public static void main(String args[]) throws Throwable {
System.out.println("Regression test for bug 8130669");
try {
Class newClass = Class.forName("ignoredClinit");
} catch (java.lang.Throwable e) {
throw new RuntimeException("Unexpected exception: " + e.getMessage());
}
try {
Class newClass = Class.forName("badInit");
throw new RuntimeException("Expected ClassFormatError exception not thrown");
} catch (java.lang.ClassFormatError e) {
System.out.println("Test BadInitMethod passed");
}
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2015, 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 8130183
* @summary For InnerClasses attribute, VM permits inner_class_info_index value of zero
* @compile badEnclMthd.jcod
* @run main/othervm -Xverify:all EnclosingMethod
*/
// Test that an EnclosingMethod attribute with the value of 0 causes a ClassFormatError.
public class EnclosingMethod {
public static void main(String args[]) throws Throwable {
System.out.println("Regression test for bug 8130183");
try {
Class newClass = Class.forName("badEnclMthd");
throw new RuntimeException("Expected ClassFormatError exception not thrown");
} catch (java.lang.ClassFormatError e) {
System.out.println("Test EnclosingMethod passed");
}
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2015, 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.
*
*/
// Source: badEnclMthd
class badEnclMthd {
0xCAFEBABE;
0; // minor version
50; // major version
[] { // Constant Pool
; // first element is empty
Utf8 "badEnclMthd"; // #1
class #1; // #2
Utf8 "java/lang/Object"; // #3
class #3; // #4
Utf8 "InnerClasses"; // #5
Utf8 "badEnclMthd"; // #6
class #6; // #7
Utf8 "badEnclMthd"; // #8
class #8; // #9
} // Constant Pool
0x0001; // access public
#2;// this_cpx
#4;// super_cpx
[] { // interfaces
} // interfaces
[] { // fields
} // fields
[] { // methods
} // methods
[] { // attributes
Attr(#5) { // InnerClasses
[] { // InnerClasses
#0 #2 #6 1; // Bad inner_class_info_index of 0 !!!
#9 #0 #8 1;
}
} // end InnerClasses
;
} // attributes
} // end class badEnclMthd

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2015, 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.
*
*/
super public class badInit
version 52:0
{
// This <init> method has a non-void signature. It should cause a
// ClassFormatError exception.
Method "<init>":"(I)I"
stack 1 locals 2
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
iconst_4;
ireturn;
}
public static Method main:"([Ljava/lang/String;)V"
stack 0 locals 1
{
return;
}
} // end Class badInit

View File

@ -19,28 +19,21 @@
* 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 8076421
* @summary Test of hprof option crashes Zero
* @compile cpu002.java
* @run main/othervm -Xrunhprof:cpu=times,file=cpu002.hprof.out cpu002
*/
// This class contains a <clinit> method with signature: ()I. The JVM should
// not complain about this because methods named <clinit> that have arguments
// and/or are not void should be ignored by the JVM.
import java.io.*;
public class ignoredClinit version 51:0
{
public class cpu002 {
public static final int PASSED = 0;
public static final int FAILED = 2;
public static final int JCK_STATUS_BASE = 95;
public static void main (String argv[]) {
System.exit(run(argv,System.out) + JCK_STATUS_BASE);
public static Method "<clinit>":"()I"
stack 1 locals 1
{
iconst_0;
ireturn;
}
public static int run(String argv[], PrintStream out) {
return PASSED;
}
}
} // end Class ignoredClinit

View File

@ -60,6 +60,7 @@ public class ReserveMemory {
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
"-XX:-TransmitErrorReport",
"-XX:-CreateCoredumpOnCrash",
"-Xmx32m",
"ReserveMemory",
"test");

View File

@ -34,6 +34,7 @@ import jdk.test.lib.apps.LingeredApp;
* @test
* @library /../../test/lib/share/classes
* @library /testlibrary
* @ignore 8129971
* @build jdk.test.lib.*
* @build jdk.test.lib.apps.*
* @run main TestStackTrace