Merge
This commit is contained in:
commit
0b717619ae
@ -10,3 +10,4 @@
|
||||
.igv.log
|
||||
^.hgtip
|
||||
.DS_Store
|
||||
\.class$
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -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
|
||||
|
@ -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 %{
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 ;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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'
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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.");
|
||||
|
||||
{
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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("??");
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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 ); }
|
||||
|
@ -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");
|
||||
|
@ -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() )
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -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---------------------------
|
||||
|
@ -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; }
|
||||
|
@ -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) }
|
||||
};
|
||||
|
||||
|
@ -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") \
|
||||
\
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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); }
|
||||
|
||||
|
@ -101,6 +101,7 @@
|
||||
template(WhiteBoxOperation) \
|
||||
template(ClassLoaderStatsOperation) \
|
||||
template(DumpHashtable) \
|
||||
template(DumpTouchedMethods) \
|
||||
template(MarkActiveNMethods) \
|
||||
template(PrintCompileQueue) \
|
||||
template(PrintCodeList) \
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
101
hotspot/test/runtime/CommandLine/PrintTouchedMethods.java
Normal file
101
hotspot/test/runtime/CommandLine/PrintTouchedMethods.java
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
32
hotspot/test/runtime/CommandLine/TestLogTouchedMethods.java
Normal file
32
hotspot/test/runtime/CommandLine/TestLogTouchedMethods.java
Normal 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
|
||||
}
|
@ -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");
|
||||
}
|
||||
|
@ -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());
|
||||
|
54
hotspot/test/runtime/classFileParserBug/BadInitMethod.java
Normal file
54
hotspot/test/runtime/classFileParserBug/BadInitMethod.java
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
45
hotspot/test/runtime/classFileParserBug/EnclosingMethod.java
Normal file
45
hotspot/test/runtime/classFileParserBug/EnclosingMethod.java
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
60
hotspot/test/runtime/classFileParserBug/badEnclMthd.jcod
Normal file
60
hotspot/test/runtime/classFileParserBug/badEnclMthd.jcod
Normal 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
|
47
hotspot/test/runtime/classFileParserBug/badInit.jasm
Normal file
47
hotspot/test/runtime/classFileParserBug/badInit.jasm
Normal 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
|
@ -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
|
@ -60,6 +60,7 @@ public class ReserveMemory {
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"-XX:-TransmitErrorReport",
|
||||
"-XX:-CreateCoredumpOnCrash",
|
||||
"-Xmx32m",
|
||||
"ReserveMemory",
|
||||
"test");
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user