--- a/hotspot/.hgignore Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/.hgignore Thu Jul 23 15:28:52 2015 -0700
@@ -10,3 +10,4 @@
.igv.log
^.hgtip
.DS_Store
+\.class$
--- a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -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, StackShadowPages, 4 DEBUG_ONLY(+5));
-define_pd_global(intx, PreInflateSpin, 10);
-
define_pd_global(bool, RewriteBytecodes, true);
define_pd_global(bool, RewriteFrequentPairs, true);
--- a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
// 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_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();
--- a/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
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);
}
--- a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -47,8 +47,6 @@
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);
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -3433,6 +3433,376 @@
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
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -677,6 +677,31 @@
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
//
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -423,6 +423,13 @@
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
--- a/hotspot/src/cpu/ppc/vm/ppc.ad Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/ppc/vm/ppc.ad Thu Jul 23 15:28:52 2015 -0700
@@ -10930,7 +10930,7 @@
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 %{
--- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -2053,6 +2053,79 @@
__ 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 @@
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:
--- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -668,7 +668,7 @@
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 @@
// 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.
--- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -198,6 +198,10 @@
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 @@
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.
--- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -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, 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);
--- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
// 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_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 ;
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -308,7 +308,7 @@
}
} 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);
}
--- a/hotspot/src/cpu/x86/vm/globals_x86.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -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, 4 DEBUG_ONLY(+5));
#endif // AMD64
-define_pd_global(intx, PreInflateSpin, 10);
-
define_pd_global(bool, RewriteBytecodes, true);
define_pd_global(bool, RewriteFrequentPairs, true);
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -1781,6 +1781,7 @@
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 @@
}
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 @@
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 @@
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
--- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -2456,7 +2456,8 @@
// 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;
--- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -2780,6 +2780,7 @@
const XMMRegister xmm_temp7 = xmm7;
__ enter();
+ handleSOERegisters(true); // Save registers
__ movptr(state, state_param);
__ movptr(subkeyH, subkeyH_param);
@@ -2883,6 +2884,7 @@
__ 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;
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -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_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_normal_entry(bool synchronized) {
// determine code generation flags
- bool inc_counter = UseCompiler || CountCompiledCalls;
+ bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
// rbx,: Method*
// rsi: sender sp
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
// 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_normal_entry(bool synchronized) {
// determine code generation flags
- bool inc_counter = UseCompiler || CountCompiledCalls;
+ bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;
// ebx: Method*
// r13: sender sp
--- a/hotspot/src/cpu/zero/vm/globals_zero.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/cpu/zero/vm/globals_zero.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -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, 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);
--- a/hotspot/src/os/windows/vm/os_windows.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -3740,15 +3740,6 @@
"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;
- }
}
--- a/hotspot/src/share/tools/LogCompilation/Makefile Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/tools/LogCompilation/Makefile Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
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
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/BasicLogEvent.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/BasicLogEvent.java Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
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 @@
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);
}
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/CallSite.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/CallSite.java Thu Jul 23 15:28:52 2015 -0700
@@ -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.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 void print(PrintStream stream) {
- print(stream, 0);
+ print(stream, 0, true, false);
}
void emit(PrintStream stream, int indent) {
@@ -92,21 +170,14 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 {
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Compilation.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Compilation.java Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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;
}
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCleanupReader.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCleanupReader.java Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
* 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 {
-class LogCleanupReader extends Reader {
private Reader reader;
private char[] buffer = new char[4096];
@@ -55,32 +54,38 @@
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;
}
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java Thu Jul 23 15:28:52 2015 -0700
@@ -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 (a.equals("-n")) {
+ sort = LogParser.sortByNameAndStart;
index++;
- } else if (args[index].equals("-n")) {
- defaultSort = LogParser.sortByNameAndStart;
+ } else if (a.equals("-s")) {
+ sort = LogParser.sortByStart;
index++;
- } else if (args[index].equals("-s")) {
- defaultSort = LogParser.sortByStart;
+ } else if (a.equals("-t")) {
+ printTimeStamps = true;
index++;
- } else if (args[index].equals("-c")) {
+ } 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 @@
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 @@
}
}
+ /**
+ * 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 @@
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 @@
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 @@
}
}
}
+
+ /**
+ * 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();
+ }
+ }
+
}
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogEvent.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogEvent.java Thu Jul 23 15:28:52 2015 -0700
@@ -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);
}
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java Thu Jul 23 15:28:52 2015 -0700
@@ -33,30 +33,269 @@
import java.io.Reader;
import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Comparator;
+import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedHashMap;
-import java.util.Stack;
+import java.util.regex.Pattern;
+
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
+
import org.xml.sax.Attributes;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
import org.xml.sax.helpers.DefaultHandler;
-public class LogParser extends DefaultHandler implements ErrorHandler, Constants {
+/**
+ * A SAX parser for HotSpot compilation logs. The bulk of the parsing and event
+ * maintenance work is done in the {@link #startElement(String,String,String,Attributes)}
+ * and {@link #endElement(String,String,String)} methods.
+ */
+public class LogParser extends DefaultHandler implements ErrorHandler {
+
+ static final Pattern spacePattern = Pattern.compile(" ");
- static final HashMap<String, String> typeMap;
+ /**
+ * Map internal array type descriptors to Java names.
+ */
+ static final HashMap<String, String> type2printableMap;
+
+ /**
+ * Map Java primitive type names to internal type descriptors.
+ */
+ static final HashMap<String, String> type2vmtypeMap;
+
static {
- typeMap = new HashMap<String, String>();
- typeMap.put("[I", "int[]");
- typeMap.put("[C", "char[]");
- typeMap.put("[Z", "boolean[]");
- typeMap.put("[L", "Object[]");
- typeMap.put("[B", "byte[]");
+ type2printableMap = new HashMap<>();
+ type2printableMap.put("[I", "int[]");
+ type2printableMap.put("[C", "char[]");
+ type2printableMap.put("[Z", "boolean[]");
+ type2printableMap.put("[L", "Object[]");
+ type2printableMap.put("[B", "byte[]");
+
+ type2vmtypeMap = new HashMap<>();
+ type2vmtypeMap.put("void", "V");
+ type2vmtypeMap.put("boolean", "Z");
+ type2vmtypeMap.put("byte", "B");
+ type2vmtypeMap.put("char", "C");
+ type2vmtypeMap.put("short", "S");
+ type2vmtypeMap.put("int", "I");
+ type2vmtypeMap.put("long", "J");
+ type2vmtypeMap.put("float", "F");
+ type2vmtypeMap.put("double", "D");
}
+ static String[] bytecodes = new String[] {
+ "nop",
+ "aconst_null",
+ "iconst_m1",
+ "iconst_0",
+ "iconst_1",
+ "iconst_2",
+ "iconst_3",
+ "iconst_4",
+ "iconst_5",
+ "lconst_0",
+ "lconst_1",
+ "fconst_0",
+ "fconst_1",
+ "fconst_2",
+ "dconst_0",
+ "dconst_1",
+ "bipush",
+ "sipush",
+ "ldc",
+ "ldc_w",
+ "ldc2_w",
+ "iload",
+ "lload",
+ "fload",
+ "dload",
+ "aload",
+ "iload_0",
+ "iload_1",
+ "iload_2",
+ "iload_3",
+ "lload_0",
+ "lload_1",
+ "lload_2",
+ "lload_3",
+ "fload_0",
+ "fload_1",
+ "fload_2",
+ "fload_3",
+ "dload_0",
+ "dload_1",
+ "dload_2",
+ "dload_3",
+ "aload_0",
+ "aload_1",
+ "aload_2",
+ "aload_3",
+ "iaload",
+ "laload",
+ "faload",
+ "daload",
+ "aaload",
+ "baload",
+ "caload",
+ "saload",
+ "istore",
+ "lstore",
+ "fstore",
+ "dstore",
+ "astore",
+ "istore_0",
+ "istore_1",
+ "istore_2",
+ "istore_3",
+ "lstore_0",
+ "lstore_1",
+ "lstore_2",
+ "lstore_3",
+ "fstore_0",
+ "fstore_1",
+ "fstore_2",
+ "fstore_3",
+ "dstore_0",
+ "dstore_1",
+ "dstore_2",
+ "dstore_3",
+ "astore_0",
+ "astore_1",
+ "astore_2",
+ "astore_3",
+ "iastore",
+ "lastore",
+ "fastore",
+ "dastore",
+ "aastore",
+ "bastore",
+ "castore",
+ "sastore",
+ "pop",
+ "pop2",
+ "dup",
+ "dup_x1",
+ "dup_x2",
+ "dup2",
+ "dup2_x1",
+ "dup2_x2",
+ "swap",
+ "iadd",
+ "ladd",
+ "fadd",
+ "dadd",
+ "isub",
+ "lsub",
+ "fsub",
+ "dsub",
+ "imul",
+ "lmul",
+ "fmul",
+ "dmul",
+ "idiv",
+ "ldiv",
+ "fdiv",
+ "ddiv",
+ "irem",
+ "lrem",
+ "frem",
+ "drem",
+ "ineg",
+ "lneg",
+ "fneg",
+ "dneg",
+ "ishl",
+ "lshl",
+ "ishr",
+ "lshr",
+ "iushr",
+ "lushr",
+ "iand",
+ "land",
+ "ior",
+ "lor",
+ "ixor",
+ "lxor",
+ "iinc",
+ "i2l",
+ "i2f",
+ "i2d",
+ "l2i",
+ "l2f",
+ "l2d",
+ "f2i",
+ "f2l",
+ "f2d",
+ "d2i",
+ "d2l",
+ "d2f",
+ "i2b",
+ "i2c",
+ "i2s",
+ "lcmp",
+ "fcmpl",
+ "fcmpg",
+ "dcmpl",
+ "dcmpg",
+ "ifeq",
+ "ifne",
+ "iflt",
+ "ifge",
+ "ifgt",
+ "ifle",
+ "if_icmpeq",
+ "if_icmpne",
+ "if_icmplt",
+ "if_icmpge",
+ "if_icmpgt",
+ "if_icmple",
+ "if_acmpeq",
+ "if_acmpne",
+ "goto",
+ "jsr",
+ "ret",
+ "tableswitch",
+ "lookupswitch",
+ "ireturn",
+ "lreturn",
+ "freturn",
+ "dreturn",
+ "areturn",
+ "return",
+ "getstatic",
+ "putstatic",
+ "getfield",
+ "putfield",
+ "invokevirtual",
+ "invokespecial",
+ "invokestatic",
+ "invokeinterface",
+ "invokedynamic",
+ "new",
+ "newarray",
+ "anewarray",
+ "arraylength",
+ "athrow",
+ "checkcast",
+ "instanceof",
+ "monitorenter",
+ "monitorexit",
+ "wide",
+ "multianewarray",
+ "ifnull",
+ "ifnonnull",
+ "goto_w",
+ "jsr_w",
+ "breakpoint"
+ };
+
+ /**
+ * Sort log events by start time.
+ */
static Comparator<LogEvent> sortByStart = new Comparator<LogEvent>() {
public int compare(LogEvent a, LogEvent b) {
@@ -80,25 +319,29 @@
return 7;
}
};
+
+ /**
+ * Sort log events first by the name of the compiled method, then by start
+ * time. In case one of the events has no associated compilation (or the
+ * associated compilation has no method name), the event with a compilation
+ * and/or name is considered the larger one.
+ */
static Comparator<LogEvent> sortByNameAndStart = new Comparator<LogEvent>() {
public int compare(LogEvent a, LogEvent b) {
Compilation c1 = a.getCompilation();
Compilation c2 = b.getCompilation();
- if (c1 != null && c2 != null) {
+ if (c1 != null && c1.getMethod() != null && c2 != null && c2.getMethod() != null) {
int result = c1.getMethod().toString().compareTo(c2.getMethod().toString());
if (result != 0) {
return result;
}
- }
- double difference = (a.getStart() - b.getStart());
- if (difference < 0) {
+ } else if ((c1 == null || c1.getMethod() == null) && c2 != null && c2.getMethod() != null) {
return -1;
- }
- if (difference > 0) {
+ } else if ((c2 == null || c2.getMethod() == null) && c1 != null && c1.getMethod() != null) {
return 1;
}
- return 0;
+ return Double.compare(a.getStart(), b.getStart());
}
public boolean equals(Object other) {
@@ -110,6 +353,10 @@
return 7;
}
};
+
+ /**
+ * Sort log events by duration.
+ */
static Comparator<LogEvent> sortByElapsed = new Comparator<LogEvent>() {
public int compare(LogEvent a, LogEvent b) {
@@ -134,6 +381,10 @@
}
};
+ /**
+ * Shrink-wrapped representation of a JVMState (tailored to meet this
+ * tool's needs). It only records a method and bytecode instruction index.
+ */
class Jvms {
Jvms(Method method, int bci) {
this.method = method;
@@ -146,12 +397,33 @@
}
}
+ /**
+ * Representation of a lock elimination. Locks, corresponding to
+ * synchronized blocks and method calls, may be eliminated if the object in
+ * question is guaranteed to be used thread-locally.
+ */
class LockElimination extends BasicLogEvent {
- ArrayList<Jvms> jvms = new ArrayList<Jvms>(1);
+ /**
+ * Track all locations from which this lock was eliminated.
+ */
+ ArrayList<Jvms> jvms = new ArrayList<>(1);
+
+ /**
+ * The kind of lock (coarsened, nested, non-escaping, unknown).
+ */
final String kind;
+
+ /**
+ * The lock class (unlock, lock, unknown).
+ */
final String classId;
+
+ /**
+ * The precise type of lock.
+ */
final String tagName;
+
LockElimination(String tagName, double start, String id, String kind, String classId) {
super(start, id);
this.kind = kind;
@@ -160,8 +432,11 @@
}
@Override
- public void print(PrintStream stream) {
- stream.printf("%s %s %s %s %.3f ", getId(), tagName, kind, classId, getStart());
+ public void print(PrintStream stream, boolean printID) {
+ if (printID) {
+ stream.printf("%s ", getId());
+ }
+ stream.printf("%s %s %s %.3f ", tagName, kind, classId, getStart());
stream.print(jvms.toString());
stream.print("\n");
}
@@ -172,25 +447,154 @@
}
- private ArrayList<LogEvent> events = new ArrayList<LogEvent>();
+ /**
+ * A list of log events. This is populated with the events found in the
+ * compilation log file during parsing.
+ */
+ private ArrayList<LogEvent> events = new ArrayList<>();
+
+ /**
+ * Map compilation log IDs to type names.
+ */
+ private HashMap<String, String> types = new HashMap<>();
- private HashMap<String, String> types = new HashMap<String, String>();
- private HashMap<String, Method> methods = new HashMap<String, Method>();
- private LinkedHashMap<String, NMethod> nmethods = new LinkedHashMap<String, NMethod>();
- private HashMap<String, Compilation> compiles = new HashMap<String, Compilation>();
+ /**
+ * Map compilation log IDs to methods.
+ */
+ private HashMap<String, Method> methods = new HashMap<>();
+
+ /**
+ * Map compilation IDs ({@see #makeId()}) to newly created nmethods.
+ */
+ private LinkedHashMap<String, NMethod> nmethods = new LinkedHashMap<>();
+
+ /**
+ * Map compilation task IDs {@see #makeId()}) to {@link Compilation}
+ * objects.
+ */
+ private HashMap<String, Compilation> compiles = new HashMap<>();
+
+ /**
+ * Track compilation failure reasons.
+ */
private String failureReason;
- private int bci;
- private Stack<CallSite> scopes = new Stack<CallSite>();
+
+ /**
+ * The current bytecode instruction index.
+ */
+ private int current_bci;
+
+ /**
+ * The current bytecode instruction.
+ */
+ private int current_bytecode;
+
+ /**
+ * A sequence of {@link CallSite}s representing a call stack. A scope
+ * typically holds several {@link CallSite}s that represent calls
+ * originating from that scope.
+ *
+ * New scopes are typically pushed when parse log events are encountered
+ * ({@see #startElement()}) and popped when parsing of a given Java method
+ * is done ({@see #endElement()}). Parsing events can be nested. Several
+ * other events add information to scopes ({@see #startElement()}).
+ */
+ private Deque<CallSite> scopes = new ArrayDeque<>();
+
+ /**
+ * The current compilation.
+ */
private Compilation compile;
+
+ /**
+ * The {@linkplain CallSite compilation scope} currently in focus.
+ */
private CallSite site;
+
+ /**
+ * The {@linkplain CallSite method handle call site} currently under
+ * observation.
+ */
private CallSite methodHandleSite;
- private Stack<Phase> phaseStack = new Stack<Phase>();
+
+ /**
+ * Keep track of potentially nested compiler {@linkplain Phase phases}.
+ */
+ private Deque<Phase> phaseStack = new ArrayDeque<>();
+
+ /**
+ * The {@linkplain LockElimination lock elimination event} currently being
+ * processed.
+ */
private LockElimination currentLockElimination;
+
+ /**
+ * The {@linkplain UncommonTrapEvent uncommon trap event} currently being
+ * processed.
+ */
private UncommonTrapEvent currentTrap;
- private Stack<CallSite> lateInlineScope;
+
+ /**
+ * During the processing of a late inline event, this stack holds the
+ * {@link CallSite}s that represent the inlining event's call stack.
+ */
+ private Deque<CallSite> lateInlineScope;
+
+ /**
+ * Denote whether a late inlining event is currently being processed.
+ */
private boolean lateInlining;
+ /**
+ * A document locator to provide better error messages: this allows the
+ * tool to display in which line of the log file the problem occurred.
+ */
+ private Locator locator;
+ /**
+ * Callback for the SAX framework to set the document locator.
+ */
+ @Override
+ public void setDocumentLocator(Locator locator) {
+ this.locator = locator;
+ }
+
+ /**
+ * Report an internal error explicitly raised, i.e., not derived from an
+ * exception.
+ *
+ * @param msg The error message to report.
+ */
+ private void reportInternalError(String msg) {
+ reportInternalError(msg, null);
+ }
+
+ /**
+ * Report an internal error derived from an exception.
+ *
+ * @param msg The beginning of the error message to report. The message
+ * from the exception will be appended to this.
+ * @param e The exception that led to the internal error.
+ */
+ private void reportInternalError(String msg, Exception e) {
+ if (locator != null) {
+ msg += " at " + locator.getLineNumber() + ":" + locator.getColumnNumber();
+ if (e != null) {
+ msg += " - " + e.getMessage();
+ }
+ }
+ if (e != null) {
+ throw new Error(msg, e);
+ } else {
+ throw new Error(msg);
+ }
+ }
+
+ /**
+ * Parse a long hexadecimal address into a {@code long} value. As Java only
+ * supports positive {@code long} values, extra error handling and parsing
+ * logic is provided.
+ */
long parseLong(String l) {
try {
return Long.decode(l).longValue();
@@ -207,16 +611,29 @@
System.out.println(v1);
System.out.println(v2);
System.out.println(Long.toHexString(v1 + v2));
- throw new InternalError("bad conversion");
+ reportInternalError("bad conversion");
}
return v1 + v2;
}
}
+ /**
+ * Entry point for log file parsing with a file name.
+ *
+ * @param file The name of the log file to parse.
+ * @param cleanup Whether to perform bad XML cleanup during parsing (this
+ * is relevant for some log files generated by the 1.5 JVM).
+ * @return a list of {@link LogEvent} instances describing the events found
+ * in the log file.
+ */
public static ArrayList<LogEvent> parse(String file, boolean cleanup) throws Exception {
return parse(new FileReader(file), cleanup);
}
+ /**
+ * Entry point for log file parsing with a file reader.
+ * {@see #parse(String,boolean)}
+ */
public static ArrayList<LogEvent> parse(Reader reader, boolean cleanup) throws Exception {
// Create the XML input factory
SAXParserFactory factory = SAXParserFactory.newInstance();
@@ -238,31 +655,58 @@
// Carry on with what we've got...
}
- // Associate compilations with their NMethods
- for (NMethod nm : log.nmethods.values()) {
- Compilation c = log.compiles.get(nm.getId());
- nm.setCompilation(c);
- // Native wrappers for methods don't have a compilation
- if (c != null) {
- c.setNMethod(nm);
+ // Associate compilations with their NMethods and other kinds of events
+ for (LogEvent e : log.events) {
+ if (e instanceof BasicLogEvent) {
+ BasicLogEvent ble = (BasicLogEvent) e;
+ Compilation c = log.compiles.get(ble.getId());
+ if (c == null) {
+ if (!(ble instanceof NMethod)) {
+ throw new InternalError("only nmethods should have a null compilation, here's a " + ble.getClass());
+ }
+ continue;
+ }
+ ble.setCompilation(c);
+ if (ble instanceof NMethod) {
+ c.setNMethod((NMethod) ble);
+ }
}
}
- // Initially we want the LogEvent log sorted by timestamp
- Collections.sort(log.events, sortByStart);
-
return log.events;
}
+ /**
+ * Retrieve a given attribute's value from a collection of XML tag
+ * attributes. Report an error if the requested attribute is not found.
+ *
+ * @param attr A collection of XML tag attributes.
+ * @param name The name of the attribute the value of which is to be found.
+ * @return The value of the requested attribute, or {@code null} if it was
+ * not found.
+ */
String search(Attributes attr, String name) {
String result = attr.getValue(name);
if (result != null) {
return result;
} else {
- throw new InternalError("can't find " + name);
+ reportInternalError("can't find " + name);
+ return null;
}
}
+ /**
+ * Retrieve a given attribute's value from a collection of XML tag
+ * attributes. Return a default value if the requested attribute is not
+ * found.
+ *
+ * @param attr A collection of XML tag attributes.
+ * @param name The name of the attribute the value of which is to be found.
+ * @param defaultValue The default value to return if the attribute is not
+ * found.
+ * @return The value of the requested attribute, or the default value if it
+ * was not found.
+ */
String search(Attributes attr, String name, String defaultValue) {
String result = attr.getValue(name);
if (result != null) {
@@ -270,33 +714,70 @@
}
return defaultValue;
}
- int indent = 0;
+ /**
+ * Map a type ID from the compilation log to an actual type name. In case
+ * the type represents an internal array type descriptor, return a
+ * Java-level name. If the type ID cannot be mapped to a name, raise an
+ * error.
+ */
String type(String id) {
String result = types.get(id);
if (result == null) {
- throw new InternalError(id);
+ reportInternalError(id);
}
- String remapped = typeMap.get(result);
+ String remapped = type2printableMap.get(result);
if (remapped != null) {
return remapped;
}
return result;
}
+ /**
+ * Register a mapping from log file type ID to type name.
+ */
void type(String id, String name) {
assert type(id) == null;
types.put(id, name);
}
+ /**
+ * Map a log file type ID to an internal type declarator.
+ */
+ String sigtype(String id) {
+ String result = types.get(id);
+ String remapped = type2vmtypeMap.get(result);
+ if (remapped != null) {
+ return remapped;
+ }
+ if (result == null) {
+ reportInternalError(id);
+ }
+ if (result.charAt(0) == '[') {
+ return result;
+ }
+ return "L" + result + ";";
+ }
+
+ /**
+ * Retrieve a method based on the log file ID it was registered under.
+ * Raise an error if the ID does not map to a method.
+ */
Method method(String id) {
Method result = methods.get(id);
if (result == null) {
- throw new InternalError(id);
+ reportInternalError(id);
}
return result;
}
+ /**
+ * From a compilation ID and kind, assemble a compilation ID for inclusion
+ * in the output.
+ *
+ * @param atts A collection of XML attributes from which the required
+ * attributes are retrieved.
+ */
public String makeId(Attributes atts) {
String id = atts.getValue("compile_id");
String kind = atts.getValue("kind");
@@ -306,11 +787,60 @@
return id;
}
+ /**
+ * Process the start of a compilation log XML element.<ul>
+ * <li><b>phase:</b> record the beginning of a compilation phase, pushing
+ * it on the {@linkplain #phaseStack phase stack} and collecting
+ * information about the compiler graph.</li>
+ * <li><b>phase_done:</b> record the end of a compilation phase, popping it
+ * off the {@linkplain #phaseStack phase stack} and collecting information
+ * about the compiler graph (number of nodes and live nodes).</li>
+ * <li><b>task:</b> register the start of a new compilation.</li>
+ * <li><b>type:</b> register a type.</li>
+ * <li><b>bc:</b> note the current bytecode index and instruction name,
+ * updating {@link #current_bci} and {@link #current_bytecode}.</li>
+ * <li><b>klass:</b> register a type (class).</li>
+ * <li><b>method:</b> register a Java method.</li>
+ * <li><b>call:</b> process a call, populating {@link #site} with the
+ * appropriate data.</li>
+ * <li><b>regalloc:</b> record the register allocator's trip count in the
+ * {@linkplain #compile current compilation}.</li>
+ * <li><b>inline_fail:</b> record the reason for a failed inline
+ * operation.</li>
+ * <li><b>inline_success:</b> record a successful inlining operation,
+ * noting the success reason in the {@linkplain #site call site}.</li>
+ * <li><b>failure:</b> note a compilation failure, storing the reason
+ * description in {@link #failureReason}.</li>
+ * <li><b>task_done:</b> register the end of a compilation, recording time
+ * stamp and success information.</li>
+ * <li><b>make_not_entrant:</b> deal with making a native method
+ * non-callable (e.g., during an OSR compilation, if there are still
+ * activations) or a zombie (when the method can be deleted).</li>
+ * <li><b>uncommon_trap:</b> process an uncommon trap, setting the
+ * {@link #currentTrap} field.</li>
+ * <li><b>eliminate_lock:</b> record the start of a lock elimination,
+ * setting the {@link #currentLockElimination} event.</li>
+ * <li><b>late_inline:</b> start processing a late inline decision:
+ * initialize the {@linkplain #lateInlineScope inline scope stack}, create
+ * an {@linkplain #site initial scope} with a bogus bytecode index and the
+ * right inline ID, and push the scope with the inline ID attached. Note
+ * that most of late inlining processing happens in
+ * {@link #endElement()}.</li>
+ * <li><b>jvms:</b> record a {@linkplain Jvms JVMState}. Depending on the
+ * context in which this event is encountered, this can mean adding
+ * information to the currently being processed trap, lock elimination, or
+ * inlining operation.</li>
+ * <li><b>inline_id:</b> set the inline ID in the
+ * {@linkplain #site current call site}.</li>
+ * <li><b>nmethod:</b> record the creation of a new {@link NMethod} and
+ * store it in the {@link #nmethods} map.</li>
+ * <li><b>parse:</b> begin parsing a Java method's bytecode and
+ * transforming it into an initial compiler IR graph.</li>
+ * <li><b>parse_done:</b> finish parsing a Java method's bytecode.</li>
+ * </ul>
+ */
@Override
- public void startElement(String uri,
- String localName,
- String qname,
- Attributes atts) {
+ public void startElement(String uri, String localName, String qname, Attributes atts) {
if (qname.equals("phase")) {
Phase p = new Phase(search(atts, "name"),
Double.parseDouble(search(atts, "stamp")),
@@ -322,45 +852,62 @@
String phaseName = search(atts, "name", null);
if (phaseName != null && !p.getId().equals(phaseName)) {
System.out.println("phase: " + p.getId());
- throw new InternalError("phase name mismatch");
+ reportInternalError("phase name mismatch");
}
p.setEnd(Double.parseDouble(search(atts, "stamp")));
p.setEndNodes(Integer.parseInt(search(atts, "nodes", "0")));
p.setEndLiveNodes(Integer.parseInt(search(atts, "live", "0")));
compile.getPhases().add(p);
} else if (qname.equals("task")) {
+ String id = makeId(atts);
+
+ // Create the new Compilation instance and populate it with readily
+ // available data.
compile = new Compilation(Integer.parseInt(search(atts, "compile_id", "-1")));
compile.setStart(Double.parseDouble(search(atts, "stamp")));
compile.setICount(search(atts, "count", "0"));
compile.setBCount(search(atts, "backedge_count", "0"));
-
- String method = atts.getValue("method");
- int space = method.indexOf(' ');
- method = method.substring(0, space) + "::" +
- method.substring(space + 1, method.indexOf(' ', space + 1) + 1);
+ compile.setBCI(Integer.parseInt(search(atts, "osr_bci", "-1")));
String compiler = atts.getValue("compiler");
if (compiler == null) {
compiler = "";
}
+ compile.setCompiler(compiler);
+
+ // Extract the name of the compiled method.
+ String[] parts = spacePattern.split(atts.getValue("method"));
+ String methodName = parts[0] + "::" + parts[1];
+
+ // Continue collecting compilation meta-data.
String kind = atts.getValue("compile_kind");
if (kind == null) {
kind = "normal";
}
if (kind.equals("osr")) {
compile.setOsr(true);
- compile.setOsr_bci(Integer.parseInt(search(atts, "osr_bci")));
} else if (kind.equals("c2i")) {
- compile.setSpecial("--- adapter " + method);
+ compile.setSpecial("--- adapter " + methodName);
} else {
- compile.setSpecial(compile.getId() + " " + method + " (0 bytes)");
+ compile.setSpecial(compile.getId() + " " + methodName + " (0 bytes)");
}
+
+ // Build a dummy method to stuff in the Compilation at the
+ // beginning.
+ Method m = new Method();
+ m.setHolder(parts[0]);
+ m.setName(parts[1]);
+ m.setSignature(parts[2]);
+ m.setFlags("0");
+ m.setBytes("unknown");
+ compile.setMethod(m);
events.add(compile);
- compiles.put(makeId(atts), compile);
+ compiles.put(id, compile);
site = compile.getCall();
} else if (qname.equals("type")) {
type(search(atts, "id"), search(atts, "name"));
} else if (qname.equals("bc")) {
- bci = Integer.parseInt(search(atts, "bci"));
+ current_bci = Integer.parseInt(search(atts, "bci"));
+ current_bytecode = Integer.parseInt(search(atts, "code"));
} else if (qname.equals("klass")) {
type(search(atts, "id"), search(atts, "name"));
} else if (qname.equals("method")) {
@@ -369,7 +916,19 @@
m.setHolder(type(search(atts, "holder")));
m.setName(search(atts, "name"));
m.setReturnType(type(search(atts, "return")));
- m.setArguments(search(atts, "arguments", "void"));
+ String arguments = atts.getValue("arguments");;
+ if (arguments == null) {
+ m.setSignature("()" + sigtype(atts.getValue("return")));
+ } else {
+ String[] args = spacePattern.split(arguments);
+ StringBuilder sb = new StringBuilder("(");
+ for (int i = 0; i < args.length; i++) {
+ sb.append(sigtype(args[i]));
+ }
+ sb.append(")");
+ sb.append(sigtype(atts.getValue("return")));
+ m.setSignature(sb.toString());
+ }
if (search(atts, "unloaded", "0").equals("0")) {
m.setBytes(search(atts, "bytes"));
@@ -385,15 +944,17 @@
if (lateInlining && scopes.size() == 0) {
// re-attempting already seen call site (late inlining for MH invokes)
if (m != site.getMethod()) {
- if (bci != site.getBci()) {
- System.out.println(m + " bci: " + bci);
- System.out.println(site.getMethod() + " bci: " + site.getBci());
- throw new InternalError("bci mismatch after late inlining");
+ if (current_bci != site.getBci()) {
+ System.err.println(m + " bci: " + current_bci);
+ System.err.println(site.getMethod() + " bci: " + site.getBci());
+ reportInternalError("bci mismatch after late inlining");
}
site.setMethod(m);
}
} else {
- site = new CallSite(bci, m);
+ // We're dealing with a new call site; the called method is
+ // likely to be parsed next.
+ site = new CallSite(current_bci, m);
}
site.setCount(Integer.parseInt(search(atts, "count", "0")));
String receiver = atts.getValue("receiver");
@@ -403,7 +964,8 @@
}
int methodHandle = Integer.parseInt(search(atts, "method_handle_intrinsic", "0"));
if (lateInlining && scopes.size() == 0) {
- // The call was added before this round of late inlining
+ // The call was already added before this round of late
+ // inlining. Ignore.
} else if (methodHandle == 0) {
scopes.peek().add(site);
} else {
@@ -421,18 +983,16 @@
methodHandleSite = null;
}
if (lateInlining && scopes.size() == 0) {
- site.setReason(search(atts, "reason"));
+ site.setReason("fail: " + search(atts, "reason"));
lateInlining = false;
} else {
- scopes.peek().last().setReason(search(atts, "reason"));
+ scopes.peek().last().setReason("fail: " + search(atts, "reason"));
}
} else if (qname.equals("inline_success")) {
if (methodHandleSite != null) {
- throw new InternalError("method handle site should have been replaced");
+ reportInternalError("method handle site should have been replaced");
}
- if (lateInlining && scopes.size() == 0) {
- site.setReason(null);
- }
+ site.setReason("succeed: " + search(atts, "reason"));
} else if (qname.equals("failure")) {
failureReason = search(atts, "reason");
} else if (qname.equals("task_done")) {
@@ -444,7 +1004,7 @@
} else if (qname.equals("make_not_entrant")) {
String id = makeId(atts);
NMethod nm = nmethods.get(id);
- if (nm == null) throw new InternalError();
+ if (nm == null) reportInternalError("nm == null");
LogEvent e = new MakeNotEntrantEvent(Double.parseDouble(search(atts, "stamp")), id,
atts.getValue("zombie") != null, nm);
events.add(e);
@@ -459,8 +1019,22 @@
Integer.parseInt(search(atts, "count", "0")));
events.add(currentTrap);
} else {
- // uncommon trap inserted during parsing.
- // ignore for now
+ if (atts.getValue("method") != null) {
+ // These are messages from ciTypeFlow that don't
+ // actually correspond to generated code.
+ return;
+ }
+ try {
+ if (scopes.size() == 0) {
+ reportInternalError("scope underflow");
+ }
+ scopes.peek().add(new UncommonTrap(Integer.parseInt(search(atts, "bci")),
+ search(atts, "reason"),
+ search(atts, "action"),
+ bytecodes[current_bytecode]));
+ } catch (Error e) {
+ e.printStackTrace();
+ }
}
} else if (qname.startsWith("eliminate_lock")) {
String id = atts.getValue("compile_id");
@@ -474,24 +1048,27 @@
} else if (qname.equals("late_inline")) {
long inlineId = 0;
try {
- Long.parseLong(search(atts, "inline_id"));
+ inlineId = Long.parseLong(search(atts, "inline_id"));
} catch (InternalError ex) {
// Log files from older hotspots may lack inline_id,
// and zero is an acceptable substitute that allows processing to continue.
}
- lateInlineScope = new Stack<CallSite>();
- site = new CallSite(-999, method(search(atts, "method")));
+ lateInlineScope = new ArrayDeque<>();
+ Method m = method(search(atts, "method"));
+ site = new CallSite(-999, m);
site.setInlineId(inlineId);
lateInlineScope.push(site);
} else if (qname.equals("jvms")) {
// <jvms bci='4' method='java/io/DataInputStream readChar ()C' bytes='40' count='5815' iicount='20815'/>
if (currentTrap != null) {
- currentTrap.addJVMS(atts.getValue("method"), Integer.parseInt(atts.getValue("bci")));
+ String[] parts = spacePattern.split(atts.getValue("method"));
+ currentTrap.addMethodAndBCI(parts[0].replace('/', '.') + '.' + parts[1] + parts[2], Integer.parseInt(atts.getValue("bci")));
} else if (currentLockElimination != null) {
currentLockElimination.addJVMS(method(atts.getValue("method")), Integer.parseInt(atts.getValue("bci")));
} else if (lateInlineScope != null) {
- bci = Integer.parseInt(search(atts, "bci"));
- site = new CallSite(bci, method(search(atts, "method")));
+ current_bci = Integer.parseInt(search(atts, "bci"));
+ Method m = method(search(atts, "method"));
+ site = new CallSite(current_bci, m);
lateInlineScope.push(site);
} else {
// Ignore <eliminate_allocation type='667'>,
@@ -499,7 +1076,7 @@
}
} else if (qname.equals("inline_id")) {
if (methodHandleSite != null) {
- throw new InternalError("method handle site should have been replaced");
+ reportInternalError("method handle site should have been replaced");
}
long id = Long.parseLong(search(atts, "id"));
site.setInlineId(id);
@@ -513,33 +1090,53 @@
events.add(nm);
} else if (qname.equals("parse")) {
if (failureReason != null && scopes.size() == 0 && !lateInlining) {
+ // A compilation just failed, and we're back at a top
+ // compilation scope.
failureReason = null;
compile.reset();
site = compile.getCall();
}
+ // Error checking.
if (methodHandleSite != null) {
- throw new InternalError("method handle site should have been replaced");
+ reportInternalError("method handle site should have been replaced");
}
- Method m = method(search(atts, "method"));
+ Method m = method(search(atts, "method")); // this is the method being parsed
if (lateInlining && scopes.size() == 0) {
if (site.getMethod() != m) {
- System.out.println(site.getMethod());
- System.out.println(m);
- throw new InternalError("Unexpected method mismatch during late inlining");
+ reportInternalError("Unexpected method mismatch during late inlining (method at call site: " +
+ site.getMethod() + ", method being parsed: " + m + ")");
}
}
+
if (scopes.size() == 0 && !lateInlining) {
+ // The method being parsed is actually the method being
+ // compiled; i.e., we're dealing with a compilation top scope,
+ // which we must consequently push to the scopes stack.
compile.setMethod(m);
scopes.push(site);
} else {
+ // The method being parsed is *not* the current compilation's
+ // top scope; i.e., we're dealing with an actual call site
+ // in the top scope or somewhere further down a call stack.
if (site.getMethod() == m) {
+ // We're dealing with monomorphic inlining that didn't have
+ // to be narrowed down, because the receiver was known
+ // beforehand.
scopes.push(site);
- } else if (scopes.peek().getCalls().size() > 2 && m == scopes.peek().last(-2).getMethod()) {
- scopes.push(scopes.peek().last(-2));
+ } else if (scopes.peek().getCalls().size() > 2 && m == scopes.peek().lastButOne().getMethod()) {
+ // We're dealing with an at least bimorphic call site, and
+ // the compiler has now decided to parse the last-but-one
+ // method. The last one may already have been parsed for
+ // inlining.
+ scopes.push(scopes.peek().lastButOne());
} else {
- // C1 prints multiple method tags during inlining when it narrows method being inlinied.
- // Example:
+ // The method has been narrowed down to the one we're now
+ // going to parse, which is inlined here. It's monomorphic
+ // inlining, but was not immediately clear as such.
+ //
+ // C1 prints multiple method tags during inlining when it
+ // narrows the method being inlined. Example:
// ...
// <method id="813" holder="694" name="toString" return="695" flags="1" bytes="36" iicount="1"/>
// <call method="813" instr="invokevirtual"/>
@@ -552,100 +1149,132 @@
}
}
} else if (qname.equals("parse_done")) {
- CallSite call = scopes.pop();
+ // Attach collected information about IR nodes to the current
+ // parsing scope before it's popped off the stack in endElement()
+ // (see where the parse tag is handled).
+ CallSite call = scopes.peek();
call.setEndNodes(Integer.parseInt(search(atts, "nodes", "0")));
call.setEndLiveNodes(Integer.parseInt(search(atts, "live", "0")));
call.setTimeStamp(Double.parseDouble(search(atts, "stamp")));
- scopes.push(call);
}
}
+ /**
+ * Process the end of a compilation log XML element.<ul>
+ * <li><b>parse:</b> finish transforming a Java method's bytecode
+ * instructions to an initial compiler IR graph.</li>
+ * <li><b>uncommon_trap:</b> record the end of processing an uncommon trap,
+ * resetting {@link #currentTrap}.</li>
+ * <li><b>eliminate_lock:</b> record the end of a lock elimination,
+ * resetting {@link #currentLockElimination}.</li>
+ * <li><b>late_inline:</b> the closing tag for late_inline does not denote
+ * the end of a late inlining operation, but the end of the descriptive log
+ * data given at its beginning. That is, we're now in the position to
+ * assemble details about the inlining chain (bytecode instruction index in
+ * caller, called method). The {@link #lateInlining} flag is set to
+ * {@code true} here. (It will be reset when parsing the inlined methods is
+ * done; this happens for the successful case in this method as well, when
+ * {@code parse} elements are processed; and for inlining failures, in
+ * {@link #startElement()}, when {@code inline_fail} elements are
+ * processed.)</li>
+ * <li><b>task:</b> perform cleanup at the end of a compilation. Note that
+ * the explicit {@code task_done} event is handled in
+ * {@link #startElement()}.</li>
+ * </ul>
+ */
@Override
- public void endElement(String uri,
- String localName,
- String qname) {
- if (qname.equals("parse")) {
- indent -= 2;
- scopes.pop();
- if (scopes.size() == 0) {
- lateInlining = false;
- }
- } else if (qname.equals("uncommon_trap")) {
- currentTrap = null;
- } else if (qname.startsWith("eliminate_lock")) {
- currentLockElimination = null;
- } else if (qname.equals("late_inline")) {
- // Populate late inlining info.
- if (scopes.size() != 0) {
- throw new InternalError("scopes should be empty for late inline");
- }
- // late inline scopes are specified in reverse order:
- // compiled method should be on top of stack.
- CallSite caller = lateInlineScope.pop();
- Method m = compile.getMethod();
- if (m != caller.getMethod()) {
- System.err.println(m);
- System.err.println(caller.getMethod() + " bci: " + bci);
- throw new InternalError("call site and late_inline info don't match");
- }
+ public void endElement(String uri, String localName, String qname) {
+ try {
+ if (qname.equals("parse")) {
+ // Finish dealing with the current call scope. If no more are
+ // left, no late inlining can be going on.
+ scopes.pop();
+ if (scopes.size() == 0) {
+ lateInlining = false;
+ }
+ } else if (qname.equals("uncommon_trap")) {
+ currentTrap = null;
+ } else if (qname.startsWith("eliminate_lock")) {
+ currentLockElimination = null;
+ } else if (qname.equals("late_inline")) {
+ // Populate late inlining info.
+ if (scopes.size() != 0) {
+ reportInternalError("scopes should be empty for late inline");
+ }
+ // late inline scopes are specified in reverse order:
+ // compiled method should be on top of stack.
+ CallSite caller = lateInlineScope.pop();
+ Method m = compile.getMethod();
+ if (!m.equals(caller.getMethod())) {
+ reportInternalError(String.format("call site and late_inline info don't match:\n method %s\n caller method %s, bci %d", m, caller.getMethod(), current_bci));
+ }
- // late_inline contains caller+bci info, convert it
- // to bci+callee info used by LogCompilation.
- CallSite lateInlineSite = compile.getLateInlineCall();
- ArrayDeque<CallSite> thisCallScopes = new ArrayDeque<CallSite>();
- do {
- bci = caller.getBci();
- // Next inlined call.
- caller = lateInlineScope.pop();
- CallSite callee = new CallSite(bci, caller.getMethod());
- callee.setInlineId(caller.getInlineId());
- thisCallScopes.addLast(callee);
- lateInlineSite.add(callee);
- lateInlineSite = callee;
- } while (!lateInlineScope.empty());
+ // Walk down the inlining chain and assemble bci+callee info.
+ // This needs to be converted from caller+bci info contained in
+ // the late_inline data.
+ CallSite lateInlineSite = compile.getLateInlineCall();
+ ArrayDeque<CallSite> thisCallScopes = new ArrayDeque<>();
+ do {
+ current_bci = caller.getBci();
+ // Next inlined call.
+ caller = lateInlineScope.pop();
+ CallSite callee = new CallSite(current_bci, caller.getMethod());
+ callee.setInlineId(caller.getInlineId());
+ thisCallScopes.addLast(callee);
+ lateInlineSite.add(callee);
+ lateInlineSite = callee;
+ } while (!lateInlineScope.isEmpty());
- site = compile.getCall().findCallSite(thisCallScopes);
- if (site == null) {
- System.out.println("call scopes:");
- for (CallSite c : thisCallScopes) {
- System.out.println(c.getMethod() + " " + c.getBci() + " " + c.getInlineId());
+ site = compile.getCall().findCallSite(thisCallScopes);
+ if (site == null) {
+ // Call site could not be found - report the problem in detail.
+ System.err.println("call scopes:");
+ for (CallSite c : thisCallScopes) {
+ System.err.println(c.getMethod() + " " + c.getBci() + " " + c.getInlineId());
+ }
+ CallSite c = thisCallScopes.getLast();
+ if (c.getInlineId() != 0) {
+ System.err.println("Looking for call site in entire tree:");
+ ArrayDeque<CallSite> stack = compile.getCall().findCallSite2(c);
+ for (CallSite c2 : stack) {
+ System.err.println(c2.getMethod() + " " + c2.getBci() + " " + c2.getInlineId());
+ }
+ }
+ System.err.println(caller.getMethod() + " bci: " + current_bci);
+ reportInternalError("couldn't find call site");
}
- CallSite c = thisCallScopes.getLast();
- if (c.getInlineId() != 0) {
- System.out.println("Looking for call site in entire tree:");
- ArrayDeque<CallSite> stack = compile.getCall().findCallSite2(c);
- for (CallSite c2 : stack) {
- System.out.println(c2.getMethod() + " " + c2.getBci() + " " + c2.getInlineId());
+ lateInlining = true;
+
+ if (caller.getBci() != -999) {
+ System.out.println(caller.getMethod());
+ reportInternalError("broken late_inline info");
+ }
+ if (site.getMethod() != caller.getMethod()) {
+ if (site.getInlineId() == caller.getInlineId()) {
+ site.setMethod(caller.getMethod());
+ } else {
+ System.out.println(site.getMethod());
+ System.out.println(caller.getMethod());
+ reportInternalError("call site and late_inline info don't match");
}
}
- System.out.println(caller.getMethod() + " bci: " + bci);
- throw new InternalError("couldn't find call site");
- }
- lateInlining = true;
-
- if (caller.getBci() != -999) {
- System.out.println(caller.getMethod());
- throw new InternalError("broken late_inline info");
+ // late_inline is followed by parse with scopes.size() == 0,
+ // 'site' will be pushed to scopes.
+ lateInlineScope = null;
+ } else if (qname.equals("task")) {
+ types.clear();
+ methods.clear();
+ site = null;
}
- if (site.getMethod() != caller.getMethod()) {
- if (site.getInlineId() == caller.getInlineId()) {
- site.setMethod(caller.getMethod());
- } else {
- System.out.println(site.getMethod());
- System.out.println(caller.getMethod());
- throw new InternalError("call site and late_inline info don't match");
- }
- }
- // late_inline is followed by parse with scopes.size() == 0,
- // 'site' will be pushed to scopes.
- lateInlineScope = null;
- } else if (qname.equals("task")) {
- types.clear();
- methods.clear();
- site = null;
+ } catch (Exception e) {
+ reportInternalError("exception while processing end element", e);
}
}
+ //
+ // Handlers for problems that occur in XML parsing itself.
+ //
+
@Override
public void warning(org.xml.sax.SAXParseException e) {
System.err.println(e.getMessage() + " at line " + e.getLineNumber() + ", column " + e.getColumnNumber());
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/MakeNotEntrantEvent.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/MakeNotEntrantEvent.java Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
return nmethod;
}
- public void print(PrintStream stream) {
+ public void print(PrintStream stream, boolean printID) {
if (isZombie()) {
stream.printf("%s make_zombie\n", getId());
} else {
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Method.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Method.java Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
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 @@
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 @@
return getHolder() + "::" + getName() + " (" + getBytes() + " bytes)";
}
+ public String getFullName() {
+ return getHolder().replace('/', '.') + "." + getName() + signature;
+ }
+
public String getHolder() {
return holder;
}
@@ -86,12 +138,16 @@
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 @@
@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();
+ }
}
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/NMethod.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/NMethod.java Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
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 @@
size = sz;
}
- public void print(PrintStream out) {
+ public void print(PrintStream out, boolean printID) {
// XXX Currently we do nothing
// throw new InternalError();
}
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Phase.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Phase.java Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
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 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 @@
}
@Override
- public void print(PrintStream stream) {
+ public void print(PrintStream stream, boolean printID) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrap.java Thu Jul 23 15:28:52 2015 -0700
@@ -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();
+ }
+}
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrapEvent.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrapEvent.java Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
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 @@
this.count = count;
}
- public String getJvms() {
- return 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) {
+ 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 setJvms(String jvms) {
- this.jvms = jvms;
+ public void addMethodAndBCI(String method, int bci) {
+ jvmsMethods.add(0, method);
+ jvmsBCIs.add(0, bci);
}
- public void setCompilation(Compilation compilation) {
- this.compilation = compilation;
- }
}
--- a/hotspot/src/share/vm/ci/ciMethod.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/ci/ciMethod.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -75,6 +75,9 @@
{
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());
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -2698,8 +2698,7 @@
// 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 @@
// 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;
}
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -58,14 +58,14 @@
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;
}
--- a/hotspot/src/share/vm/classfile/verifier.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/classfile/verifier.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -2846,7 +2846,7 @@
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");
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -501,8 +501,8 @@
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'
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -848,7 +848,7 @@
_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());
}
--- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -96,7 +96,7 @@
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 @@
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 @@
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 @@
&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.");
{
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -741,11 +741,9 @@
#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 {
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -436,7 +436,7 @@
// 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;
--- a/hotspot/src/share/vm/oops/markOop.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/oops/markOop.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -32,26 +32,32 @@
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("??");
}
--- a/hotspot/src/share/vm/oops/method.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/oops/method.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -422,6 +422,11 @@
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 @@
}
#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) {
--- a/hotspot/src/share/vm/oops/method.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/oops/method.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -625,6 +625,8 @@
#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 ); }
--- a/hotspot/src/share/vm/oops/symbol.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/oops/symbol.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
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");
--- a/hotspot/src/share/vm/opto/loopTransform.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/opto/loopTransform.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -280,6 +280,10 @@
|| (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 @@
_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 @@
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 @@
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 @@
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 @@
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 @@
// 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() )
--- a/hotspot/src/share/vm/opto/loopUnswitch.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/opto/loopUnswitch.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -61,6 +61,12 @@
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.
--- a/hotspot/src/share/vm/opto/loopnode.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/opto/loopnode.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -2317,7 +2317,11 @@
// 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);
--- a/hotspot/src/share/vm/opto/loopnode.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/opto/loopnode.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -64,7 +64,9 @@
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 @@
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 @@
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 @@
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; }
--- a/hotspot/src/share/vm/opto/superword.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/opto/superword.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -100,6 +100,10 @@
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 @@
}
//------------------------------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 @@
// 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 @@
}
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 @@
}
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 @@
_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 @@
}
}
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---------------------------
--- a/hotspot/src/share/vm/opto/superword.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/opto/superword.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -241,7 +241,7 @@
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; }
--- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -277,6 +277,8 @@
{ "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) }
};
--- a/hotspot/src/share/vm/runtime/globals.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -1291,7 +1291,7 @@
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 @@
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 @@
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 @@
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 @@
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") \
\
--- a/hotspot/src/share/vm/runtime/java.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/java.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -330,6 +330,10 @@
SystemDictionary::print();
}
+ if (LogTouchedMethods && PrintTouchedMethodsAtExit) {
+ Method::print_touched_methods(tty);
+ }
+
if (PrintBiasedLockingStatistics) {
BiasedLocking::print_counters();
}
@@ -382,6 +386,10 @@
if (PrintNMTStatistics) {
MemTracker::final_report(tty);
}
+
+ if (LogTouchedMethods && PrintTouchedMethodsAtExit) {
+ Method::print_touched_methods(tty);
+ }
}
#endif
--- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -63,6 +63,7 @@
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 @@
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);
--- a/hotspot/src/share/vm/runtime/mutexLocker.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -55,6 +55,7 @@
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
--- a/hotspot/src/share/vm/runtime/objectMonitor.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
// -----------------------------------------------------------------------------
// 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 @@
}
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 @@
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 @@
#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 @@
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;
--- a/hotspot/src/share/vm/runtime/objectMonitor.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/objectMonitor.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
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 @@
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 @@
#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
--- a/hotspot/src/share/vm/runtime/synchronizer.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/synchronizer.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
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 @@
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 @@
// 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 @@
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);
}
}
--- a/hotspot/src/share/vm/runtime/thread.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/thread.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -1802,14 +1802,25 @@
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.
+ //
+ // 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 this.
- if (exit_type == jni_detach && JNIDetachReleasesMonitors) {
- assert(!this->has_last_Java_frame(), "detaching with Java frames?");
+ // 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");
}
--- a/hotspot/src/share/vm/runtime/vframe.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/vframe.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -144,7 +144,7 @@
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 @@
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 @@
}
}
-
- // 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 @@
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 @@
)) {
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();
}
--- a/hotspot/src/share/vm/runtime/vframe.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/vframe.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
// 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); }
--- a/hotspot/src/share/vm/runtime/vm_operations.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/runtime/vm_operations.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -101,6 +101,7 @@
template(WhiteBoxOperation) \
template(ClassLoaderStatsOperation) \
template(DumpHashtable) \
+ template(DumpTouchedMethods) \
template(MarkActiveNMethods) \
template(PrintCompileQueue) \
template(PrintCodeList) \
--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Thu Jul 23 15:28:52 2015 -0700
@@ -74,6 +74,7 @@
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 @@
}
#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;
+}
--- a/hotspot/src/share/vm/services/diagnosticCommand.hpp Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp Thu Jul 23 15:28:52 2015 -0700
@@ -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 @@
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:
--- a/hotspot/test/compiler/codegen/7184394/TestAESBase.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/test/compiler/codegen/7184394/TestAESBase.java Thu Jul 23 15:28:52 2015 -0700
@@ -61,12 +61,12 @@
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 @@
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 @@
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);
+ algParams = cipher.getParameters();
+ dCipher.init(Cipher.DECRYPT_MODE, key, initVector);
+
+ // GCM init
} else if (mode.equals("GCM")) {
- iv = new byte[64];
- random.nextBytes(iv);
- aad = new byte[5];
- random.nextBytes(aad);
- gcm_init();
+ gcm_init(true);
+ gcm_init(false);
+
+ // ECB init
} else {
- algParams = cipher.getParameters();
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 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);
+
+
+ }
}
}
--- a/hotspot/test/compiler/codegen/7184394/TestAESDecode.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/test/compiler/codegen/7184394/TestAESDecode.java Thu Jul 23 15:28:52 2015 -0700
@@ -32,7 +32,11 @@
@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);
--- a/hotspot/test/compiler/codegen/7184394/TestAESEncode.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/test/compiler/codegen/7184394/TestAESEncode.java Thu Jul 23 15:28:52 2015 -0700
@@ -33,7 +33,7 @@
public void run() {
try {
if (mode.equals("GCM")) {
- gcm_init();
+ gcm_init(true);
} else if (!noReinit) {
cipher.init(Cipher.ENCRYPT_MODE, key, algParams);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/PrintTouchedMethods.java Thu Jul 23 15:28:52 2015 -0700
@@ -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");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/TestLogTouchedMethods.java Thu Jul 23 15:28:52 2015 -0700
@@ -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
+}
--- a/hotspot/test/runtime/ErrorHandling/CreateCoredumpOnCrash.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/test/runtime/ErrorHandling/CreateCoredumpOnCrash.java Thu Jul 23 15:28:52 2015 -0700
@@ -46,16 +46,8 @@
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");
}
--- a/hotspot/test/runtime/ErrorHandling/TestOnError.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/test/runtime/ErrorHandling/TestOnError.java Thu Jul 23 15:28:52 2015 -0700
@@ -45,6 +45,7 @@
// 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());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/BadInitMethod.java Thu Jul 23 15:28:52 2015 -0700
@@ -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");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/EnclosingMethod.java Thu Jul 23 15:28:52 2015 -0700
@@ -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");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/badEnclMthd.jcod Thu Jul 23 15:28:52 2015 -0700
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/badInit.jasm Thu Jul 23 15:28:52 2015 -0700
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/ignoredClinit.jasm Thu Jul 23 15:28:52 2015 -0700
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ *
+ */
+
+// 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.
+
+public class ignoredClinit version 51:0
+{
+
+ public static Method "<clinit>":"()I"
+ stack 1 locals 1
+ {
+ iconst_0;
+ ireturn;
+ }
+
+} // end Class ignoredClinit
--- a/hotspot/test/runtime/memory/ReserveMemory.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/test/runtime/memory/ReserveMemory.java Thu Jul 23 15:28:52 2015 -0700
@@ -60,6 +60,7 @@
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
"-XX:-TransmitErrorReport",
+ "-XX:-CreateCoredumpOnCrash",
"-Xmx32m",
"ReserveMemory",
"test");
--- a/hotspot/test/serviceability/hprof/cpu002.java Thu Jul 23 11:54:26 2015 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * 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 8076421
- * @summary Test of hprof option crashes Zero
- * @compile cpu002.java
- * @run main/othervm -Xrunhprof:cpu=times,file=cpu002.hprof.out cpu002
- */
-
-import java.io.*;
-
-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 int run(String argv[], PrintStream out) {
- return PASSED;
- }
-}
--- a/hotspot/test/serviceability/sa/TestStackTrace.java Thu Jul 23 11:54:26 2015 -0700
+++ b/hotspot/test/serviceability/sa/TestStackTrace.java Thu Jul 23 15:28:52 2015 -0700
@@ -34,6 +34,7 @@
* @test
* @library /../../test/lib/share/classes
* @library /testlibrary
+ * @ignore 8129971
* @build jdk.test.lib.*
* @build jdk.test.lib.apps.*
* @run main TestStackTrace